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                         (gchar *) cr_selector_to_string (a_this->kind.ruleset->
00605                                                sel_list);
00606                 if (tmp_str) {
00607                         g_string_append (stringue, tmp_str);
00608                         g_free (tmp_str);
00609                         tmp_str = NULL;
00610                 }
00611         }
00612         g_string_append (stringue, " {\n");
00613         if (a_this->kind.ruleset->decl_list) {
00614                 tmp_str = (gchar *) cr_declaration_list_to_string2
00615                         (a_this->kind.ruleset->decl_list,
00616                          a_indent + DECLARATION_INDENT_NB, TRUE);
00617                 if (tmp_str) {
00618                         g_string_append (stringue, tmp_str);
00619                         g_free (tmp_str);
00620                         tmp_str = NULL;
00621                 }
00622                 g_string_append (stringue, "\n");
00623                 cr_utils_dump_n_chars2 (' ', stringue, a_indent);
00624         }
00625         g_string_append (stringue, "}");
00626         result = stringue->str;
00627 
00628         if (stringue) {
00629                 g_string_free (stringue, FALSE);
00630                 stringue = NULL;
00631         }
00632         if (tmp_str) {
00633                 g_free (tmp_str);
00634                 tmp_str = NULL;
00635         }
00636         return result;
00637 }
00638 
00639 
00640 /**
00641  * cr_statement_font_face_rule_to_string:
00642  *
00643  *@a_this: the current instance of #CRStatement to consider
00644  *It must be a font face rule statement.
00645  *@a_indent: the number of white spaces of indentation.
00646  *
00647  *Serializes a font face rule statement into a string.
00648  *
00649  *Returns the serialized string. Must be deallocated by the caller
00650  *using g_free().
00651  */
00652 static gchar *
00653 cr_statement_font_face_rule_to_string (CRStatement const * a_this,
00654                                        glong a_indent)
00655 {
00656         gchar *result = NULL, *tmp_str = NULL ;
00657         GString *stringue = NULL ;
00658 
00659         g_return_val_if_fail (a_this 
00660                               && a_this->type == AT_FONT_FACE_RULE_STMT,
00661                               NULL);
00662 
00663         if (a_this->kind.font_face_rule->decl_list) {
00664                 stringue = g_string_new (NULL) ;
00665                 g_return_val_if_fail (stringue, NULL) ;
00666                 if (a_indent)
00667                         cr_utils_dump_n_chars2 (' ', stringue, 
00668                                         a_indent);
00669                 g_string_append (stringue, "@font-face {\n");
00670                 tmp_str = (gchar *) cr_declaration_list_to_string2 
00671                         (a_this->kind.font_face_rule->decl_list,
00672                          a_indent + DECLARATION_INDENT_NB, TRUE) ;
00673                 if (tmp_str) {
00674                         g_string_append (stringue,
00675                                          tmp_str) ;
00676                         g_free (tmp_str) ;
00677                         tmp_str = NULL ;
00678                 }
00679                 g_string_append (stringue, "\n}");
00680         }
00681         if (stringue) {
00682                 result = stringue->str ;
00683                 g_string_free (stringue, FALSE) ;
00684                 stringue = NULL ;
00685         }
00686         return result ;
00687 }
00688 
00689 
00690 /**
00691  * cr_statement_charset_to_string:
00692  *
00693  *Serialises an \@charset statement into a string.
00694  *@a_this: the statement to serialize.
00695  *@a_indent: the number of indentation spaces
00696  *
00697  *Returns the serialized charset statement. Must be
00698  *freed by the caller using g_free().
00699  */
00700 static gchar *
00701 cr_statement_charset_to_string (CRStatement const *a_this,
00702                                 gulong a_indent)
00703 {
00704         gchar *str = NULL ;
00705         GString *stringue = NULL ;
00706 
00707         g_return_val_if_fail (a_this
00708                               && a_this->type == AT_CHARSET_RULE_STMT,
00709                               NULL) ;
00710 
00711         if (a_this->kind.charset_rule
00712             && a_this->kind.charset_rule->charset
00713             && a_this->kind.charset_rule->charset->stryng
00714             && a_this->kind.charset_rule->charset->stryng->str) {
00715                 str = g_strndup (a_this->kind.charset_rule->charset->stryng->str,
00716                                  a_this->kind.charset_rule->charset->stryng->len);
00717                 g_return_val_if_fail (str, NULL);
00718                 stringue = g_string_new (NULL) ;
00719                 g_return_val_if_fail (stringue, NULL) ;
00720                 cr_utils_dump_n_chars2 (' ', stringue, a_indent);
00721                 g_string_append_printf (stringue, 
00722                                         "@charset \"%s\" ;", str);
00723                 if (str) {
00724                         g_free (str);
00725                         str = NULL;
00726                 }
00727         }
00728         if (stringue) {
00729                 str = stringue->str ;
00730                 g_string_free (stringue, FALSE) ;
00731         }
00732         return str ;
00733 }
00734 
00735 
00736 /**
00737  * cr_statement_at_page_rule_to_string:
00738  *
00739  *Serialises the at page rule statement into a string
00740  *@a_this: the current instance of #CRStatement. Must
00741  *be an "\@page" rule statement.
00742  *
00743  *Returns the serialized string. Must be freed by the caller
00744  */
00745 static gchar *
00746 cr_statement_at_page_rule_to_string (CRStatement const *a_this,
00747                                      gulong a_indent)
00748 {
00749         GString *stringue = NULL;
00750         gchar *result = NULL ;
00751 
00752         stringue = g_string_new (NULL) ;
00753 
00754         cr_utils_dump_n_chars2 (' ', stringue, a_indent) ;
00755         g_string_append (stringue, "@page");
00756         if (a_this->kind.page_rule->name
00757             && a_this->kind.page_rule->name->stryng) {
00758                 g_string_append_printf 
00759                   (stringue, " %s",
00760                    a_this->kind.page_rule->name->stryng->str) ;
00761         } else {
00762                 g_string_append (stringue, " ");
00763         }
00764         if (a_this->kind.page_rule->pseudo
00765             && a_this->kind.page_rule->pseudo->stryng) {
00766                 g_string_append_printf 
00767                   (stringue,  " :%s",
00768                    a_this->kind.page_rule->pseudo->stryng->str) ;
00769         }
00770         if (a_this->kind.page_rule->decl_list) {
00771                 gchar *str = NULL ;
00772                 g_string_append (stringue, " {\n");
00773                 str = (gchar *) cr_declaration_list_to_string2
00774                         (a_this->kind.page_rule->decl_list,
00775                          a_indent + DECLARATION_INDENT_NB, TRUE) ;
00776                 if (str) {
00777                         g_string_append (stringue, str) ;
00778                         g_free (str) ;
00779                         str = NULL ;
00780                 }
00781                 g_string_append (stringue, "\n}\n");
00782         }
00783         result = stringue->str ;
00784         g_string_free (stringue, FALSE) ;
00785         stringue = NULL ;
00786         return result ;
00787 }
00788 
00789 
00790 /**
00791  *Serializes an \@media statement.
00792  *@param a_this the current instance of #CRStatement
00793  *@param a_indent the number of spaces of indentation.
00794  *@return the serialized \@media statement. Must be freed
00795  *by the caller using g_free().
00796  */
00797 static gchar *
00798 cr_statement_media_rule_to_string (CRStatement const *a_this,
00799                                    gulong a_indent)
00800 {
00801         gchar *str = NULL ;
00802         GString *stringue = NULL ;
00803         GList const *cur = NULL;
00804 
00805         g_return_val_if_fail (a_this->type == AT_MEDIA_RULE_STMT,
00806                               NULL);
00807 
00808         if (a_this->kind.media_rule) {
00809                 stringue = g_string_new (NULL) ;                
00810                 cr_utils_dump_n_chars2 (' ', stringue, a_indent);
00811                 g_string_append (stringue, "@media");
00812 
00813                 for (cur = a_this->kind.media_rule->media_list; cur;
00814                      cur = cur->next) {
00815                         if (cur->data) {
00816                                 gchar *str2 = cr_string_dup2
00817                                         ((CRString const *) cur->data);
00818 
00819                                 if (str2) {
00820                                         if (cur->prev) {
00821                                                 g_string_append
00822                                                         (stringue, 
00823                                                          ",");
00824                                         }
00825                                         g_string_append_printf 
00826                                                 (stringue, 
00827                                                  " %s", str2);
00828                                         g_free (str2);
00829                                         str2 = NULL;
00830                                 }
00831                         }
00832                 }
00833                 g_string_append (stringue, " {\n");
00834                 str = cr_statement_list_to_string
00835                         (a_this->kind.media_rule->rulesets,
00836                          a_indent + DECLARATION_INDENT_NB) ;
00837                 if (str) {
00838                         g_string_append (stringue, str) ;
00839                         g_free (str) ;
00840                         str = NULL ;
00841                 }
00842                 g_string_append (stringue, "\n}");
00843         }
00844         if (stringue) {
00845                 str = stringue->str ;
00846                 g_string_free (stringue, FALSE) ;
00847         }
00848         return str ;
00849 }
00850 
00851 
00852 static gchar *
00853 cr_statement_import_rule_to_string (CRStatement const *a_this,
00854                                     gulong a_indent)
00855 {
00856         GString *stringue = NULL ;
00857         gchar *str = NULL;
00858 
00859         g_return_val_if_fail (a_this
00860                               && a_this->type == AT_IMPORT_RULE_STMT
00861                               && a_this->kind.import_rule,
00862                               NULL) ;
00863 
00864         if (a_this->kind.import_rule->url
00865             && a_this->kind.import_rule->url->stryng) { 
00866                 stringue = g_string_new (NULL) ;
00867                 g_return_val_if_fail (stringue, NULL) ;
00868                 str = g_strndup (a_this->kind.import_rule->url->stryng->str,
00869                                  a_this->kind.import_rule->url->stryng->len);
00870                 cr_utils_dump_n_chars2 (' ', stringue, a_indent);
00871                 if (str) {
00872                         g_string_append_printf (stringue,
00873                                                 "@import url(\"%s\")", 
00874                                                 str);
00875                         g_free (str);
00876                         str = NULL ;
00877                 } else          /*there is no url, so no import rule, get out! */
00878                         return NULL;
00879 
00880                 if (a_this->kind.import_rule->media_list) {
00881                         GList const *cur = NULL;
00882 
00883                         for (cur = a_this->kind.import_rule->media_list;
00884                              cur; cur = cur->next) {
00885                                 if (cur->data) {
00886                                         CRString const *crstr = cur->data;
00887 
00888                                         if (cur->prev) {
00889                                                 g_string_append 
00890                                                         (stringue, ", ");
00891                                         }
00892                                         if (crstr 
00893                                             && crstr->stryng
00894                                             && crstr->stryng->str) {
00895                                                 g_string_append_len 
00896                                                         (stringue,
00897                                                          crstr->stryng->str,
00898                                                          crstr->stryng->len) ;
00899                                         }
00900                                 }
00901                         }
00902                 }
00903                 g_string_append (stringue, " ;");
00904         }
00905         if (stringue) {
00906                 str = stringue->str ;
00907                 g_string_free (stringue, FALSE) ;
00908                 stringue = NULL ;
00909         }
00910         return str ;
00911 }
00912 
00913 
00914 /*******************
00915  *public functions
00916  ******************/
00917 
00918 /**
00919  * cr_statement_does_buf_parses_against_core:
00920  *
00921  *@a_buf: the buffer to parse.
00922  *@a_encoding: the character encoding of a_buf.
00923  *
00924  *Tries to parse a buffer and says whether if the content of the buffer
00925  *is a css statement as defined by the "Core CSS Grammar" (chapter 4 of the
00926  *css spec) or not.
00927  *
00928  *Returns TRUE if the buffer parses against the core grammar, false otherwise.
00929  */
00930 gboolean
00931 cr_statement_does_buf_parses_against_core (const guchar * a_buf,
00932                                            enum CREncoding a_encoding)
00933 {
00934         CRParser *parser = NULL;
00935         enum CRStatus status = CR_OK;
00936         gboolean result = FALSE;
00937 
00938         parser = cr_parser_new_from_buf ((guchar*)a_buf, strlen ((const char *) a_buf),
00939                                          a_encoding, FALSE);
00940         g_return_val_if_fail (parser, FALSE);
00941 
00942         status = cr_parser_set_use_core_grammar (parser, TRUE);
00943         if (status != CR_OK) {
00944                 goto cleanup;
00945         }
00946 
00947         status = cr_parser_parse_statement_core (parser);
00948         if (status == CR_OK) {
00949                 result = TRUE;
00950         }
00951 
00952       cleanup:
00953         if (parser) {
00954                 cr_parser_destroy (parser);
00955         }
00956 
00957         return result;
00958 }
00959 
00960 /**
00961  * cr_statement_parse_from_buf:
00962  *
00963  *@a_buf: the buffer to parse.
00964  *@a_encoding: the character encoding of a_buf.
00965  *
00966  *Parses a buffer that contains a css statement and returns 
00967  *an instance of #CRStatement in case of successful parsing.
00968  *TODO: at support of "\@import" rules.
00969  *
00970  *Returns the newly built instance of #CRStatement in case
00971  *of successful parsing, NULL otherwise.
00972  */
00973 CRStatement *
00974 cr_statement_parse_from_buf (const guchar * a_buf, enum CREncoding a_encoding)
00975 {
00976         CRStatement *result = NULL;
00977 
00978         /*
00979          *The strategy of this function is "brute force".
00980          *It tries to parse all the types of CRStatement it knows about.
00981          *I could do this a smarter way but I don't have the time now.
00982          *I think I will revisit this when time of performances and
00983          *pull based incremental parsing comes.
00984          */
00985 
00986         result = cr_statement_ruleset_parse_from_buf (a_buf, a_encoding);
00987         if (!result) {
00988                 result = cr_statement_at_charset_rule_parse_from_buf
00989                         (a_buf, a_encoding);
00990         } else {
00991                 goto out;
00992         }
00993 
00994         if (!result) {
00995                 result = cr_statement_at_media_rule_parse_from_buf
00996                         (a_buf, a_encoding);
00997         } else {
00998                 goto out;
00999         }
01000 
01001         if (!result) {
01002                 result = cr_statement_at_charset_rule_parse_from_buf
01003                         (a_buf, a_encoding);
01004         } else {
01005                 goto out;
01006         }
01007 
01008         if (!result) {
01009                 result = cr_statement_font_face_rule_parse_from_buf
01010                         (a_buf, a_encoding);
01011 
01012         } else {
01013                 goto out;
01014         }
01015 
01016         if (!result) {
01017                 result = cr_statement_at_page_rule_parse_from_buf
01018                         (a_buf, a_encoding);
01019         } else {
01020                 goto out;
01021         }
01022 
01023         if (!result) {
01024                 result = cr_statement_at_import_rule_parse_from_buf
01025                         (a_buf, a_encoding);
01026         } else {
01027                 goto out;
01028         }
01029 
01030       out:
01031         return result;
01032 }
01033 
01034 /**
01035  * cr_statement_ruleset_parse_from_buf:
01036  *
01037  *@a_buf: the buffer to parse.
01038  *@a_enc: the character encoding of a_buf.
01039  *
01040  *Parses a buffer that contains a ruleset statement an instanciates
01041  *a #CRStatement of type RULESET_STMT.
01042  *
01043  *Returns the newly built instance of #CRStatement in case of successful parsing,
01044  *NULL otherwise.
01045  */
01046 CRStatement *
01047 cr_statement_ruleset_parse_from_buf (const guchar * a_buf,
01048                                      enum CREncoding a_enc)
01049 {
01050         enum CRStatus status = CR_OK;
01051         CRStatement *result = NULL;
01052         CRStatement **resultptr = NULL;
01053         CRParser *parser = NULL;
01054         CRDocHandler *sac_handler = NULL;
01055 
01056         g_return_val_if_fail (a_buf, NULL);
01057 
01058         parser = cr_parser_new_from_buf ((guchar*)a_buf, strlen ((const char *) a_buf), 
01059                                          a_enc, FALSE);
01060 
01061         g_return_val_if_fail (parser, NULL);
01062 
01063         sac_handler = cr_doc_handler_new ();
01064         g_return_val_if_fail (parser, NULL);
01065 
01066         sac_handler->start_selector = parse_ruleset_start_selector_cb;
01067         sac_handler->end_selector = parse_ruleset_end_selector_cb;
01068         sac_handler->property = parse_ruleset_property_cb;
01069         sac_handler->unrecoverable_error =
01070                 parse_ruleset_unrecoverable_error_cb;
01071 
01072         cr_parser_set_sac_handler (parser, sac_handler);
01073         cr_parser_try_to_skip_spaces_and_comments (parser);
01074         status = cr_parser_parse_ruleset (parser);
01075         if (status != CR_OK) {
01076                 goto cleanup;
01077         }
01078 
01079         resultptr = &result;
01080         status = cr_doc_handler_get_result (sac_handler,
01081                                             (gpointer *) resultptr);
01082         if (!((status == CR_OK) && result)) {
01083                 if (result) {
01084                         cr_statement_destroy (result);
01085                         result = NULL;
01086                 }
01087         }
01088 
01089       cleanup:
01090         if (parser) {
01091                 cr_parser_destroy (parser);
01092                 parser = NULL;
01093                 sac_handler = NULL ;
01094         }
01095         if (sac_handler) {
01096                 cr_doc_handler_unref (sac_handler);
01097                 sac_handler = NULL;
01098         }
01099         return result;
01100 }
01101 
01102 /**
01103  * cr_statement_new_ruleset:
01104  *
01105  *@a_sel_list: the list of #CRSimpleSel (selectors)
01106  *the rule applies to.
01107  *@a_decl_list: the list of instances of #CRDeclaration
01108  *that composes the ruleset.
01109  *@a_media_types: a list of instances of GString that
01110  *describe the media list this ruleset applies to.
01111  *
01112  *Creates a new instance of #CRStatement of type
01113  *#CRRulSet.
01114  *
01115  *Returns the new instance of #CRStatement or NULL if something
01116  *went wrong.
01117  */
01118 CRStatement *
01119 cr_statement_new_ruleset (CRStyleSheet * a_sheet,
01120                           CRSelector * a_sel_list,
01121                           CRDeclaration * a_decl_list,
01122                           CRStatement * a_parent_media_rule)
01123 {
01124         CRStatement *result = NULL;
01125 
01126         g_return_val_if_fail (a_sel_list, NULL);
01127 
01128         if (a_parent_media_rule) {
01129                 g_return_val_if_fail
01130                         (a_parent_media_rule->type == AT_MEDIA_RULE_STMT,
01131                          NULL);
01132                 g_return_val_if_fail (a_parent_media_rule->kind.media_rule,
01133                                       NULL);
01134         }
01135 
01136         result = g_try_malloc (sizeof (CRStatement));
01137 
01138         if (!result) {
01139                 cr_utils_trace_info ("Out of memory");
01140                 return NULL;
01141         }
01142 
01143         memset (result, 0, sizeof (CRStatement));
01144         result->type = RULESET_STMT;
01145         result->kind.ruleset = g_try_malloc (sizeof (CRRuleSet));
01146 
01147         if (!result->kind.ruleset) {
01148                 cr_utils_trace_info ("Out of memory");
01149                 if (result)
01150                         g_free (result);
01151                 return NULL;
01152         }
01153 
01154         memset (result->kind.ruleset, 0, sizeof (CRRuleSet));
01155         result->kind.ruleset->sel_list = a_sel_list;
01156         if (a_sel_list)
01157                 cr_selector_ref (a_sel_list);
01158         result->kind.ruleset->decl_list = a_decl_list;
01159 
01160         if (a_parent_media_rule) {
01161                 result->kind.ruleset->parent_media_rule = a_parent_media_rule;
01162                 a_parent_media_rule->kind.media_rule->rulesets =
01163                         cr_statement_append
01164                         (a_parent_media_rule->kind.media_rule->rulesets,
01165                          result);
01166         }
01167 
01168         cr_statement_set_parent_sheet (result, a_sheet);
01169 
01170         return result;
01171 }
01172 
01173 /**
01174  * cr_statement_at_media_rule_parse_from_buf:
01175  *
01176  *@a_buf: the input to parse.
01177  *@a_enc: the encoding of the buffer.
01178  *
01179  *Parses a buffer that contains an "\@media" declaration
01180  *and builds an \@media css statement.
01181  *
01182  *Returns the \@media statement, or NULL if the buffer could not
01183  *be successfully parsed.
01184  */
01185 CRStatement *
01186 cr_statement_at_media_rule_parse_from_buf (const guchar * a_buf,
01187                                            enum CREncoding a_enc)
01188 {
01189         CRParser *parser = NULL;
01190         CRStatement *result = NULL;
01191         CRStatement **resultptr = NULL;
01192         CRDocHandler *sac_handler = NULL;
01193         enum CRStatus status = CR_OK;
01194 
01195         parser = cr_parser_new_from_buf ((guchar*)a_buf, strlen ((const char *) a_buf), 
01196                                          a_enc, FALSE);
01197         if (!parser) {
01198                 cr_utils_trace_info ("Instantiation of the parser failed");
01199                 goto cleanup;
01200         }
01201 
01202         sac_handler = cr_doc_handler_new ();
01203         if (!sac_handler) {
01204                 cr_utils_trace_info
01205                         ("Instantiation of the sac handler failed");
01206                 goto cleanup;
01207         }
01208 
01209         sac_handler->start_media = parse_at_media_start_media_cb;
01210         sac_handler->start_selector = parse_at_media_start_selector_cb;
01211         sac_handler->property = parse_at_media_property_cb;
01212         sac_handler->end_selector = parse_at_media_end_selector_cb;
01213         sac_handler->end_media = parse_at_media_end_media_cb;
01214         sac_handler->unrecoverable_error =
01215                 parse_at_media_unrecoverable_error_cb;
01216 
01217         status = cr_parser_set_sac_handler (parser, sac_handler);
01218         if (status != CR_OK)
01219                 goto cleanup;
01220 
01221         status = cr_parser_try_to_skip_spaces_and_comments (parser);
01222         if (status != CR_OK)
01223                 goto cleanup;
01224 
01225         status = cr_parser_parse_media (parser);
01226         if (status != CR_OK)
01227                 goto cleanup;
01228 
01229         resultptr = &result;
01230         status = cr_doc_handler_get_result (sac_handler,
01231                                             (gpointer *) resultptr);
01232         if (status != CR_OK)
01233                 goto cleanup;
01234 
01235       cleanup:
01236 
01237         if (parser) {
01238                 cr_parser_destroy (parser);
01239                 parser = NULL;
01240                 sac_handler = NULL ;
01241         }
01242         if (sac_handler) {
01243                 cr_doc_handler_unref (sac_handler);
01244                 sac_handler = NULL;
01245         }
01246 
01247         return result;
01248 }
01249 
01250 /**
01251  * cr_statement_new_at_media_rule:
01252  *
01253  *@a_ruleset: the ruleset statements contained
01254  *in the \@media rule.
01255  *@a_media: the media string list. A list of GString pointers.
01256  *
01257  *Instanciates an instance of #CRStatement of type
01258  *AT_MEDIA_RULE_STMT (\@media ruleset).
01259  *
01260  */
01261 CRStatement *
01262 cr_statement_new_at_media_rule (CRStyleSheet * a_sheet,
01263                                 CRStatement * a_rulesets, GList * a_media)
01264 {
01265         CRStatement *result = NULL,
01266                 *cur = NULL;
01267 
01268         if (a_rulesets)
01269                 g_return_val_if_fail (a_rulesets->type == RULESET_STMT, NULL);
01270 
01271         result = g_try_malloc (sizeof (CRStatement));
01272 
01273         if (!result) {
01274                 cr_utils_trace_info ("Out of memory");
01275                 return NULL;
01276         }
01277 
01278         memset (result, 0, sizeof (CRStatement));
01279         result->type = AT_MEDIA_RULE_STMT;
01280 
01281         result->kind.media_rule = g_try_malloc (sizeof (CRAtMediaRule));
01282         if (!result->kind.media_rule) {
01283                 cr_utils_trace_info ("Out of memory");
01284                 g_free (result);
01285                 return NULL;
01286         }
01287         memset (result->kind.media_rule, 0, sizeof (CRAtMediaRule));
01288         result->kind.media_rule->rulesets = a_rulesets;
01289         for (cur = a_rulesets; cur; cur = cur->next) {
01290                 if (cur->type != RULESET_STMT || !cur->kind.ruleset) {
01291                         cr_utils_trace_info ("Bad parameter a_rulesets. "
01292                                              "It should be a list of "
01293                                              "correct ruleset statement only !");
01294                         goto error;
01295                 }
01296                 cur->kind.ruleset->parent_media_rule = result;
01297         }
01298 
01299         result->kind.media_rule->media_list = a_media;
01300         if (a_sheet) {
01301                 cr_statement_set_parent_sheet (result, a_sheet);
01302         }
01303 
01304         return result;
01305 
01306       error:
01307         return NULL;
01308 }
01309 
01310 /**
01311  * cr_statement_new_at_import_rule:
01312  *
01313  *@a_url: the url to connect to the get the file
01314  *to be imported.
01315  *@a_sheet: the imported parsed stylesheet.
01316  *
01317  *Creates a new instance of #CRStatment of type
01318  *#CRAtImportRule.
01319  *
01320  *Returns the newly built instance of #CRStatement.
01321  */
01322 CRStatement *
01323 cr_statement_new_at_import_rule (CRStyleSheet * a_container_sheet,
01324                                  CRString * a_url,
01325                                  GList * a_media_list,
01326                                  CRStyleSheet * a_imported_sheet)
01327 {
01328         CRStatement *result = NULL;
01329 
01330         result = g_try_malloc (sizeof (CRStatement));
01331 
01332         if (!result) {
01333                 cr_utils_trace_info ("Out of memory");
01334                 return NULL;
01335         }
01336 
01337         memset (result, 0, sizeof (CRStatement));
01338         result->type = AT_IMPORT_RULE_STMT;
01339 
01340         result->kind.import_rule = g_try_malloc (sizeof (CRAtImportRule));
01341 
01342         if (!result->kind.import_rule) {
01343                 cr_utils_trace_info ("Out of memory");
01344                 g_free (result);
01345                 return NULL;
01346         }
01347 
01348         memset (result->kind.import_rule, 0, sizeof (CRAtImportRule));
01349         result->kind.import_rule->url = a_url;
01350         result->kind.import_rule->media_list = a_media_list;
01351         result->kind.import_rule->sheet = a_imported_sheet;
01352         if (a_container_sheet)
01353                 cr_statement_set_parent_sheet (result, a_container_sheet);
01354 
01355         return result;
01356 }
01357 
01358 /**
01359  * cr_statement_at_import_rule_parse_from_buf:
01360  *
01361  *@a_buf: the buffer to parse.
01362  *@a_encoding: the encoding of a_buf.
01363  *
01364  *Parses a buffer that contains an "\@import" rule and
01365  *instanciate a #CRStatement of type AT_IMPORT_RULE_STMT
01366  *
01367  *Returns the newly built instance of #CRStatement in case of 
01368  *a successful parsing, NULL otherwise.
01369  */
01370 CRStatement *
01371 cr_statement_at_import_rule_parse_from_buf (const guchar * a_buf,
01372                                             enum CREncoding a_encoding)
01373 {
01374         enum CRStatus status = CR_OK;
01375         CRParser *parser = NULL;
01376         CRStatement *result = NULL;
01377         GList *media_list = NULL;
01378         CRString *import_string = NULL;
01379         CRParsingLocation location = {0} ;
01380 
01381         parser = cr_parser_new_from_buf ((guchar*)a_buf, strlen ((const char *) a_buf),
01382                                          a_encoding, FALSE);
01383         if (!parser) {
01384                 cr_utils_trace_info ("Instantiation of parser failed.");
01385                 goto cleanup;
01386         }
01387 
01388         status = cr_parser_try_to_skip_spaces_and_comments (parser);
01389         if (status != CR_OK)
01390                 goto cleanup;
01391 
01392         status = cr_parser_parse_import (parser,
01393                                          &media_list, 
01394                                          &import_string,
01395                                          &location);
01396         if (status != CR_OK || !import_string)
01397                 goto cleanup;
01398 
01399         result = cr_statement_new_at_import_rule (NULL, import_string,
01400                                                   media_list, NULL);
01401         if (result) {
01402                 cr_parsing_location_copy (&result->location,
01403                                           &location) ;
01404                 import_string = NULL;
01405                 media_list = NULL;
01406         }
01407 
01408  cleanup:
01409         if (parser) {
01410                 cr_parser_destroy (parser);
01411                 parser = NULL;
01412         }
01413         if (media_list) {
01414                 for (; media_list;
01415                      media_list = g_list_next (media_list)) {
01416                         if (media_list->data) {
01417                                 cr_string_destroy ((CRString*)media_list->data);
01418                                 media_list->data = NULL;
01419                         }
01420                 }
01421                 g_list_free (media_list);
01422                 media_list = NULL;
01423         }
01424         if (import_string) {
01425                 cr_string_destroy (import_string);
01426                 import_string = NULL;
01427         }
01428 
01429         return result;
01430 }
01431 
01432 /**
01433  * cr_statement_new_at_page_rule:
01434  *
01435  *@a_decl_list: a list of instances of #CRDeclarations
01436  *which is actually the list of declarations that applies to
01437  *this page rule.
01438  *@a_selector: the page rule selector.
01439  *
01440  *Creates a new instance of #CRStatement of type
01441  *#CRAtPageRule.
01442  *
01443  *Returns the newly built instance of #CRStatement or NULL
01444  *in case of error.
01445  */
01446 CRStatement *
01447 cr_statement_new_at_page_rule (CRStyleSheet * a_sheet,
01448                                CRDeclaration * a_decl_list,
01449                                CRString * a_name, CRString * a_pseudo)
01450 {
01451         CRStatement *result = NULL;
01452 
01453         result = g_try_malloc (sizeof (CRStatement));
01454 
01455         if (!result) {
01456                 cr_utils_trace_info ("Out of memory");
01457                 return NULL;
01458         }
01459 
01460         memset (result, 0, sizeof (CRStatement));
01461         result->type = AT_PAGE_RULE_STMT;
01462 
01463         result->kind.page_rule = g_try_malloc (sizeof (CRAtPageRule));
01464 
01465         if (!result->kind.page_rule) {
01466                 cr_utils_trace_info ("Out of memory");
01467                 g_free (result);
01468                 return NULL;
01469         }
01470 
01471         memset (result->kind.page_rule, 0, sizeof (CRAtPageRule));
01472         if (a_decl_list) {
01473                 result->kind.page_rule->decl_list = a_decl_list;
01474                 cr_declaration_ref (a_decl_list);
01475         }
01476         result->kind.page_rule->name = a_name;
01477         result->kind.page_rule->pseudo = a_pseudo;
01478         if (a_sheet)
01479                 cr_statement_set_parent_sheet (result, a_sheet);
01480 
01481         return result;
01482 }
01483 
01484 /**
01485  * cr_statement_at_page_rule_parse_from_buf:
01486  *
01487  *@a_buf: the character buffer to parse.
01488  *@a_encoding: the character encoding of a_buf.
01489  *
01490  *Parses a buffer that contains an "\@page" production and,
01491  *if the parsing succeeds, builds the page statement.
01492  *
01493  *Returns the newly built at page statement in case of successful parsing,
01494  *NULL otherwise.
01495  */
01496 CRStatement *
01497 cr_statement_at_page_rule_parse_from_buf (const guchar * a_buf,
01498                                           enum CREncoding a_encoding)
01499 {
01500         enum CRStatus status = CR_OK;
01501         CRParser *parser = NULL;
01502         CRDocHandler *sac_handler = NULL;
01503         CRStatement *result = NULL;
01504         CRStatement **resultptr = NULL;
01505 
01506         g_return_val_if_fail (a_buf, NULL);
01507 
01508         parser = cr_parser_new_from_buf ((guchar*)a_buf, strlen ((const char *) a_buf),
01509                                          a_encoding, FALSE);
01510         if (!parser) {
01511                 cr_utils_trace_info ("Instantiation of the parser failed.");
01512                 goto cleanup;
01513         }
01514 
01515         sac_handler = cr_doc_handler_new ();
01516         if (!sac_handler) {
01517                 cr_utils_trace_info
01518                         ("Instantiation of the sac handler failed.");
01519                 goto cleanup;
01520         }
01521 
01522         sac_handler->start_page = parse_page_start_page_cb;
01523         sac_handler->property = parse_page_property_cb;
01524         sac_handler->end_page = parse_page_end_page_cb;
01525         sac_handler->unrecoverable_error = parse_page_unrecoverable_error_cb;
01526 
01527         status = cr_parser_set_sac_handler (parser, sac_handler);
01528         if (status != CR_OK)
01529                 goto cleanup;
01530 
01531         /*Now, invoke the parser to parse the "@page production" */
01532         cr_parser_try_to_skip_spaces_and_comments (parser);
01533         if (status != CR_OK)
01534                 goto cleanup;
01535         status = cr_parser_parse_page (parser);
01536         if (status != CR_OK)
01537                 goto cleanup;
01538 
01539         resultptr = &result;
01540         status = cr_doc_handler_get_result (sac_handler,
01541                                             (gpointer *) resultptr);
01542 
01543       cleanup:
01544 
01545         if (parser) {
01546                 cr_parser_destroy (parser);
01547                 parser = NULL;
01548                 sac_handler = NULL ;
01549         }
01550         if (sac_handler) {
01551                 cr_doc_handler_unref (sac_handler);
01552                 sac_handler = NULL;
01553         }
01554         return result;
01555 }
01556 
01557 /**
01558  * cr_statement_new_at_charset_rule:
01559  *
01560  *@a_charset: the string representing the charset.
01561  *Note that the newly built instance of #CRStatement becomes
01562  *the owner of a_charset. The caller must not free a_charset !!!.
01563  *
01564  *Creates a new instance of #CRStatement of type
01565  *#CRAtCharsetRule.
01566  *
01567  *Returns the newly built instance of #CRStatement or NULL
01568  *if an error arises.
01569  */
01570 CRStatement *
01571 cr_statement_new_at_charset_rule (CRStyleSheet * a_sheet, 
01572                                   CRString * a_charset)
01573 {
01574         CRStatement *result = NULL;
01575 
01576         g_return_val_if_fail (a_charset, NULL);
01577 
01578         result = g_try_malloc (sizeof (CRStatement));
01579 
01580         if (!result) {
01581                 cr_utils_trace_info ("Out of memory");
01582                 return NULL;
01583         }
01584 
01585         memset (result, 0, sizeof (CRStatement));
01586         result->type = AT_CHARSET_RULE_STMT;
01587 
01588         result->kind.charset_rule = g_try_malloc (sizeof (CRAtCharsetRule));
01589 
01590         if (!result->kind.charset_rule) {
01591                 cr_utils_trace_info ("Out of memory");
01592                 g_free (result);
01593                 return NULL;
01594         }
01595         memset (result->kind.charset_rule, 0, sizeof (CRAtCharsetRule));
01596         result->kind.charset_rule->charset = a_charset;
01597         cr_statement_set_parent_sheet (result, a_sheet);
01598 
01599         return result;
01600 }
01601 
01602 /**
01603  * cr_statement_at_charset_rule_parse_from_buf:
01604  *
01605  *@a_buf: the buffer to parse.
01606  *@a_encoding: the character encoding of the buffer.
01607  *
01608  *Parses a buffer that contains an '\@charset' rule and
01609  *creates an instance of #CRStatement of type AT_CHARSET_RULE_STMT.
01610  *
01611  *Returns the newly built instance of #CRStatement.
01612  */
01613 CRStatement *
01614 cr_statement_at_charset_rule_parse_from_buf (const guchar * a_buf,
01615                                              enum CREncoding a_encoding)
01616 {
01617         enum CRStatus status = CR_OK;
01618         CRParser *parser = NULL;
01619         CRStatement *result = NULL;
01620         CRString *charset = NULL;
01621 
01622         g_return_val_if_fail (a_buf, NULL);
01623 
01624         parser = cr_parser_new_from_buf ((guchar*)a_buf, strlen ((const char *) a_buf),
01625                                          a_encoding, FALSE);
01626         if (!parser) {
01627                 cr_utils_trace_info ("Instantiation of the parser failed.");
01628                 goto cleanup;
01629         }
01630 
01631         /*Now, invoke the parser to parse the "@charset production" */
01632         cr_parser_try_to_skip_spaces_and_comments (parser);
01633         if (status != CR_OK)
01634                 goto cleanup;
01635         status = cr_parser_parse_charset (parser, &charset, NULL);
01636         if (status != CR_OK || !charset)
01637                 goto cleanup;
01638 
01639         result = cr_statement_new_at_charset_rule (NULL, charset);
01640         if (result)
01641                 charset = NULL;
01642 
01643       cleanup:
01644 
01645         if (parser) {
01646                 cr_parser_destroy (parser);
01647                 parser = NULL;
01648         }
01649         if (charset) {
01650                 cr_string_destroy (charset);
01651         }
01652 
01653         return result;
01654 }
01655 
01656 /**
01657  * cr_statement_new_at_font_face_rule:
01658  *
01659  *@a_font_decls: a list of instances of #CRDeclaration. Each declaration
01660  *is actually a font declaration.
01661  *
01662  *Creates an instance of #CRStatement of type #CRAtFontFaceRule.
01663  *
01664  *Returns the newly built instance of #CRStatement.
01665  */
01666 CRStatement *
01667 cr_statement_new_at_font_face_rule (CRStyleSheet * a_sheet,
01668                                     CRDeclaration * a_font_decls)
01669 {
01670         CRStatement *result = NULL;
01671 
01672         result = g_try_malloc (sizeof (CRStatement));
01673 
01674         if (!result) {
01675                 cr_utils_trace_info ("Out of memory");
01676                 return NULL;
01677         }
01678         memset (result, 0, sizeof (CRStatement));
01679         result->type = AT_FONT_FACE_RULE_STMT;
01680 
01681         result->kind.font_face_rule = g_try_malloc
01682                 (sizeof (CRAtFontFaceRule));
01683 
01684         if (!result->kind.font_face_rule) {
01685                 cr_utils_trace_info ("Out of memory");
01686                 g_free (result);
01687                 return NULL;
01688         }
01689         memset (result->kind.font_face_rule, 0, sizeof (CRAtFontFaceRule));
01690 
01691         result->kind.font_face_rule->decl_list = a_font_decls;
01692         if (a_sheet)
01693                 cr_statement_set_parent_sheet (result, a_sheet);
01694 
01695         return result;
01696 }
01697 
01698 /**
01699  * cr_statement_font_face_rule_parse_from_buf:
01700  *
01701  *
01702  *@a_buf: the buffer to parse.
01703  *@a_encoding: the character encoding of a_buf.
01704  *
01705  *Parses a buffer that contains an "\@font-face" rule and builds
01706  *an instance of #CRStatement of type AT_FONT_FACE_RULE_STMT out of it.
01707  *
01708  *Returns the newly built instance of #CRStatement in case of successufull
01709  *parsing, NULL otherwise.
01710  */
01711 CRStatement *
01712 cr_statement_font_face_rule_parse_from_buf (const guchar * a_buf,
01713                                             enum CREncoding a_encoding)
01714 {
01715         CRStatement *result = NULL;
01716         CRStatement **resultptr = NULL;
01717         CRParser *parser = NULL;
01718         CRDocHandler *sac_handler = NULL;
01719         enum CRStatus status = CR_OK;
01720 
01721         parser = cr_parser_new_from_buf ((guchar*)a_buf, strlen ((const char *) a_buf),
01722                                          a_encoding, FALSE);
01723         if (!parser)
01724                 goto cleanup;
01725 
01726         sac_handler = cr_doc_handler_new ();
01727         if (!sac_handler)
01728                 goto cleanup;
01729 
01730         /*
01731          *set sac callbacks here
01732          */
01733         sac_handler->start_font_face = parse_font_face_start_font_face_cb;
01734         sac_handler->property = parse_font_face_property_cb;
01735         sac_handler->end_font_face = parse_font_face_end_font_face_cb;
01736         sac_handler->unrecoverable_error =
01737                 parse_font_face_unrecoverable_error_cb;
01738 
01739         status = cr_parser_set_sac_handler (parser, sac_handler);
01740         if (status != CR_OK)
01741                 goto cleanup;
01742 
01743         /*
01744          *cleanup spaces of comment that may be there before the real
01745          *"@font-face" thing.
01746          */
01747         status = cr_parser_try_to_skip_spaces_and_comments (parser);
01748         if (status != CR_OK)
01749                 goto cleanup;
01750 
01751         status = cr_parser_parse_font_face (parser);
01752         if (status != CR_OK)
01753                 goto cleanup;
01754 
01755         resultptr = &result;
01756         status = cr_doc_handler_get_result (sac_handler,
01757                                             (gpointer *) resultptr);
01758         if (status != CR_OK || !result)
01759                 goto cleanup;
01760 
01761       cleanup:
01762         if (parser) {
01763                 cr_parser_destroy (parser);
01764                 parser = NULL;
01765                 sac_handler = NULL ;
01766         }
01767         if (sac_handler) {
01768                 cr_doc_handler_unref (sac_handler);
01769                 sac_handler = NULL;
01770         }
01771         return result;
01772 }
01773 
01774 /**
01775  * cr_statement_set_parent_sheet:
01776  *
01777  *@a_this: the current instance of #CRStatement.
01778  *@a_sheet: the sheet that contains the current statement.
01779  *
01780  *Sets the container stylesheet.
01781  *
01782  *Returns CR_OK upon successful completion, an error code otherwise.
01783  */
01784 enum CRStatus
01785 cr_statement_set_parent_sheet (CRStatement * a_this, CRStyleSheet * a_sheet)
01786 {
01787         g_return_val_if_fail (a_this, CR_BAD_PARAM_ERROR);
01788         a_this->parent_sheet = a_sheet;
01789         return CR_OK;
01790 }
01791 
01792 /**
01793  * cr_statement_get_parent_sheet:
01794  *
01795  *@a_this: the current #CRStatement.
01796  *@a_sheet: out parameter. A pointer to the sheets that
01797  *
01798  *Gets the sheets that contains the current statement.
01799  *
01800  *Returns CR_OK upon successful completion, an error code otherwise.
01801  */
01802 enum CRStatus
01803 cr_statement_get_parent_sheet (CRStatement * a_this, CRStyleSheet ** a_sheet)
01804 {
01805         g_return_val_if_fail (a_this && a_sheet, CR_BAD_PARAM_ERROR);
01806         *a_sheet = a_this->parent_sheet;
01807         return CR_OK;
01808 }
01809 
01810 /**
01811  * cr_statement_append:
01812  *
01813  *@a_this: the current instance of the statement list.
01814  *@a_new: a_new the new instance of #CRStatement to append.
01815  *
01816  *Appends a new statement to the statement list.
01817  *
01818  *Returns the new list statement list, or NULL in cas of failure.
01819  */
01820 CRStatement *
01821 cr_statement_append (CRStatement * a_this, CRStatement * a_new)
01822 {
01823         CRStatement *cur = NULL;
01824 
01825         g_return_val_if_fail (a_new, NULL);
01826 
01827         if (!a_this) {
01828                 return a_new;
01829         }
01830 
01831         /*walk forward in the current list to find the tail list element */
01832         for (cur = a_this; cur && cur->next; cur = cur->next) ;
01833 
01834         cur->next = a_new;
01835         a_new->prev = cur;
01836 
01837         return a_this;
01838 }
01839 
01840 /**
01841  * cr_statement_prepend:
01842  *
01843  *@a_this: the current instance of #CRStatement.
01844  *@a_new: the new statement to prepend.
01845  *
01846  *Prepends the an instance of #CRStatement to
01847  *the current statement list.
01848  *
01849  *Returns the new list with the new statement prepended,
01850  *or NULL in case of an error.
01851  */
01852 CRStatement *
01853 cr_statement_prepend (CRStatement * a_this, CRStatement * a_new)
01854 {
01855         CRStatement *cur = NULL;
01856 
01857         g_return_val_if_fail (a_new, NULL);
01858 
01859         if (!a_this)
01860                 return a_new;
01861 
01862         a_new->next = a_this;
01863         a_this->prev = a_new;
01864 
01865         /*walk backward in the prepended list to find the head list element */
01866         for (cur = a_new; cur && cur->prev; cur = cur->prev) ;
01867 
01868         return cur;
01869 }
01870 
01871 /**
01872  * cr_statement_unlink:
01873  *
01874  *@a_this: the current statements list.
01875  *@a_to_unlink: the statement to unlink from the list.
01876  *
01877  *Unlinks a statement from the statements list.
01878  *
01879  *Returns the new list where a_to_unlink has been unlinked
01880  *from, or NULL in case of error.
01881  */
01882 CRStatement *
01883 cr_statement_unlink (CRStatement * a_stmt)
01884 {
01885         CRStatement *result = a_stmt;
01886 
01887         g_return_val_if_fail (result, NULL);
01888 
01889         /**
01890          *Some sanity checks first
01891          */
01892         if (a_stmt->next) {
01893                 g_return_val_if_fail (a_stmt->next->prev == a_stmt, NULL);
01894         }
01895         if (a_stmt->prev) {
01896                 g_return_val_if_fail (a_stmt->prev->next == a_stmt, NULL);
01897         }
01898 
01899         /**
01900          *Now, the real unlinking job.
01901          */
01902         if (a_stmt->next) {
01903                 a_stmt->next->prev = a_stmt->prev;
01904         }
01905         if (a_stmt->prev) {
01906                 a_stmt->prev->next = a_stmt->next;
01907         }
01908 
01909         if (a_stmt->parent_sheet
01910             && a_stmt->parent_sheet->statements == a_stmt) {
01911                 a_stmt->parent_sheet->statements =
01912                         a_stmt->parent_sheet->statements->next;
01913         }
01914 
01915         a_stmt->next = NULL;
01916         a_stmt->prev = NULL;
01917         a_stmt->parent_sheet = NULL;
01918 
01919         return result;
01920 }
01921 
01922 /**
01923  * cr_statement_nr_rules:
01924  *
01925  *@a_this: the current instance of #CRStatement.
01926  *
01927  *Gets the number of rules in the statement list;
01928  *
01929  *Returns number of rules in the statement list.
01930  */
01931 gint
01932 cr_statement_nr_rules (CRStatement const * a_this)
01933 {
01934         CRStatement const *cur = NULL;
01935         int nr = 0;
01936 
01937         g_return_val_if_fail (a_this, -1);
01938 
01939         for (cur = a_this; cur; cur = cur->next)
01940                 nr++;
01941         return nr;
01942 }
01943 
01944 /**
01945  * cr_statement_get_from_list:
01946  *
01947  *@a_this: the current instance of #CRStatement.
01948  *@itemnr: the index into the statement list.
01949  *
01950  *Use an index to get a CRStatement from the statement list.
01951  *
01952  *Returns CRStatement at position itemnr, if itemnr > number of statements - 1,
01953  *it will return NULL.
01954  */
01955 CRStatement *
01956 cr_statement_get_from_list (CRStatement * a_this, int itemnr)
01957 {
01958         CRStatement *cur = NULL;
01959         int nr = 0;
01960 
01961         g_return_val_if_fail (a_this, NULL);
01962 
01963         for (cur = a_this; cur; cur = cur->next)
01964                 if (nr++ == itemnr)
01965                         return cur;
01966         return NULL;
01967 }
01968 
01969 /**
01970  * cr_statement_ruleset_set_sel_list:
01971  *
01972  *@a_this: the current ruleset statement.
01973  *@a_sel_list: the selector list to set. Note
01974  *that this function increments the ref count of a_sel_list.
01975  *The sel list will be destroyed at the destruction of the
01976  *current instance of #CRStatement.
01977  *
01978  *Sets a selector list to a ruleset statement.
01979  *
01980  *Returns CR_OK upon successful completion, an error code otherwise.
01981  */
01982 enum CRStatus
01983 cr_statement_ruleset_set_sel_list (CRStatement * a_this,
01984                                    CRSelector * a_sel_list)
01985 {
01986         g_return_val_if_fail (a_this && a_this->type == RULESET_STMT,
01987                               CR_BAD_PARAM_ERROR);
01988 
01989         if (a_this->kind.ruleset->sel_list)
01990                 cr_selector_unref (a_this->kind.ruleset->sel_list);
01991 
01992         a_this->kind.ruleset->sel_list = a_sel_list;
01993 
01994         if (a_sel_list)
01995                 cr_selector_ref (a_sel_list);
01996 
01997         return CR_OK;
01998 }
01999 
02000 /**
02001  * cr_statement_ruleset_get_declarations:
02002  *
02003  *@a_this: the current instance of #CRStatement.
02004  *@a_decl_list: out parameter. A pointer to the the returned
02005  *list of declaration. Must not be NULL.
02006  *
02007  *Gets a pointer to the list of declaration contained
02008  *in the ruleset statement.
02009  *
02010  *Returns CR_OK upon successful completion, an error code if something
02011  *bad happened.
02012  */
02013 enum CRStatus
02014 cr_statement_ruleset_get_declarations (CRStatement * a_this,
02015                                        CRDeclaration ** a_decl_list)
02016 {
02017         g_return_val_if_fail (a_this
02018                               && a_this->type == RULESET_STMT
02019                               && a_this->kind.ruleset
02020                               && a_decl_list, CR_BAD_PARAM_ERROR);
02021 
02022         *a_decl_list = a_this->kind.ruleset->decl_list;
02023 
02024         return CR_OK;
02025 }
02026 
02027 /**
02028  * cr_statement_ruleset_get_sel_list:
02029  *
02030  *@a_this: the current ruleset statement.
02031  *@a_list: out parameter. The returned selector list,
02032  *if and only if the function returned CR_OK.
02033  *
02034  *Gets a pointer to the selector list contained in
02035  *the current ruleset statement.
02036  *
02037  *Returns CR_OK upon successful completion, an error code otherwise.
02038  */
02039 enum CRStatus
02040 cr_statement_ruleset_get_sel_list (CRStatement const * a_this, CRSelector ** a_list)
02041 {
02042         g_return_val_if_fail (a_this && a_this->type == RULESET_STMT
02043                               && a_this->kind.ruleset, CR_BAD_PARAM_ERROR);
02044 
02045         *a_list = a_this->kind.ruleset->sel_list;
02046 
02047         return CR_OK;
02048 }
02049 
02050 /**
02051  * cr_statement_ruleset_set_decl_list:
02052  *
02053  *@a_this: the current ruleset statement.
02054  *@a_list: the declaration list to be added to the current
02055  *ruleset statement.
02056  *
02057  *Sets a declaration list to the current ruleset statement.
02058  *
02059  *Returns CR_OK upon successful completion, an error code otherwise.
02060  */
02061 enum CRStatus
02062 cr_statement_ruleset_set_decl_list (CRStatement * a_this,
02063                                     CRDeclaration * a_list)
02064 {
02065         g_return_val_if_fail (a_this && a_this->type == RULESET_STMT
02066                               && a_this->kind.ruleset, CR_BAD_PARAM_ERROR);
02067 
02068         if (a_this->kind.ruleset->decl_list == a_list)
02069                 return CR_OK;
02070 
02071         if (a_this->kind.ruleset->sel_list) {
02072                 cr_declaration_destroy (a_this->kind.ruleset->decl_list);
02073         }
02074 
02075         a_this->kind.ruleset->sel_list = NULL;
02076 
02077         return CR_OK;
02078 }
02079 
02080 /**
02081  * cr_statement_ruleset_append_decl2:
02082  *
02083  *@a_this: the current statement.
02084  *@a_prop: the property of the declaration.
02085  *@a_value: the value of the declaration.
02086  *
02087  *Appends a declaration to the current ruleset statement.
02088  *
02089  *Returns CR_OK upon successful completion, an error code
02090  *otherwise.
02091  */
02092 enum CRStatus
02093 cr_statement_ruleset_append_decl2 (CRStatement * a_this,
02094                                    CRString * a_prop, 
02095                                    CRTerm * a_value)
02096 {
02097         CRDeclaration *new_decls = NULL;
02098 
02099         g_return_val_if_fail (a_this && a_this->type == RULESET_STMT
02100                               && a_this->kind.ruleset, CR_BAD_PARAM_ERROR);
02101 
02102         new_decls = cr_declaration_append2
02103                 (a_this->kind.ruleset->decl_list, 
02104                  a_prop, a_value);
02105         g_return_val_if_fail (new_decls, CR_ERROR);
02106         a_this->kind.ruleset->decl_list = new_decls;
02107 
02108         return CR_OK;
02109 }
02110 
02111 /**
02112  * cr_statement_ruleset_append_decl:
02113  *
02114  *Appends a declaration to the current statement.
02115  *
02116  *@a_this: the current statement.
02117  *@a_declaration: the declaration to append.
02118  *
02119  *Returns CR_OK upon sucessful completion, an error code
02120  *otherwise.
02121  */
02122 enum CRStatus
02123 cr_statement_ruleset_append_decl (CRStatement * a_this,
02124                                   CRDeclaration * a_decl)
02125 {
02126         CRDeclaration *new_decls = NULL;
02127 
02128         g_return_val_if_fail (a_this && a_this->type == RULESET_STMT
02129                               && a_this->kind.ruleset, CR_BAD_PARAM_ERROR);
02130 
02131         new_decls = cr_declaration_append
02132                 (a_this->kind.ruleset->decl_list, a_decl);
02133         g_return_val_if_fail (new_decls, CR_ERROR);
02134         a_this->kind.ruleset->decl_list = new_decls;
02135 
02136         return CR_OK;
02137 }
02138 
02139 /**
02140  * cr_statement_at_import_rule_set_imported_sheet:
02141  *
02142  *Sets a stylesheet to the current \@import rule.
02143  *@a_this: the current \@import rule.
02144  *@a_sheet: the stylesheet. The stylesheet is owned
02145  *by the current instance of #CRStatement, that is, the 
02146  *stylesheet will be destroyed when the current instance
02147  *of #CRStatement is destroyed.
02148  *
02149  *Returns CR_OK upon successful completion, an error code otherwise.
02150  */
02151 enum CRStatus
02152 cr_statement_at_import_rule_set_imported_sheet (CRStatement * a_this,
02153                                                 CRStyleSheet * a_sheet)
02154 {
02155         g_return_val_if_fail (a_this
02156                               && a_this->type == AT_IMPORT_RULE_STMT
02157                               && a_this->kind.import_rule,
02158                               CR_BAD_PARAM_ERROR);
02159 
02160         a_this->kind.import_rule->sheet = a_sheet;
02161 
02162         return CR_OK;
02163 }
02164 
02165 /**
02166  * cr_statement_at_import_rule_get_imported_sheet:
02167  *
02168  *@a_this: the current \@import rule statement.
02169  *@a_sheet: out parameter. The returned stylesheet if and
02170  *only if the function returns CR_OK.
02171  *
02172  *Gets the stylesheet contained by the \@import rule statement.
02173  *Returns CR_OK upon sucessful completion, an error code otherwise.
02174  */
02175 enum CRStatus
02176 cr_statement_at_import_rule_get_imported_sheet (CRStatement * a_this,
02177                                                 CRStyleSheet ** a_sheet)
02178 {
02179         g_return_val_if_fail (a_this
02180                               && a_this->type == AT_IMPORT_RULE_STMT
02181                               && a_this->kind.import_rule,
02182                               CR_BAD_PARAM_ERROR);
02183         *a_sheet = a_this->kind.import_rule->sheet;
02184         return CR_OK;
02185 
02186 }
02187 
02188 /**
02189  * cr_statement_at_import_rule_set_url:
02190  *
02191  *@a_this: the current \@import rule statement.
02192  *@a_url: the url to set.
02193  *
02194  *Sets an url to the current \@import rule statement.
02195  *
02196  *Returns CR_OK upon successful completion, an error code otherwise.
02197  */
02198 enum CRStatus
02199 cr_statement_at_import_rule_set_url (CRStatement * a_this, 
02200                                      CRString * a_url)
02201 {
02202         g_return_val_if_fail (a_this
02203                               && a_this->type == AT_IMPORT_RULE_STMT
02204                               && a_this->kind.import_rule,
02205                               CR_BAD_PARAM_ERROR);
02206 
02207         if (a_this->kind.import_rule->url) {
02208                 cr_string_destroy (a_this->kind.import_rule->url);
02209         }
02210 
02211         a_this->kind.import_rule->url = a_url;
02212 
02213         return CR_OK;
02214 }
02215 
02216 /**
02217  * cr_statement_at_import_rule_get_url:
02218  *
02219  *@a_this: the current \@import rule statement.
02220  *@a_url: out parameter. The returned url if
02221  *and only if the function returned CR_OK.
02222  *
02223  *Gets the url of the \@import rule statement.
02224  *Returns CR_OK upon successful completion, an error code otherwise.
02225  */
02226 enum CRStatus
02227 cr_statement_at_import_rule_get_url (CRStatement const * a_this,
02228                                      CRString ** a_url)
02229 {
02230         g_return_val_if_fail (a_this
02231                               && a_this->type == AT_IMPORT_RULE_STMT
02232                               && a_this->kind.import_rule,
02233                               CR_BAD_PARAM_ERROR);
02234 
02235         *a_url = a_this->kind.import_rule->url;
02236 
02237         return CR_OK;
02238 }
02239 
02240 /**
02241  * cr_statement_at_media_nr_rules:
02242  *
02243  *@a_this: the current instance of #CRStatement.
02244  *
02245  *Returns the number of rules in the media rule;
02246  */
02247 int
02248 cr_statement_at_media_nr_rules (CRStatement const * a_this)
02249 {
02250         g_return_val_if_fail (a_this
02251                               && a_this->type == AT_MEDIA_RULE_STMT
02252                               && a_this->kind.media_rule, CR_BAD_PARAM_ERROR);
02253 
02254         return cr_statement_nr_rules (a_this->kind.media_rule->rulesets);
02255 }
02256 
02257 /**
02258  * cr_statement_at_media_get_from_list:
02259  *
02260  *@a_this: the current instance of #CRStatement.
02261  *@itemnr: the index into the media rule list of rules.
02262  *
02263  *Use an index to get a CRStatement from the media rule list of rules.
02264  *
02265  *Returns CRStatement at position itemnr, if itemnr > number of rules - 1,
02266  *it will return NULL.
02267  */
02268 CRStatement *
02269 cr_statement_at_media_get_from_list (CRStatement * a_this, int itemnr)
02270 {
02271         g_return_val_if_fail (a_this
02272                               && a_this->type == AT_MEDIA_RULE_STMT
02273                               && a_this->kind.media_rule, NULL);
02274 
02275         return cr_statement_get_from_list (a_this->kind.media_rule->rulesets,
02276                                            itemnr);
02277 }
02278 
02279 /**
02280  * cr_statement_at_page_rule_set_declarations:
02281  *
02282  *@a_this: the current \@page rule statement.
02283  *@a_decl_list: the declaration list to add. Will be freed
02284  *by the current instance of #CRStatement when it is destroyed.
02285  *
02286  *Sets a declaration list to the current \@page rule statement.
02287  *
02288  *Returns CR_OK upon successful completion, an error code otherwise.
02289  */
02290 enum CRStatus
02291 cr_statement_at_page_rule_set_declarations (CRStatement * a_this,
02292                                             CRDeclaration * a_decl_list)
02293 {
02294         g_return_val_if_fail (a_this
02295                               && a_this->type == AT_PAGE_RULE_STMT
02296                               && a_this->kind.page_rule, CR_BAD_PARAM_ERROR);
02297 
02298         if (a_this->kind.page_rule->decl_list) {
02299                 cr_declaration_unref (a_this->kind.page_rule->decl_list);
02300         }
02301 
02302         a_this->kind.page_rule->decl_list = a_decl_list;
02303 
02304         if (a_decl_list) {
02305                 cr_declaration_ref (a_decl_list);
02306         }
02307 
02308         return CR_OK;
02309 }
02310 
02311 /**
02312  * cr_statement_at_page_rule_get_declarations:
02313  *
02314  *@a_this: the current \@page rule statement.
02315  *@a_decl_list: out parameter. The returned declaration list.
02316  *
02317  *Gets the declaration list associated to the current \@page rule
02318  *statement.
02319  *
02320  *Returns CR_OK upon successful completion, an error code otherwise.
02321  */
02322 enum CRStatus
02323 cr_statement_at_page_rule_get_declarations (CRStatement * a_this,
02324                                             CRDeclaration ** a_decl_list)
02325 {
02326         g_return_val_if_fail (a_this
02327                               && a_this->type == AT_PAGE_RULE_STMT
02328                               && a_this->kind.page_rule, CR_BAD_PARAM_ERROR);
02329 
02330         *a_decl_list = a_this->kind.page_rule->decl_list;
02331 
02332         return CR_OK;
02333 }
02334 
02335 /**
02336  * cr_statement_at_charset_rule_set_charset:
02337  *
02338  *
02339  *@a_this: the current \@charset rule statement.
02340  *@a_charset: the charset to set.
02341  *
02342  *Sets the charset of the current \@charset rule statement.
02343  *
02344  *Returns CR_OK upon successful completion, an error code otherwise.
02345  */
02346 enum CRStatus
02347 cr_statement_at_charset_rule_set_charset (CRStatement * a_this,
02348                                           CRString * a_charset)
02349 {
02350         g_return_val_if_fail (a_this
02351                               && a_this->type == AT_CHARSET_RULE_STMT
02352                               && a_this->kind.charset_rule,
02353                               CR_BAD_PARAM_ERROR);
02354 
02355         if (a_this->kind.charset_rule->charset) {
02356                 cr_string_destroy (a_this->kind.charset_rule->charset);
02357         }
02358         a_this->kind.charset_rule->charset = a_charset;
02359         return CR_OK;
02360 }
02361 
02362 /**
02363  * cr_statement_at_charset_rule_get_charset:
02364  *@a_this: the current \@charset rule statement.
02365  *@a_charset: out parameter. The returned charset string if
02366  *and only if the function returned CR_OK.
02367  *
02368  *Gets the charset string associated to the current
02369  *\@charset rule statement.
02370  *
02371  * Returns CR_OK upon successful completion, an error code otherwise.
02372  */
02373 enum CRStatus
02374 cr_statement_at_charset_rule_get_charset (CRStatement const * a_this,
02375                                           CRString ** a_charset)
02376 {
02377         g_return_val_if_fail (a_this
02378                               && a_this->type == AT_CHARSET_RULE_STMT
02379                               && a_this->kind.charset_rule,
02380                               CR_BAD_PARAM_ERROR);
02381 
02382         *a_charset = a_this->kind.charset_rule->charset;
02383 
02384         return CR_OK;
02385 }
02386 
02387 /**
02388  * cr_statement_at_font_face_rule_set_decls:
02389  *
02390  *@a_this: the current \@font-face rule statement.
02391  *@a_decls: the declarations list to set.
02392  *
02393  *Sets a declaration list to the current \@font-face rule statement.
02394  *
02395  *Returns CR_OK upon successful completion, an error code otherwise.
02396  */
02397 enum CRStatus
02398 cr_statement_at_font_face_rule_set_decls (CRStatement * a_this,
02399                                           CRDeclaration * a_decls)
02400 {
02401         g_return_val_if_fail (a_this
02402                               && a_this->type == AT_FONT_FACE_RULE_STMT
02403                               && a_this->kind.font_face_rule,
02404                               CR_BAD_PARAM_ERROR);
02405 
02406         if (a_this->kind.font_face_rule->decl_list) {
02407                 cr_declaration_unref (a_this->kind.font_face_rule->decl_list);
02408         }
02409 
02410         a_this->kind.font_face_rule->decl_list = a_decls;
02411         cr_declaration_ref (a_decls);
02412 
02413         return CR_OK;
02414 }
02415 
02416 /**
02417  * cr_statement_at_font_face_rule_get_decls:
02418  *
02419  *@a_this: the current \@font-face rule statement.
02420  *@a_decls: out parameter. The returned declaration list if
02421  *and only if this function returns CR_OK.
02422  *
02423  *Gets the declaration list associated to the current instance
02424  *of \@font-face rule statement.
02425  *
02426  *Returns CR_OK upon successful completion, an error code otherwise.
02427  */
02428 enum CRStatus
02429 cr_statement_at_font_face_rule_get_decls (CRStatement * a_this,
02430                                           CRDeclaration ** a_decls)
02431 {
02432         g_return_val_if_fail (a_this
02433                               && a_this->type == AT_FONT_FACE_RULE_STMT
02434                               && a_this->kind.font_face_rule,
02435                               CR_BAD_PARAM_ERROR);
02436 
02437         *a_decls = a_this->kind.font_face_rule->decl_list;
02438 
02439         return CR_OK;
02440 }
02441 
02442 /**
02443  * cr_statement_at_font_face_rule_add_decl:
02444  *
02445  *@a_this: the current \@font-face rule statement.
02446  *@a_prop: the property of the declaration.
02447  *@a_value: the value of the declaration.
02448  *
02449  *Adds a declaration to the current \@font-face rule
02450  *statement.
02451  *
02452  *Returns CR_OK upon successful completion, an error code otherwise.
02453  */
02454 enum CRStatus
02455 cr_statement_at_font_face_rule_add_decl (CRStatement * a_this,
02456                                          CRString * a_prop, CRTerm * a_value)
02457 {
02458         CRDeclaration *decls = NULL;
02459 
02460         g_return_val_if_fail (a_this
02461                               && a_this->type == AT_FONT_FACE_RULE_STMT
02462                               && a_this->kind.font_face_rule,
02463                               CR_BAD_PARAM_ERROR);
02464 
02465         decls = cr_declaration_append2
02466                 (a_this->kind.font_face_rule->decl_list, 
02467                  a_prop, a_value);
02468 
02469         g_return_val_if_fail (decls, CR_ERROR);
02470 
02471         if (a_this->kind.font_face_rule->decl_list == NULL)
02472                 cr_declaration_ref (decls);
02473 
02474         a_this->kind.font_face_rule->decl_list = decls;
02475 
02476         return CR_OK;
02477 }
02478 
02479 
02480 /**
02481  * cr_statement_to_string:
02482  *
02483  *@a_this: the current statement to serialize
02484  *@a_indent: the number of white space of indentation.
02485  *
02486  *Serializes a css statement into a string
02487  *
02488  *Returns the serialized statement. Must be freed by the caller
02489  *using g_free().
02490  */
02491 gchar *
02492 cr_statement_to_string (CRStatement const * a_this, gulong a_indent)
02493 {
02494         gchar *str = NULL ;
02495 
02496         if (!a_this)
02497                 return NULL;
02498 
02499         switch (a_this->type) {
02500         case RULESET_STMT:
02501                 str = cr_statement_ruleset_to_string 
02502                         (a_this, a_indent);
02503                 break;
02504 
02505         case AT_FONT_FACE_RULE_STMT:
02506                 str = cr_statement_font_face_rule_to_string 
02507                         (a_this, a_indent) ;
02508                 break;
02509 
02510         case AT_CHARSET_RULE_STMT:
02511                 str = cr_statement_charset_to_string
02512                         (a_this, a_indent);                
02513                 break;
02514 
02515         case AT_PAGE_RULE_STMT:
02516                 str = cr_statement_at_page_rule_to_string
02517                         (a_this, a_indent);
02518                 break;
02519 
02520         case AT_MEDIA_RULE_STMT:
02521                 str = cr_statement_media_rule_to_string
02522                         (a_this, a_indent);
02523                 break;
02524 
02525         case AT_IMPORT_RULE_STMT:
02526                 str = cr_statement_import_rule_to_string
02527                         (a_this, a_indent);
02528                 break;
02529 
02530         default:
02531                 cr_utils_trace_info ("Statement unrecognized");
02532                 break;
02533         }
02534         return str ;
02535 }
02536 
02537 gchar*
02538 cr_statement_list_to_string (CRStatement const *a_this, gulong a_indent)
02539 {
02540         CRStatement const *cur_stmt = NULL ;
02541         GString *stringue = NULL ;
02542         gchar *str = NULL ;
02543 
02544         g_return_val_if_fail (a_this, NULL) ;
02545 
02546         stringue = g_string_new (NULL) ;
02547         if (!stringue) {
02548                 cr_utils_trace_info ("Out of memory") ;
02549                 return NULL ;
02550         }
02551         for (cur_stmt = a_this ; cur_stmt;
02552              cur_stmt = cur_stmt->next) {
02553                 str = cr_statement_to_string (cur_stmt, a_indent) ;
02554                 if (str) {
02555                         if (!cur_stmt->prev) {
02556                                 g_string_append (stringue, str) ;
02557                         } else {
02558                                 g_string_append_printf 
02559                                         (stringue, "\n%s", str) ;
02560                         }
02561                         g_free (str) ;
02562                         str = NULL ;
02563                 }                
02564         }
02565         str = stringue->str ;
02566         g_string_free (stringue, FALSE) ;
02567         return str ;
02568 }
02569 
02570 /**
02571  * cr_statement_dump:
02572  *
02573  *@a_this: the current css2 statement.
02574  *@a_fp: the destination file pointer.
02575  *@a_indent: the number of white space indentation characters.
02576  *
02577  *Dumps the css2 statement to a file.
02578  */
02579 void
02580 cr_statement_dump (CRStatement const * a_this, FILE * a_fp, gulong a_indent)
02581 {
02582         gchar *str = NULL ;
02583 
02584         if (!a_this)
02585                 return;
02586 
02587         str = cr_statement_to_string (a_this, a_indent) ;
02588         if (str) {
02589                 fprintf (a_fp, "%s",str) ;
02590                 g_free (str) ;
02591                 str = NULL ;
02592         }
02593 }
02594 
02595 /**
02596  * cr_statement_dump_ruleset:
02597  *
02598  *@a_this: the current instance of #CRStatement.
02599  *@a_fp: the destination file pointer.
02600  *@a_indent: the number of indentation white spaces to add.
02601  *
02602  *Dumps a ruleset statement to a file.
02603  */
02604 void
02605 cr_statement_dump_ruleset (CRStatement const * a_this, FILE * a_fp, glong a_indent)
02606 {
02607         gchar *str = NULL;
02608 
02609         g_return_if_fail (a_fp && a_this);
02610         str = cr_statement_ruleset_to_string (a_this, a_indent);
02611         if (str) {
02612                 fprintf (a_fp, "%s", str);
02613                 g_free (str);
02614                 str = NULL;
02615         }
02616 }
02617 
02618 /**
02619  * cr_statement_dump_font_face_rule:
02620  *
02621  *@a_this: the current instance of font face rule statement.
02622  *@a_fp: the destination file pointer.
02623  *@a_indent: the number of white space indentation.
02624  *
02625  *Dumps a font face rule statement to a file.
02626  */
02627 void
02628 cr_statement_dump_font_face_rule (CRStatement const * a_this, FILE * a_fp,
02629                                   glong a_indent)
02630 {
02631         gchar *str = NULL ;
02632         g_return_if_fail (a_this 
02633                           && a_this->type == AT_FONT_FACE_RULE_STMT);
02634 
02635         str = cr_statement_font_face_rule_to_string (a_this,
02636                                                      a_indent) ;
02637         if (str) {
02638                 fprintf (a_fp, "%s", str) ;
02639                 g_free (str) ;
02640                 str = NULL ;
02641         }
02642 }
02643 
02644 /**
02645  * cr_statement_dump_charset:
02646  *
02647  *@a_this: the current instance of the \@charset rule statement.
02648  *@a_fp: the destination file pointer.
02649  *@a_indent: the number of indentation white spaces.
02650  *
02651  *Dumps an \@charset rule statement to a file.
02652  */
02653 void
02654 cr_statement_dump_charset (CRStatement const * a_this, FILE * a_fp, gulong a_indent)
02655 {
02656         gchar *str = NULL;
02657 
02658         g_return_if_fail (a_this && a_this->type == AT_CHARSET_RULE_STMT);
02659 
02660         str = cr_statement_charset_to_string (a_this,
02661                                               a_indent) ;
02662         if (str) {
02663                 fprintf (a_fp, "%s", str) ;
02664                 g_free (str) ;
02665                 str = NULL ;
02666         }
02667 }
02668 
02669 
02670 /**
02671  * cr_statement_dump_page:
02672  *
02673  *@a_this: the statement to dump on stdout.
02674  *@a_fp: the destination file pointer.
02675  *@a_indent: the number of indentation white spaces.
02676  *
02677  *Dumps an \@page rule statement on stdout.
02678  */
02679 void
02680 cr_statement_dump_page (CRStatement const * a_this, FILE * a_fp, gulong a_indent)
02681 {
02682         gchar *str = NULL;
02683 
02684         g_return_if_fail (a_this
02685                           && a_this->type == AT_PAGE_RULE_STMT
02686                           && a_this->kind.page_rule);
02687 
02688         str = cr_statement_at_page_rule_to_string (a_this, a_indent) ;
02689         if (str) {
02690                 fprintf (a_fp, "%s", str);
02691                 g_free (str) ;
02692                 str = NULL ; 
02693         }
02694 }
02695 
02696 
02697 /**
02698  * cr_statement_dump_media_rule:
02699  *
02700  *@a_this: the statement to dump.
02701  *@a_fp: the destination file pointer
02702  *@a_indent: the number of white spaces indentation.
02703  *
02704  *Dumps an \@media rule statement to a file.
02705  */
02706 void
02707 cr_statement_dump_media_rule (CRStatement const * a_this,
02708                               FILE * a_fp,
02709                               gulong a_indent)
02710 {
02711         gchar *str = NULL ;
02712         g_return_if_fail (a_this->type == AT_MEDIA_RULE_STMT);
02713 
02714         str = cr_statement_media_rule_to_string (a_this, a_indent) ;
02715         if (str) {
02716                 fprintf (a_fp, "%s", str) ;
02717                 g_free (str) ;
02718                 str = NULL ;
02719         }
02720 }
02721 
02722 /**
02723  * cr_statement_dump_import_rule:
02724  *
02725  *@a_fp: the destination file pointer.
02726  *@a_indent: the number of white space indentations.
02727  *
02728  *Dumps an \@import rule statement to a file.
02729  */
02730 void
02731 cr_statement_dump_import_rule (CRStatement const * a_this, FILE * a_fp,
02732                                gulong a_indent)
02733 {
02734         gchar *str = NULL ;
02735         g_return_if_fail (a_this
02736                           && a_this->type == AT_IMPORT_RULE_STMT
02737                           && a_fp
02738                           && a_this->kind.import_rule);
02739 
02740         str = cr_statement_import_rule_to_string (a_this, a_indent) ;
02741         if (str) {
02742                 fprintf (a_fp, "%s", str) ;
02743                 g_free (str) ;
02744                 str = NULL ;
02745         }
02746 }
02747 
02748 /**
02749  * cr_statement_destroy:
02750  *
02751  * @a_this: the current instance of #CRStatement.
02752  *
02753  *Destructor of #CRStatement.
02754  */
02755 void
02756 cr_statement_destroy (CRStatement * a_this)
02757 {
02758         CRStatement *cur = NULL;
02759 
02760         g_return_if_fail (a_this);
02761 
02762         /*go get the tail of the list */
02763         for (cur = a_this; cur && cur->next; cur = cur->next) {
02764                 cr_statement_clear (cur);
02765         }
02766 
02767         if (cur)
02768                 cr_statement_clear (cur);
02769 
02770         if (cur->prev == NULL) {
02771                 g_free (a_this);
02772                 return;
02773         }
02774 
02775         /*walk backward and free next element */
02776         for (cur = cur->prev; cur && cur->prev; cur = cur->prev) {
02777                 if (cur->next) {
02778                         g_free (cur->next);
02779                         cur->next = NULL;
02780                 }
02781         }
02782 
02783         if (!cur)
02784                 return;
02785 
02786         /*free the one remaining list */
02787         if (cur->next) {
02788                 g_free (cur->next);
02789                 cur->next = NULL;
02790         }
02791 
02792         g_free (cur);
02793         cur = NULL;
02794 }