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 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 = 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 = 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 = 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 guchar *str = cr_string_dup2 00817 ((CRString const *) cur->data); 00818 00819 if (str) { 00820 if (cur->prev) { 00821 g_string_append 00822 (stringue, 00823 ","); 00824 } 00825 g_string_append_printf 00826 (stringue, 00827 " %s", str); 00828 g_free (str); 00829 str = 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 guchar *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 (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 (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 (a_buf), 01196 a_enc, FALSE); 01197 if (!parser) { 01198 cr_utils_trace_info ("Instanciation 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 ("Instanciation 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 (a_buf), 01382 a_encoding, FALSE); 01383 if (!parser) { 01384 cr_utils_trace_info ("Instanciation 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 GList *cur = NULL; 01415 01416 for (cur = media_list; media_list; 01417 media_list = g_list_next (media_list)) { 01418 if (media_list->data) { 01419 cr_string_destroy ((CRString*)media_list->data); 01420 media_list->data = NULL; 01421 } 01422 } 01423 g_list_free (media_list); 01424 media_list = NULL; 01425 } 01426 if (import_string) { 01427 cr_string_destroy (import_string); 01428 import_string = NULL; 01429 } 01430 01431 return result; 01432 } 01433 01434 /** 01435 * cr_statement_new_at_page_rule: 01436 * 01437 *@a_decl_list: a list of instances of #CRDeclarations 01438 *which is actually the list of declarations that applies to 01439 *this page rule. 01440 *@a_selector: the page rule selector. 01441 * 01442 *Creates a new instance of #CRStatement of type 01443 *#CRAtPageRule. 01444 * 01445 *Returns the newly built instance of #CRStatement or NULL 01446 *in case of error. 01447 */ 01448 CRStatement * 01449 cr_statement_new_at_page_rule (CRStyleSheet * a_sheet, 01450 CRDeclaration * a_decl_list, 01451 CRString * a_name, CRString * a_pseudo) 01452 { 01453 CRStatement *result = NULL; 01454 01455 result = g_try_malloc (sizeof (CRStatement)); 01456 01457 if (!result) { 01458 cr_utils_trace_info ("Out of memory"); 01459 return NULL; 01460 } 01461 01462 memset (result, 0, sizeof (CRStatement)); 01463 result->type = AT_PAGE_RULE_STMT; 01464 01465 result->kind.page_rule = g_try_malloc (sizeof (CRAtPageRule)); 01466 01467 if (!result->kind.page_rule) { 01468 cr_utils_trace_info ("Out of memory"); 01469 g_free (result); 01470 return NULL; 01471 } 01472 01473 memset (result->kind.page_rule, 0, sizeof (CRAtPageRule)); 01474 if (a_decl_list) { 01475 result->kind.page_rule->decl_list = a_decl_list; 01476 cr_declaration_ref (a_decl_list); 01477 } 01478 result->kind.page_rule->name = a_name; 01479 result->kind.page_rule->pseudo = a_pseudo; 01480 if (a_sheet) 01481 cr_statement_set_parent_sheet (result, a_sheet); 01482 01483 return result; 01484 } 01485 01486 /** 01487 * cr_statement_at_page_rule_parse_from_buf: 01488 * 01489 *@a_buf: the character buffer to parse. 01490 *@a_encoding: the character encoding of a_buf. 01491 * 01492 *Parses a buffer that contains an "\@page" production and, 01493 *if the parsing succeeds, builds the page statement. 01494 * 01495 *Returns the newly built at page statement in case of successful parsing, 01496 *NULL otherwise. 01497 */ 01498 CRStatement * 01499 cr_statement_at_page_rule_parse_from_buf (const guchar * a_buf, 01500 enum CREncoding a_encoding) 01501 { 01502 enum CRStatus status = CR_OK; 01503 CRParser *parser = NULL; 01504 CRDocHandler *sac_handler = NULL; 01505 CRStatement *result = NULL; 01506 CRStatement **resultptr = NULL; 01507 01508 g_return_val_if_fail (a_buf, NULL); 01509 01510 parser = cr_parser_new_from_buf ((guchar*)a_buf, strlen (a_buf), 01511 a_encoding, FALSE); 01512 if (!parser) { 01513 cr_utils_trace_info ("Instanciation of the parser failed."); 01514 goto cleanup; 01515 } 01516 01517 sac_handler = cr_doc_handler_new (); 01518 if (!sac_handler) { 01519 cr_utils_trace_info 01520 ("Instanciation of the sac handler failed."); 01521 goto cleanup; 01522 } 01523 01524 sac_handler->start_page = parse_page_start_page_cb; 01525 sac_handler->property = parse_page_property_cb; 01526 sac_handler->end_page = parse_page_end_page_cb; 01527 sac_handler->unrecoverable_error = parse_page_unrecoverable_error_cb; 01528 01529 status = cr_parser_set_sac_handler (parser, sac_handler); 01530 if (status != CR_OK) 01531 goto cleanup; 01532 01533 /*Now, invoke the parser to parse the "@page production" */ 01534 cr_parser_try_to_skip_spaces_and_comments (parser); 01535 if (status != CR_OK) 01536 goto cleanup; 01537 status = cr_parser_parse_page (parser); 01538 if (status != CR_OK) 01539 goto cleanup; 01540 01541 resultptr = &result; 01542 status = cr_doc_handler_get_result (sac_handler, 01543 (gpointer *) resultptr); 01544 01545 cleanup: 01546 01547 if (parser) { 01548 cr_parser_destroy (parser); 01549 parser = NULL; 01550 sac_handler = NULL ; 01551 } 01552 if (sac_handler) { 01553 cr_doc_handler_unref (sac_handler); 01554 sac_handler = NULL; 01555 } 01556 return result; 01557 } 01558 01559 /** 01560 * cr_statement_new_at_charset_rule: 01561 * 01562 *@a_charset: the string representing the charset. 01563 *Note that the newly built instance of #CRStatement becomes 01564 *the owner of a_charset. The caller must not free a_charset !!!. 01565 * 01566 *Creates a new instance of #CRStatement of type 01567 *#CRAtCharsetRule. 01568 * 01569 *Returns the newly built instance of #CRStatement or NULL 01570 *if an error arises. 01571 */ 01572 CRStatement * 01573 cr_statement_new_at_charset_rule (CRStyleSheet * a_sheet, 01574 CRString * a_charset) 01575 { 01576 CRStatement *result = NULL; 01577 01578 g_return_val_if_fail (a_charset, NULL); 01579 01580 result = g_try_malloc (sizeof (CRStatement)); 01581 01582 if (!result) { 01583 cr_utils_trace_info ("Out of memory"); 01584 return NULL; 01585 } 01586 01587 memset (result, 0, sizeof (CRStatement)); 01588 result->type = AT_CHARSET_RULE_STMT; 01589 01590 result->kind.charset_rule = g_try_malloc (sizeof (CRAtCharsetRule)); 01591 01592 if (!result->kind.charset_rule) { 01593 cr_utils_trace_info ("Out of memory"); 01594 g_free (result); 01595 return NULL; 01596 } 01597 memset (result->kind.charset_rule, 0, sizeof (CRAtCharsetRule)); 01598 result->kind.charset_rule->charset = a_charset; 01599 cr_statement_set_parent_sheet (result, a_sheet); 01600 01601 return result; 01602 } 01603 01604 /** 01605 * cr_statement_at_charset_rule_parse_from_buf: 01606 * 01607 *@a_buf: the buffer to parse. 01608 *@a_encoding: the character encoding of the buffer. 01609 * 01610 *Parses a buffer that contains an '\@charset' rule and 01611 *creates an instance of #CRStatement of type AT_CHARSET_RULE_STMT. 01612 * 01613 *Returns the newly built instance of #CRStatement. 01614 */ 01615 CRStatement * 01616 cr_statement_at_charset_rule_parse_from_buf (const guchar * a_buf, 01617 enum CREncoding a_encoding) 01618 { 01619 enum CRStatus status = CR_OK; 01620 CRParser *parser = NULL; 01621 CRStatement *result = NULL; 01622 CRString *charset = NULL; 01623 01624 g_return_val_if_fail (a_buf, NULL); 01625 01626 parser = cr_parser_new_from_buf ((guchar*)a_buf, strlen (a_buf), 01627 a_encoding, FALSE); 01628 if (!parser) { 01629 cr_utils_trace_info ("Instanciation of the parser failed."); 01630 goto cleanup; 01631 } 01632 01633 /*Now, invoke the parser to parse the "@charset production" */ 01634 cr_parser_try_to_skip_spaces_and_comments (parser); 01635 if (status != CR_OK) 01636 goto cleanup; 01637 status = cr_parser_parse_charset (parser, &charset, NULL); 01638 if (status != CR_OK || !charset) 01639 goto cleanup; 01640 01641 result = cr_statement_new_at_charset_rule (NULL, charset); 01642 if (result) 01643 charset = NULL; 01644 01645 cleanup: 01646 01647 if (parser) { 01648 cr_parser_destroy (parser); 01649 parser = NULL; 01650 } 01651 if (charset) { 01652 cr_string_destroy (charset); 01653 } 01654 01655 return result; 01656 } 01657 01658 /** 01659 * cr_statement_new_at_font_face_rule: 01660 * 01661 *@a_font_decls: a list of instances of #CRDeclaration. Each declaration 01662 *is actually a font declaration. 01663 * 01664 *Creates an instance of #CRStatement of type #CRAtFontFaceRule. 01665 * 01666 *Returns the newly built instance of #CRStatement. 01667 */ 01668 CRStatement * 01669 cr_statement_new_at_font_face_rule (CRStyleSheet * a_sheet, 01670 CRDeclaration * a_font_decls) 01671 { 01672 CRStatement *result = NULL; 01673 01674 result = g_try_malloc (sizeof (CRStatement)); 01675 01676 if (!result) { 01677 cr_utils_trace_info ("Out of memory"); 01678 return NULL; 01679 } 01680 memset (result, 0, sizeof (CRStatement)); 01681 result->type = AT_FONT_FACE_RULE_STMT; 01682 01683 result->kind.font_face_rule = g_try_malloc 01684 (sizeof (CRAtFontFaceRule)); 01685 01686 if (!result->kind.font_face_rule) { 01687 cr_utils_trace_info ("Out of memory"); 01688 g_free (result); 01689 return NULL; 01690 } 01691 memset (result->kind.font_face_rule, 0, sizeof (CRAtFontFaceRule)); 01692 01693 result->kind.font_face_rule->decl_list = a_font_decls; 01694 if (a_sheet) 01695 cr_statement_set_parent_sheet (result, a_sheet); 01696 01697 return result; 01698 } 01699 01700 /** 01701 * cr_statement_font_face_rule_parse_from_buf: 01702 * 01703 * 01704 *@a_buf: the buffer to parse. 01705 *@a_encoding: the character encoding of a_buf. 01706 * 01707 *Parses a buffer that contains an "\@font-face" rule and builds 01708 *an instance of #CRStatement of type AT_FONT_FACE_RULE_STMT out of it. 01709 * 01710 *Returns the newly built instance of #CRStatement in case of successufull 01711 *parsing, NULL otherwise. 01712 */ 01713 CRStatement * 01714 cr_statement_font_face_rule_parse_from_buf (const guchar * a_buf, 01715 enum CREncoding a_encoding) 01716 { 01717 CRStatement *result = NULL; 01718 CRStatement **resultptr = NULL; 01719 CRParser *parser = NULL; 01720 CRDocHandler *sac_handler = NULL; 01721 enum CRStatus status = CR_OK; 01722 01723 parser = cr_parser_new_from_buf ((guchar*)a_buf, strlen (a_buf), 01724 a_encoding, FALSE); 01725 if (!parser) 01726 goto cleanup; 01727 01728 sac_handler = cr_doc_handler_new (); 01729 if (!sac_handler) 01730 goto cleanup; 01731 01732 /* 01733 *set sac callbacks here 01734 */ 01735 sac_handler->start_font_face = parse_font_face_start_font_face_cb; 01736 sac_handler->property = parse_font_face_property_cb; 01737 sac_handler->end_font_face = parse_font_face_end_font_face_cb; 01738 sac_handler->unrecoverable_error = 01739 parse_font_face_unrecoverable_error_cb; 01740 01741 status = cr_parser_set_sac_handler (parser, sac_handler); 01742 if (status != CR_OK) 01743 goto cleanup; 01744 01745 /* 01746 *cleanup spaces of comment that may be there before the real 01747 *"@font-face" thing. 01748 */ 01749 status = cr_parser_try_to_skip_spaces_and_comments (parser); 01750 if (status != CR_OK) 01751 goto cleanup; 01752 01753 status = cr_parser_parse_font_face (parser); 01754 if (status != CR_OK) 01755 goto cleanup; 01756 01757 resultptr = &result; 01758 status = cr_doc_handler_get_result (sac_handler, 01759 (gpointer *) resultptr); 01760 if (status != CR_OK || !result) 01761 goto cleanup; 01762 01763 cleanup: 01764 if (parser) { 01765 cr_parser_destroy (parser); 01766 parser = NULL; 01767 sac_handler = NULL ; 01768 } 01769 if (sac_handler) { 01770 cr_doc_handler_unref (sac_handler); 01771 sac_handler = NULL; 01772 } 01773 return result; 01774 } 01775 01776 /** 01777 * cr_statement_set_parent_sheet: 01778 * 01779 *@a_this: the current instance of #CRStatement. 01780 *@a_sheet: the sheet that contains the current statement. 01781 * 01782 *Sets the container stylesheet. 01783 * 01784 *Returns CR_OK upon successful completion, an error code otherwise. 01785 */ 01786 enum CRStatus 01787 cr_statement_set_parent_sheet (CRStatement * a_this, CRStyleSheet * a_sheet) 01788 { 01789 g_return_val_if_fail (a_this, CR_BAD_PARAM_ERROR); 01790 a_this->parent_sheet = a_sheet; 01791 return CR_OK; 01792 } 01793 01794 /** 01795 * cr_statement_get_parent_sheet: 01796 * 01797 *@a_this: the current #CRStatement. 01798 *@a_sheet: out parameter. A pointer to the sheets that 01799 * 01800 *Gets the sheets that contains the current statement. 01801 * 01802 *Returns CR_OK upon successful completion, an error code otherwise. 01803 */ 01804 enum CRStatus 01805 cr_statement_get_parent_sheet (CRStatement * a_this, CRStyleSheet ** a_sheet) 01806 { 01807 g_return_val_if_fail (a_this && a_sheet, CR_BAD_PARAM_ERROR); 01808 *a_sheet = a_this->parent_sheet; 01809 return CR_OK; 01810 } 01811 01812 /** 01813 * cr_statement_append: 01814 * 01815 *@a_this: the current instance of the statement list. 01816 *@a_new: a_new the new instance of #CRStatement to append. 01817 * 01818 *Appends a new statement to the statement list. 01819 * 01820 *Returns the new list statement list, or NULL in cas of failure. 01821 */ 01822 CRStatement * 01823 cr_statement_append (CRStatement * a_this, CRStatement * a_new) 01824 { 01825 CRStatement *cur = NULL; 01826 01827 g_return_val_if_fail (a_new, NULL); 01828 01829 if (!a_this) { 01830 return a_new; 01831 } 01832 01833 /*walk forward in the current list to find the tail list element */ 01834 for (cur = a_this; cur && cur->next; cur = cur->next) ; 01835 01836 cur->next = a_new; 01837 a_new->prev = cur; 01838 01839 return a_this; 01840 } 01841 01842 /** 01843 * cr_statement_prepend: 01844 * 01845 *@a_this: the current instance of #CRStatement. 01846 *@a_new: the new statement to prepend. 01847 * 01848 *Prepends the an instance of #CRStatement to 01849 *the current statement list. 01850 * 01851 *Returns the new list with the new statement prepended, 01852 *or NULL in case of an error. 01853 */ 01854 CRStatement * 01855 cr_statement_prepend (CRStatement * a_this, CRStatement * a_new) 01856 { 01857 CRStatement *cur = NULL; 01858 01859 g_return_val_if_fail (a_new, NULL); 01860 01861 if (!a_this) 01862 return a_new; 01863 01864 a_new->next = a_this; 01865 a_this->prev = a_new; 01866 01867 /*walk backward in the prepended list to find the head list element */ 01868 for (cur = a_new; cur && cur->prev; cur = cur->prev) ; 01869 01870 return cur; 01871 } 01872 01873 /** 01874 * cr_statement_unlink: 01875 * 01876 *@a_this: the current statements list. 01877 *@a_to_unlink: the statement to unlink from the list. 01878 * 01879 *Unlinks a statement from the statements list. 01880 * 01881 *Returns the new list where a_to_unlink has been unlinked 01882 *from, or NULL in case of error. 01883 */ 01884 CRStatement * 01885 cr_statement_unlink (CRStatement * a_stmt) 01886 { 01887 CRStatement *result = a_stmt; 01888 01889 g_return_val_if_fail (result, NULL); 01890 01891 /** 01892 *Some sanity checks first 01893 */ 01894 if (a_stmt->next) { 01895 g_return_val_if_fail (a_stmt->next->prev == a_stmt, NULL); 01896 } 01897 if (a_stmt->prev) { 01898 g_return_val_if_fail (a_stmt->prev->next == a_stmt, NULL); 01899 } 01900 01901 /** 01902 *Now, the real unlinking job. 01903 */ 01904 if (a_stmt->next) { 01905 a_stmt->next->prev = a_stmt->prev; 01906 } 01907 if (a_stmt->prev) { 01908 a_stmt->prev->next = a_stmt->next; 01909 } 01910 01911 if (a_stmt->parent_sheet 01912 && a_stmt->parent_sheet->statements == a_stmt) { 01913 a_stmt->parent_sheet->statements = 01914 a_stmt->parent_sheet->statements->next; 01915 } 01916 01917 a_stmt->next = NULL; 01918 a_stmt->prev = NULL; 01919 a_stmt->parent_sheet = NULL; 01920 01921 return result; 01922 } 01923 01924 /** 01925 * cr_statement_nr_rules: 01926 * 01927 *@a_this: the current instance of #CRStatement. 01928 * 01929 *Gets the number of rules in the statement list; 01930 * 01931 *Returns number of rules in the statement list. 01932 */ 01933 gint 01934 cr_statement_nr_rules (CRStatement const * a_this) 01935 { 01936 CRStatement const *cur = NULL; 01937 int nr = 0; 01938 01939 g_return_val_if_fail (a_this, -1); 01940 01941 for (cur = a_this; cur; cur = cur->next) 01942 nr++; 01943 return nr; 01944 } 01945 01946 /** 01947 * cr_statement_get_from_list: 01948 * 01949 *@a_this: the current instance of #CRStatement. 01950 *@itemnr: the index into the statement list. 01951 * 01952 *Use an index to get a CRStatement from the statement list. 01953 * 01954 *Returns CRStatement at position itemnr, if itemnr > number of statements - 1, 01955 *it will return NULL. 01956 */ 01957 CRStatement * 01958 cr_statement_get_from_list (CRStatement * a_this, int itemnr) 01959 { 01960 CRStatement *cur = NULL; 01961 int nr = 0; 01962 01963 g_return_val_if_fail (a_this, NULL); 01964 01965 for (cur = a_this; cur; cur = cur->next) 01966 if (nr++ == itemnr) 01967 return cur; 01968 return NULL; 01969 } 01970 01971 /** 01972 * cr_statement_ruleset_set_sel_list: 01973 * 01974 *@a_this: the current ruleset statement. 01975 *@a_sel_list: the selector list to set. Note 01976 *that this function increments the ref count of a_sel_list. 01977 *The sel list will be destroyed at the destruction of the 01978 *current instance of #CRStatement. 01979 * 01980 *Sets a selector list to a ruleset statement. 01981 * 01982 *Returns CR_OK upon successful completion, an error code otherwise. 01983 */ 01984 enum CRStatus 01985 cr_statement_ruleset_set_sel_list (CRStatement * a_this, 01986 CRSelector * a_sel_list) 01987 { 01988 g_return_val_if_fail (a_this && a_this->type == RULESET_STMT, 01989 CR_BAD_PARAM_ERROR); 01990 01991 if (a_this->kind.ruleset->sel_list) 01992 cr_selector_unref (a_this->kind.ruleset->sel_list); 01993 01994 a_this->kind.ruleset->sel_list = a_sel_list; 01995 01996 if (a_sel_list) 01997 cr_selector_ref (a_sel_list); 01998 01999 return CR_OK; 02000 } 02001 02002 /** 02003 * cr_statement_ruleset_get_declarations: 02004 * 02005 *@a_this: the current instance of #CRStatement. 02006 *@a_decl_list: out parameter. A pointer to the the returned 02007 *list of declaration. Must not be NULL. 02008 * 02009 *Gets a pointer to the list of declaration contained 02010 *in the ruleset statement. 02011 * 02012 *Returns CR_OK upon successful completion, an error code if something 02013 *bad happened. 02014 */ 02015 enum CRStatus 02016 cr_statement_ruleset_get_declarations (CRStatement * a_this, 02017 CRDeclaration ** a_decl_list) 02018 { 02019 g_return_val_if_fail (a_this 02020 && a_this->type == RULESET_STMT 02021 && a_this->kind.ruleset 02022 && a_decl_list, CR_BAD_PARAM_ERROR); 02023 02024 *a_decl_list = a_this->kind.ruleset->decl_list; 02025 02026 return CR_OK; 02027 } 02028 02029 /** 02030 * cr_statement_ruleset_get_sel_list: 02031 * 02032 *@a_this: the current ruleset statement. 02033 *@a_list: out parameter. The returned selector list, 02034 *if and only if the function returned CR_OK. 02035 * 02036 *Gets a pointer to the selector list contained in 02037 *the current ruleset statement. 02038 * 02039 *Returns CR_OK upon successful completion, an error code otherwise. 02040 */ 02041 enum CRStatus 02042 cr_statement_ruleset_get_sel_list (CRStatement const * a_this, CRSelector ** a_list) 02043 { 02044 g_return_val_if_fail (a_this && a_this->type == RULESET_STMT 02045 && a_this->kind.ruleset, CR_BAD_PARAM_ERROR); 02046 02047 *a_list = a_this->kind.ruleset->sel_list; 02048 02049 return CR_OK; 02050 } 02051 02052 /** 02053 * cr_statement_ruleset_set_decl_list: 02054 * 02055 *@a_this: the current ruleset statement. 02056 *@a_list: the declaration list to be added to the current 02057 *ruleset statement. 02058 * 02059 *Sets a declaration list to the current ruleset statement. 02060 * 02061 *Returns CR_OK upon successful completion, an error code otherwise. 02062 */ 02063 enum CRStatus 02064 cr_statement_ruleset_set_decl_list (CRStatement * a_this, 02065 CRDeclaration * a_list) 02066 { 02067 g_return_val_if_fail (a_this && a_this->type == RULESET_STMT 02068 && a_this->kind.ruleset, CR_BAD_PARAM_ERROR); 02069 02070 if (a_this->kind.ruleset->decl_list == a_list) 02071 return CR_OK; 02072 02073 if (a_this->kind.ruleset->sel_list) { 02074 cr_declaration_destroy (a_this->kind.ruleset->decl_list); 02075 } 02076 02077 a_this->kind.ruleset->sel_list = NULL; 02078 02079 return CR_OK; 02080 } 02081 02082 /** 02083 * cr_statement_ruleset_append_decl2: 02084 * 02085 *@a_this: the current statement. 02086 *@a_prop: the property of the declaration. 02087 *@a_value: the value of the declaration. 02088 * 02089 *Appends a declaration to the current ruleset statement. 02090 * 02091 *Returns CR_OK upon successful completion, an error code 02092 *otherwise. 02093 */ 02094 enum CRStatus 02095 cr_statement_ruleset_append_decl2 (CRStatement * a_this, 02096 CRString * a_prop, 02097 CRTerm * a_value) 02098 { 02099 CRDeclaration *new_decls = NULL; 02100 02101 g_return_val_if_fail (a_this && a_this->type == RULESET_STMT 02102 && a_this->kind.ruleset, CR_BAD_PARAM_ERROR); 02103 02104 new_decls = cr_declaration_append2 02105 (a_this->kind.ruleset->decl_list, 02106 a_prop, a_value); 02107 g_return_val_if_fail (new_decls, CR_ERROR); 02108 a_this->kind.ruleset->decl_list = new_decls; 02109 02110 return CR_OK; 02111 } 02112 02113 /** 02114 * cr_statement_ruleset_append_decl: 02115 * 02116 *Appends a declaration to the current statement. 02117 * 02118 *@a_this: the current statement. 02119 *@a_declaration: the declaration to append. 02120 * 02121 *Returns CR_OK upon sucessful completion, an error code 02122 *otherwise. 02123 */ 02124 enum CRStatus 02125 cr_statement_ruleset_append_decl (CRStatement * a_this, 02126 CRDeclaration * a_decl) 02127 { 02128 CRDeclaration *new_decls = NULL; 02129 02130 g_return_val_if_fail (a_this && a_this->type == RULESET_STMT 02131 && a_this->kind.ruleset, CR_BAD_PARAM_ERROR); 02132 02133 new_decls = cr_declaration_append 02134 (a_this->kind.ruleset->decl_list, a_decl); 02135 g_return_val_if_fail (new_decls, CR_ERROR); 02136 a_this->kind.ruleset->decl_list = new_decls; 02137 02138 return CR_OK; 02139 } 02140 02141 /** 02142 * cr_statement_at_import_rule_set_imported_sheet: 02143 * 02144 *Sets a stylesheet to the current \@import rule. 02145 *@a_this: the current \@import rule. 02146 *@a_sheet: the stylesheet. The stylesheet is owned 02147 *by the current instance of #CRStatement, that is, the 02148 *stylesheet will be destroyed when the current instance 02149 *of #CRStatement is destroyed. 02150 * 02151 *Returns CR_OK upon successful completion, an error code otherwise. 02152 */ 02153 enum CRStatus 02154 cr_statement_at_import_rule_set_imported_sheet (CRStatement * a_this, 02155 CRStyleSheet * a_sheet) 02156 { 02157 g_return_val_if_fail (a_this 02158 && a_this->type == AT_IMPORT_RULE_STMT 02159 && a_this->kind.import_rule, 02160 CR_BAD_PARAM_ERROR); 02161 02162 a_this->kind.import_rule->sheet = a_sheet; 02163 02164 return CR_OK; 02165 } 02166 02167 /** 02168 * cr_statement_at_import_rule_get_imported_sheet: 02169 * 02170 *@a_this: the current \@import rule statement. 02171 *@a_sheet: out parameter. The returned stylesheet if and 02172 *only if the function returns CR_OK. 02173 * 02174 *Gets the stylesheet contained by the \@import rule statement. 02175 *Returns CR_OK upon sucessful completion, an error code otherwise. 02176 */ 02177 enum CRStatus 02178 cr_statement_at_import_rule_get_imported_sheet (CRStatement * a_this, 02179 CRStyleSheet ** a_sheet) 02180 { 02181 g_return_val_if_fail (a_this 02182 && a_this->type == AT_IMPORT_RULE_STMT 02183 && a_this->kind.import_rule, 02184 CR_BAD_PARAM_ERROR); 02185 *a_sheet = a_this->kind.import_rule->sheet; 02186 return CR_OK; 02187 02188 } 02189 02190 /** 02191 * cr_statement_at_import_rule_set_url: 02192 * 02193 *@a_this: the current \@import rule statement. 02194 *@a_url: the url to set. 02195 * 02196 *Sets an url to the current \@import rule statement. 02197 * 02198 *Returns CR_OK upon successful completion, an error code otherwise. 02199 */ 02200 enum CRStatus 02201 cr_statement_at_import_rule_set_url (CRStatement * a_this, 02202 CRString * a_url) 02203 { 02204 g_return_val_if_fail (a_this 02205 && a_this->type == AT_IMPORT_RULE_STMT 02206 && a_this->kind.import_rule, 02207 CR_BAD_PARAM_ERROR); 02208 02209 if (a_this->kind.import_rule->url) { 02210 cr_string_destroy (a_this->kind.import_rule->url); 02211 } 02212 02213 a_this->kind.import_rule->url = a_url; 02214 02215 return CR_OK; 02216 } 02217 02218 /** 02219 * cr_statement_at_import_rule_get_url: 02220 * 02221 *@a_this: the current \@import rule statement. 02222 *@a_url: out parameter. The returned url if 02223 *and only if the function returned CR_OK. 02224 * 02225 *Gets the url of the \@import rule statement. 02226 *Returns CR_OK upon successful completion, an error code otherwise. 02227 */ 02228 enum CRStatus 02229 cr_statement_at_import_rule_get_url (CRStatement const * a_this, 02230 CRString ** a_url) 02231 { 02232 g_return_val_if_fail (a_this 02233 && a_this->type == AT_IMPORT_RULE_STMT 02234 && a_this->kind.import_rule, 02235 CR_BAD_PARAM_ERROR); 02236 02237 *a_url = a_this->kind.import_rule->url; 02238 02239 return CR_OK; 02240 } 02241 02242 /** 02243 * cr_statement_at_media_nr_rules: 02244 * 02245 *@a_this: the current instance of #CRStatement. 02246 * 02247 *Returns the number of rules in the media rule; 02248 */ 02249 int 02250 cr_statement_at_media_nr_rules (CRStatement const * a_this) 02251 { 02252 g_return_val_if_fail (a_this 02253 && a_this->type == AT_MEDIA_RULE_STMT 02254 && a_this->kind.media_rule, CR_BAD_PARAM_ERROR); 02255 02256 return cr_statement_nr_rules (a_this->kind.media_rule->rulesets); 02257 } 02258 02259 /** 02260 * cr_statement_at_media_get_from_list: 02261 * 02262 *@a_this: the current instance of #CRStatement. 02263 *@itemnr: the index into the media rule list of rules. 02264 * 02265 *Use an index to get a CRStatement from the media rule list of rules. 02266 * 02267 *Returns CRStatement at position itemnr, if itemnr > number of rules - 1, 02268 *it will return NULL. 02269 */ 02270 CRStatement * 02271 cr_statement_at_media_get_from_list (CRStatement * a_this, int itemnr) 02272 { 02273 g_return_val_if_fail (a_this 02274 && a_this->type == AT_MEDIA_RULE_STMT 02275 && a_this->kind.media_rule, NULL); 02276 02277 return cr_statement_get_from_list (a_this->kind.media_rule->rulesets, 02278 itemnr); 02279 } 02280 02281 /** 02282 * cr_statement_at_page_rule_set_declarations: 02283 * 02284 *@a_this: the current \@page rule statement. 02285 *@a_decl_list: the declaration list to add. Will be freed 02286 *by the current instance of #CRStatement when it is destroyed. 02287 * 02288 *Sets a declaration list to the current \@page rule statement. 02289 * 02290 *Returns CR_OK upon successful completion, an error code otherwise. 02291 */ 02292 enum CRStatus 02293 cr_statement_at_page_rule_set_declarations (CRStatement * a_this, 02294 CRDeclaration * a_decl_list) 02295 { 02296 g_return_val_if_fail (a_this 02297 && a_this->type == AT_PAGE_RULE_STMT 02298 && a_this->kind.page_rule, CR_BAD_PARAM_ERROR); 02299 02300 if (a_this->kind.page_rule->decl_list) { 02301 cr_declaration_unref (a_this->kind.page_rule->decl_list); 02302 } 02303 02304 a_this->kind.page_rule->decl_list = a_decl_list; 02305 02306 if (a_decl_list) { 02307 cr_declaration_ref (a_decl_list); 02308 } 02309 02310 return CR_OK; 02311 } 02312 02313 /** 02314 * cr_statement_at_page_rule_get_declarations: 02315 * 02316 *@a_this: the current \@page rule statement. 02317 *@a_decl_list: out parameter. The returned declaration list. 02318 * 02319 *Gets the declaration list associated to the current \@page rule 02320 *statement. 02321 * 02322 *Returns CR_OK upon successful completion, an error code otherwise. 02323 */ 02324 enum CRStatus 02325 cr_statement_at_page_rule_get_declarations (CRStatement * a_this, 02326 CRDeclaration ** a_decl_list) 02327 { 02328 g_return_val_if_fail (a_this 02329 && a_this->type == AT_PAGE_RULE_STMT 02330 && a_this->kind.page_rule, CR_BAD_PARAM_ERROR); 02331 02332 *a_decl_list = a_this->kind.page_rule->decl_list; 02333 02334 return CR_OK; 02335 } 02336 02337 /** 02338 * cr_statement_at_charset_rule_set_charset: 02339 * 02340 * 02341 *@a_this: the current \@charset rule statement. 02342 *@a_charset: the charset to set. 02343 * 02344 *Sets the charset of the current \@charset rule statement. 02345 * 02346 *Returns CR_OK upon successful completion, an error code otherwise. 02347 */ 02348 enum CRStatus 02349 cr_statement_at_charset_rule_set_charset (CRStatement * a_this, 02350 CRString * a_charset) 02351 { 02352 g_return_val_if_fail (a_this 02353 && a_this->type == AT_CHARSET_RULE_STMT 02354 && a_this->kind.charset_rule, 02355 CR_BAD_PARAM_ERROR); 02356 02357 if (a_this->kind.charset_rule->charset) { 02358 cr_string_destroy (a_this->kind.charset_rule->charset); 02359 } 02360 a_this->kind.charset_rule->charset = a_charset; 02361 return CR_OK; 02362 } 02363 02364 /** 02365 * cr_statement_at_charset_rule_get_charset: 02366 *@a_this: the current \@charset rule statement. 02367 *@a_charset: out parameter. The returned charset string if 02368 *and only if the function returned CR_OK. 02369 * 02370 *Gets the charset string associated to the current 02371 *\@charset rule statement. 02372 * 02373 * Returns CR_OK upon successful completion, an error code otherwise. 02374 */ 02375 enum CRStatus 02376 cr_statement_at_charset_rule_get_charset (CRStatement const * a_this, 02377 CRString ** a_charset) 02378 { 02379 g_return_val_if_fail (a_this 02380 && a_this->type == AT_CHARSET_RULE_STMT 02381 && a_this->kind.charset_rule, 02382 CR_BAD_PARAM_ERROR); 02383 02384 *a_charset = a_this->kind.charset_rule->charset; 02385 02386 return CR_OK; 02387 } 02388 02389 /** 02390 * cr_statement_at_font_face_rule_set_decls: 02391 * 02392 *@a_this: the current \@font-face rule statement. 02393 *@a_decls: the declarations list to set. 02394 * 02395 *Sets a declaration list to the current \@font-face rule statement. 02396 * 02397 *Returns CR_OK upon successful completion, an error code otherwise. 02398 */ 02399 enum CRStatus 02400 cr_statement_at_font_face_rule_set_decls (CRStatement * a_this, 02401 CRDeclaration * a_decls) 02402 { 02403 g_return_val_if_fail (a_this 02404 && a_this->type == AT_FONT_FACE_RULE_STMT 02405 && a_this->kind.font_face_rule, 02406 CR_BAD_PARAM_ERROR); 02407 02408 if (a_this->kind.font_face_rule->decl_list) { 02409 cr_declaration_unref (a_this->kind.font_face_rule->decl_list); 02410 } 02411 02412 a_this->kind.font_face_rule->decl_list = a_decls; 02413 cr_declaration_ref (a_decls); 02414 02415 return CR_OK; 02416 } 02417 02418 /** 02419 * cr_statement_at_font_face_rule_get_decls: 02420 * 02421 *@a_this: the current \@font-face rule statement. 02422 *@a_decls: out parameter. The returned declaration list if 02423 *and only if this function returns CR_OK. 02424 * 02425 *Gets the declaration list associated to the current instance 02426 *of \@font-face rule statement. 02427 * 02428 *Returns CR_OK upon successful completion, an error code otherwise. 02429 */ 02430 enum CRStatus 02431 cr_statement_at_font_face_rule_get_decls (CRStatement * a_this, 02432 CRDeclaration ** a_decls) 02433 { 02434 g_return_val_if_fail (a_this 02435 && a_this->type == AT_FONT_FACE_RULE_STMT 02436 && a_this->kind.font_face_rule, 02437 CR_BAD_PARAM_ERROR); 02438 02439 *a_decls = a_this->kind.font_face_rule->decl_list; 02440 02441 return CR_OK; 02442 } 02443 02444 /** 02445 * cr_statement_at_font_face_rule_add_decl: 02446 * 02447 *@a_this: the current \@font-face rule statement. 02448 *@a_prop: the property of the declaration. 02449 *@a_value: the value of the declaration. 02450 * 02451 *Adds a declaration to the current \@font-face rule 02452 *statement. 02453 * 02454 *Returns CR_OK upon successful completion, an error code otherwise. 02455 */ 02456 enum CRStatus 02457 cr_statement_at_font_face_rule_add_decl (CRStatement * a_this, 02458 CRString * a_prop, CRTerm * a_value) 02459 { 02460 CRDeclaration *decls = NULL; 02461 02462 g_return_val_if_fail (a_this 02463 && a_this->type == AT_FONT_FACE_RULE_STMT 02464 && a_this->kind.font_face_rule, 02465 CR_BAD_PARAM_ERROR); 02466 02467 decls = cr_declaration_append2 02468 (a_this->kind.font_face_rule->decl_list, 02469 a_prop, a_value); 02470 02471 g_return_val_if_fail (decls, CR_ERROR); 02472 02473 if (a_this->kind.font_face_rule->decl_list == NULL) 02474 cr_declaration_ref (decls); 02475 02476 a_this->kind.font_face_rule->decl_list = decls; 02477 02478 return CR_OK; 02479 } 02480 02481 02482 /** 02483 * cr_statement_to_string: 02484 * 02485 *@a_this: the current statement to serialize 02486 *@a_indent: the number of white space of indentation. 02487 * 02488 *Serializes a css statement into a string 02489 * 02490 *Returns the serialized statement. Must be freed by the caller 02491 *using g_free(). 02492 */ 02493 gchar * 02494 cr_statement_to_string (CRStatement const * a_this, gulong a_indent) 02495 { 02496 gchar *str = NULL ; 02497 02498 if (!a_this) 02499 return NULL; 02500 02501 switch (a_this->type) { 02502 case RULESET_STMT: 02503 str = cr_statement_ruleset_to_string 02504 (a_this, a_indent); 02505 break; 02506 02507 case AT_FONT_FACE_RULE_STMT: 02508 str = cr_statement_font_face_rule_to_string 02509 (a_this, a_indent) ; 02510 break; 02511 02512 case AT_CHARSET_RULE_STMT: 02513 str = cr_statement_charset_to_string 02514 (a_this, a_indent); 02515 break; 02516 02517 case AT_PAGE_RULE_STMT: 02518 str = cr_statement_at_page_rule_to_string 02519 (a_this, a_indent); 02520 break; 02521 02522 case AT_MEDIA_RULE_STMT: 02523 str = cr_statement_media_rule_to_string 02524 (a_this, a_indent); 02525 break; 02526 02527 case AT_IMPORT_RULE_STMT: 02528 str = cr_statement_import_rule_to_string 02529 (a_this, a_indent); 02530 break; 02531 02532 default: 02533 cr_utils_trace_info ("Statement unrecognized"); 02534 break; 02535 } 02536 return str ; 02537 } 02538 02539 gchar* 02540 cr_statement_list_to_string (CRStatement const *a_this, gulong a_indent) 02541 { 02542 CRStatement const *cur_stmt = NULL ; 02543 GString *stringue = NULL ; 02544 gchar *str = NULL ; 02545 02546 g_return_val_if_fail (a_this, NULL) ; 02547 02548 stringue = g_string_new (NULL) ; 02549 if (!stringue) { 02550 cr_utils_trace_info ("Out of memory") ; 02551 return NULL ; 02552 } 02553 for (cur_stmt = a_this ; cur_stmt; 02554 cur_stmt = cur_stmt->next) { 02555 str = cr_statement_to_string (cur_stmt, a_indent) ; 02556 if (str) { 02557 if (!cur_stmt->prev) { 02558 g_string_append (stringue, str) ; 02559 } else { 02560 g_string_append_printf 02561 (stringue, "\n%s", str) ; 02562 } 02563 g_free (str) ; 02564 str = NULL ; 02565 } 02566 } 02567 str = stringue->str ; 02568 g_string_free (stringue, FALSE) ; 02569 return str ; 02570 } 02571 02572 /** 02573 * cr_statement_dump: 02574 * 02575 *@a_this: the current css2 statement. 02576 *@a_fp: the destination file pointer. 02577 *@a_indent: the number of white space indentation characters. 02578 * 02579 *Dumps the css2 statement to a file. 02580 */ 02581 void 02582 cr_statement_dump (CRStatement const * a_this, FILE * a_fp, gulong a_indent) 02583 { 02584 gchar *str = NULL ; 02585 02586 if (!a_this) 02587 return; 02588 02589 str = cr_statement_to_string (a_this, a_indent) ; 02590 if (str) { 02591 fprintf (a_fp, "%s",str) ; 02592 g_free (str) ; 02593 str = NULL ; 02594 } 02595 } 02596 02597 /** 02598 * cr_statement_dump_ruleset: 02599 * 02600 *@a_this: the current instance of #CRStatement. 02601 *@a_fp: the destination file pointer. 02602 *@a_indent: the number of indentation white spaces to add. 02603 * 02604 *Dumps a ruleset statement to a file. 02605 */ 02606 void 02607 cr_statement_dump_ruleset (CRStatement const * a_this, FILE * a_fp, glong a_indent) 02608 { 02609 guchar *str = NULL; 02610 02611 g_return_if_fail (a_fp && a_this); 02612 str = cr_statement_ruleset_to_string (a_this, a_indent); 02613 if (str) { 02614 fprintf (a_fp, "%s", str); 02615 g_free (str); 02616 str = NULL; 02617 } 02618 } 02619 02620 /** 02621 * cr_statement_dump_font_face_rule: 02622 * 02623 *@a_this: the current instance of font face rule statement. 02624 *@a_fp: the destination file pointer. 02625 *@a_indent: the number of white space indentation. 02626 * 02627 *Dumps a font face rule statement to a file. 02628 */ 02629 void 02630 cr_statement_dump_font_face_rule (CRStatement const * a_this, FILE * a_fp, 02631 glong a_indent) 02632 { 02633 gchar *str = NULL ; 02634 g_return_if_fail (a_this 02635 && a_this->type == AT_FONT_FACE_RULE_STMT); 02636 02637 str = cr_statement_font_face_rule_to_string (a_this, 02638 a_indent) ; 02639 if (str) { 02640 fprintf (a_fp, "%s", str) ; 02641 g_free (str) ; 02642 str = NULL ; 02643 } 02644 } 02645 02646 /** 02647 * cr_statement_dump_charset: 02648 * 02649 *@a_this: the current instance of the \@charset rule statement. 02650 *@a_fp: the destination file pointer. 02651 *@a_indent: the number of indentation white spaces. 02652 * 02653 *Dumps an \@charset rule statement to a file. 02654 */ 02655 void 02656 cr_statement_dump_charset (CRStatement const * a_this, FILE * a_fp, gulong a_indent) 02657 { 02658 guchar *str = NULL; 02659 02660 g_return_if_fail (a_this && a_this->type == AT_CHARSET_RULE_STMT); 02661 02662 str = cr_statement_charset_to_string (a_this, 02663 a_indent) ; 02664 if (str) { 02665 fprintf (a_fp, "%s", str) ; 02666 g_free (str) ; 02667 str = NULL ; 02668 } 02669 } 02670 02671 02672 /** 02673 * cr_statement_dump_page: 02674 * 02675 *@a_this: the statement to dump on stdout. 02676 *@a_fp: the destination file pointer. 02677 *@a_indent: the number of indentation white spaces. 02678 * 02679 *Dumps an \@page rule statement on stdout. 02680 */ 02681 void 02682 cr_statement_dump_page (CRStatement const * a_this, FILE * a_fp, gulong a_indent) 02683 { 02684 guchar *str = NULL; 02685 02686 g_return_if_fail (a_this 02687 && a_this->type == AT_PAGE_RULE_STMT 02688 && a_this->kind.page_rule); 02689 02690 str = cr_statement_at_page_rule_to_string (a_this, a_indent) ; 02691 if (str) { 02692 fprintf (a_fp, "%s", str); 02693 g_free (str) ; 02694 str = NULL ; 02695 } 02696 } 02697 02698 02699 /** 02700 * cr_statement_dump_media_rule: 02701 * 02702 *@a_this: the statement to dump. 02703 *@a_fp: the destination file pointer 02704 *@a_indent: the number of white spaces indentation. 02705 * 02706 *Dumps an \@media rule statement to a file. 02707 */ 02708 void 02709 cr_statement_dump_media_rule (CRStatement const * a_this, 02710 FILE * a_fp, 02711 gulong a_indent) 02712 { 02713 gchar *str = NULL ; 02714 g_return_if_fail (a_this->type == AT_MEDIA_RULE_STMT); 02715 02716 str = cr_statement_media_rule_to_string (a_this, a_indent) ; 02717 if (str) { 02718 fprintf (a_fp, "%s", str) ; 02719 g_free (str) ; 02720 str = NULL ; 02721 } 02722 } 02723 02724 /** 02725 * cr_statement_dump_import_rule: 02726 * 02727 *@a_fp: the destination file pointer. 02728 *@a_indent: the number of white space indentations. 02729 * 02730 *Dumps an \@import rule statement to a file. 02731 */ 02732 void 02733 cr_statement_dump_import_rule (CRStatement const * a_this, FILE * a_fp, 02734 gulong a_indent) 02735 { 02736 gchar *str = NULL ; 02737 g_return_if_fail (a_this 02738 && a_this->type == AT_IMPORT_RULE_STMT 02739 && a_fp 02740 && a_this->kind.import_rule); 02741 02742 str = cr_statement_import_rule_to_string (a_this, a_indent) ; 02743 if (str) { 02744 fprintf (a_fp, "%s", str) ; 02745 g_free (str) ; 02746 str = NULL ; 02747 } 02748 } 02749 02750 /** 02751 * cr_statement_destroy: 02752 * 02753 * @a_this: the current instance of #CRStatement. 02754 * 02755 *Destructor of #CRStatement. 02756 */ 02757 void 02758 cr_statement_destroy (CRStatement * a_this) 02759 { 02760 CRStatement *cur = NULL; 02761 02762 g_return_if_fail (a_this); 02763 02764 /*go get the tail of the list */ 02765 for (cur = a_this; cur && cur->next; cur = cur->next) { 02766 cr_statement_clear (cur); 02767 } 02768 02769 if (cur) 02770 cr_statement_clear (cur); 02771 02772 if (cur->prev == NULL) { 02773 g_free (a_this); 02774 return; 02775 } 02776 02777 /*walk backward and free next element */ 02778 for (cur = cur->prev; cur && cur->prev; cur = cur->prev) { 02779 if (cur->next) { 02780 g_free (cur->next); 02781 cur->next = NULL; 02782 } 02783 } 02784 02785 if (!cur) 02786 return; 02787 02788 /*free the one remaining list */ 02789 if (cur->next) { 02790 g_free (cur->next); 02791 cur->next = NULL; 02792 } 02793 02794 g_free (cur); 02795 cur = NULL; 02796 }