Libcroco
cr-statement.c
Go to the documentation of this file.
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 }