Main Page | Alphabetical List | Data Structures | File List | Data Fields | Globals | Related Pages

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

Generated on Sat Mar 20 02:38:44 2004 for Libcroco by doxygen 1.3.5