(root)/
gettext-0.22.4/
libtextstyle/
lib/
libcroco/
cr-statement.c
       1  /* -*- Mode: C; indent-tabs-mode: nil; c-basic-offset: 8 -*- */
       2  
       3  /* libcroco - Library for parsing and applying CSS
       4   * Copyright (C) 2006-2019 Free Software Foundation, Inc.
       5   *
       6   * This file is not part of the GNU gettext program, but is used with
       7   * GNU gettext.
       8   *
       9   * The original copyright notice is as follows:
      10   */
      11  
      12  /*
      13   * This file is part of The Croco Library
      14   *
      15   * Copyright (C) 2003-2004 Dodji Seketeli.  All Rights Reserved.
      16   *
      17   * This program is free software; you can redistribute it and/or
      18   * modify it under the terms of version 2.1 of the GNU Lesser General Public
      19   * License as published by the Free Software Foundation.
      20   *
      21   * This program is distributed in the hope that it will be useful,
      22   * but WITHOUT ANY WARRANTY; without even the implied warranty of
      23   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
      24   * GNU General Public License for more details.
      25   *
      26   * You should have received a copy of the GNU Lesser General Public License
      27   * along with this program; if not, write to the Free Software
      28   * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
      29   * USA
      30   *
      31   * Author: Dodji Seketeli.
      32   */
      33  
      34  #include <config.h>
      35  #include <string.h>
      36  #include "cr-statement.h"
      37  #include "cr-parser.h"
      38  
      39  /**
      40   *@file
      41   *Definition of the #CRStatement class.
      42   */
      43  
      44  #define DECLARATION_INDENT_NB 2
      45  
      46  static void cr_statement_clear (CRStatement * a_this);
      47  
      48  static void  
      49  parse_font_face_start_font_face_cb (CRDocHandler * a_this,
      50                                      CRParsingLocation *a_location)
      51  {
      52          CRStatement *stmt = NULL;
      53          enum CRStatus status = CR_OK;
      54  
      55          stmt = cr_statement_new_at_font_face_rule (NULL, NULL);
      56          g_return_if_fail (stmt);
      57  
      58          status = cr_doc_handler_set_ctxt (a_this, stmt);
      59          g_return_if_fail (status == CR_OK);
      60  }
      61  
      62  static void
      63  parse_font_face_unrecoverable_error_cb (CRDocHandler * a_this)
      64  {
      65          CRStatement *stmt = NULL;
      66  	CRStatement **stmtptr = NULL;
      67          enum CRStatus status = CR_OK;
      68  
      69          g_return_if_fail (a_this);
      70  
      71  	stmtptr = &stmt;
      72          status = cr_doc_handler_get_ctxt (a_this, (gpointer *) stmtptr);
      73          if (status != CR_OK) {
      74                  cr_utils_trace_info ("Couldn't get parsing context. "
      75                                       "This may lead to some memory leaks.");
      76                  return;
      77          }
      78          if (stmt) {
      79                  cr_statement_destroy (stmt);
      80                  cr_doc_handler_set_ctxt (a_this, NULL);
      81                  return;
      82          }
      83  }
      84  
      85  static void
      86  parse_font_face_property_cb (CRDocHandler * a_this,
      87                               CRString * a_name,
      88                               CRTerm * a_value, gboolean a_important)
      89  {
      90          enum CRStatus status = CR_OK;
      91          CRString *name = NULL;
      92          CRDeclaration *decl = NULL;
      93          CRStatement *stmt = NULL;
      94          CRStatement **stmtptr = NULL;
      95  
      96          g_return_if_fail (a_this && a_name);
      97  
      98  	stmtptr = &stmt;
      99          status = cr_doc_handler_get_ctxt (a_this, (gpointer *) stmtptr);
     100          g_return_if_fail (status == CR_OK && stmt);
     101          g_return_if_fail (stmt->type == AT_FONT_FACE_RULE_STMT);
     102  
     103          name = cr_string_dup (a_name) ;
     104          g_return_if_fail (name);
     105          decl = cr_declaration_new (stmt, name, a_value);
     106          if (!decl) {
     107                  cr_utils_trace_info ("cr_declaration_new () failed.");
     108                  goto error;
     109          }
     110          name = NULL;
     111  
     112          stmt->kind.font_face_rule->decl_list =
     113                  cr_declaration_append (stmt->kind.font_face_rule->decl_list,
     114                                         decl);
     115          if (!stmt->kind.font_face_rule->decl_list)
     116                  goto error;
     117          decl = NULL;
     118  
     119        error:
     120          if (decl) {
     121                  cr_declaration_unref (decl);
     122                  decl = NULL;
     123          }
     124          if (name) {
     125                  cr_string_destroy (name);
     126                  name = NULL;
     127          }
     128  }
     129  
     130  static void
     131  parse_font_face_end_font_face_cb (CRDocHandler * a_this)
     132  {
     133          CRStatement *result = NULL;
     134          CRStatement **resultptr = NULL;
     135          enum CRStatus status = CR_OK;
     136  
     137          g_return_if_fail (a_this);
     138  
     139  	resultptr = &result;
     140          status = cr_doc_handler_get_ctxt (a_this, (gpointer *) resultptr);
     141          g_return_if_fail (status == CR_OK && result);
     142          g_return_if_fail (result->type == AT_FONT_FACE_RULE_STMT);
     143  
     144          status = cr_doc_handler_set_result (a_this, result);
     145          g_return_if_fail (status == CR_OK);
     146  }
     147  
     148  static void
     149  parse_page_start_page_cb (CRDocHandler * a_this,
     150                            CRString * a_name, 
     151                            CRString * a_pseudo_page,
     152                            CRParsingLocation *a_location)
     153  {
     154          CRStatement *stmt = NULL;
     155          enum CRStatus status = CR_OK;
     156          CRString *page_name = NULL, *pseudo_name = NULL ;
     157  
     158          if (a_name)
     159                  page_name = cr_string_dup (a_name) ;
     160          if (a_pseudo_page)
     161                  pseudo_name = cr_string_dup (a_pseudo_page) ;
     162  
     163          stmt = cr_statement_new_at_page_rule (NULL, NULL, 
     164                                                page_name,
     165                                                pseudo_name);
     166          page_name = NULL ;
     167          pseudo_name = NULL ;
     168          g_return_if_fail (stmt);
     169          status = cr_doc_handler_set_ctxt (a_this, stmt);
     170          g_return_if_fail (status == CR_OK);
     171  }
     172  
     173  static void
     174  parse_page_unrecoverable_error_cb (CRDocHandler * a_this)
     175  {
     176          CRStatement *stmt = NULL;
     177          CRStatement **stmtptr = NULL;
     178          enum CRStatus status = CR_OK;
     179  
     180          g_return_if_fail (a_this);
     181  
     182  	stmtptr = &stmt;
     183          status = cr_doc_handler_get_ctxt (a_this, (gpointer *) stmtptr);
     184          if (status != CR_OK) {
     185                  cr_utils_trace_info ("Couldn't get parsing context. "
     186                                       "This may lead to some memory leaks.");
     187                  return;
     188          }
     189          if (stmt) {
     190                  cr_statement_destroy (stmt);
     191                  stmt = NULL;
     192                  cr_doc_handler_set_ctxt (a_this, NULL);
     193          }
     194  }
     195  
     196  static void
     197  parse_page_property_cb (CRDocHandler * a_this,
     198                          CRString * a_name,
     199                          CRTerm * a_expression, gboolean a_important)
     200  {
     201          CRString *name = NULL;
     202          CRStatement *stmt = NULL;
     203          CRStatement **stmtptr = NULL;
     204          CRDeclaration *decl = NULL;
     205          enum CRStatus status = CR_OK;
     206  
     207  	stmtptr = &stmt;
     208          status = cr_doc_handler_get_ctxt (a_this, (gpointer *) stmtptr);
     209          g_return_if_fail (status == CR_OK && stmt->type == AT_PAGE_RULE_STMT);
     210  
     211          name = cr_string_dup (a_name);
     212          g_return_if_fail (name);
     213  
     214          decl = cr_declaration_new (stmt, name, a_expression);
     215          g_return_if_fail (decl);
     216          decl->important = a_important;
     217          stmt->kind.page_rule->decl_list =
     218                  cr_declaration_append (stmt->kind.page_rule->decl_list, decl);
     219          g_return_if_fail (stmt->kind.page_rule->decl_list);
     220  }
     221  
     222  static void
     223  parse_page_end_page_cb (CRDocHandler * a_this,
     224                          CRString * a_name, 
     225                          CRString * a_pseudo_page)
     226  {
     227          enum CRStatus status = CR_OK;
     228          CRStatement *stmt = NULL;
     229          CRStatement **stmtptr = NULL;
     230  
     231  	stmtptr = &stmt;
     232          status = cr_doc_handler_get_ctxt (a_this, (gpointer *) stmtptr);
     233          g_return_if_fail (status == CR_OK && stmt);
     234          g_return_if_fail (stmt->type == AT_PAGE_RULE_STMT);
     235  
     236          status = cr_doc_handler_set_result (a_this, stmt);
     237          g_return_if_fail (status == CR_OK);
     238  }
     239  
     240  static void
     241  parse_at_media_start_media_cb (CRDocHandler * a_this, 
     242                                 GList * a_media_list,
     243                                 CRParsingLocation *a_location)
     244  {
     245          enum CRStatus status = CR_OK;
     246          CRStatement *at_media = NULL;
     247          GList *media_list = NULL;
     248  
     249          g_return_if_fail (a_this && a_this->priv);
     250  
     251          if (a_media_list) {
     252                  /*duplicate media list */
     253                  media_list = cr_utils_dup_glist_of_cr_string 
     254                          (a_media_list);
     255          }
     256  
     257          g_return_if_fail (media_list);
     258  
     259          /*make sure cr_statement_new_at_media_rule works in this case. */
     260          at_media = cr_statement_new_at_media_rule (NULL, NULL, media_list);
     261  
     262          status = cr_doc_handler_set_ctxt (a_this, at_media);
     263          g_return_if_fail (status == CR_OK);
     264          status = cr_doc_handler_set_result (a_this, at_media);
     265          g_return_if_fail (status == CR_OK);
     266  }
     267  
     268  static void
     269  parse_at_media_unrecoverable_error_cb (CRDocHandler * a_this)
     270  {
     271          enum CRStatus status = CR_OK;
     272          CRStatement *stmt = NULL;
     273          CRStatement **stmtptr = NULL;
     274  
     275          g_return_if_fail (a_this);
     276  
     277  	stmtptr = &stmt;
     278          status = cr_doc_handler_get_result (a_this, (gpointer *) stmtptr);
     279          if (status != CR_OK) {
     280                  cr_utils_trace_info ("Couldn't get parsing context. "
     281                                       "This may lead to some memory leaks.");
     282                  return;
     283          }
     284          if (stmt) {
     285                  cr_statement_destroy (stmt);
     286                  stmt = NULL;
     287                  cr_doc_handler_set_ctxt (a_this, NULL);
     288                  cr_doc_handler_set_result (a_this, NULL);
     289          }
     290  }
     291  
     292  static void
     293  parse_at_media_start_selector_cb (CRDocHandler * a_this,
     294                                    CRSelector * a_sellist)
     295  {
     296          enum CRStatus status = CR_OK;
     297          CRStatement *at_media = NULL;
     298          CRStatement **at_media_ptr = NULL;
     299  	CRStatement *ruleset = NULL;
     300  
     301          g_return_if_fail (a_this && a_this->priv && a_sellist);
     302  
     303  	at_media_ptr = &at_media;
     304          status = cr_doc_handler_get_ctxt (a_this, (gpointer *) at_media_ptr);
     305          g_return_if_fail (status == CR_OK && at_media);
     306          g_return_if_fail (at_media->type == AT_MEDIA_RULE_STMT);
     307          ruleset = cr_statement_new_ruleset (NULL, a_sellist, NULL, at_media);
     308          g_return_if_fail (ruleset);
     309          status = cr_doc_handler_set_ctxt (a_this, ruleset);
     310          g_return_if_fail (status == CR_OK);
     311  }
     312  
     313  static void
     314  parse_at_media_property_cb (CRDocHandler * a_this,
     315                              CRString * a_name, CRTerm * a_value,
     316                              gboolean a_important)
     317  {
     318          enum CRStatus status = CR_OK;
     319  
     320          /*
     321           *the current ruleset stmt, child of the 
     322           *current at-media being parsed.
     323           */
     324          CRStatement *stmt = NULL;
     325          CRStatement **stmtptr = NULL;
     326          CRDeclaration *decl = NULL;
     327          CRString *name = NULL;
     328  
     329          g_return_if_fail (a_this && a_name);
     330  
     331          name = cr_string_dup (a_name) ;
     332          g_return_if_fail (name);
     333  
     334  	stmtptr = &stmt;
     335          status = cr_doc_handler_get_ctxt (a_this, 
     336                                            (gpointer *) stmtptr);
     337          g_return_if_fail (status == CR_OK && stmt);
     338          g_return_if_fail (stmt->type == RULESET_STMT);
     339  
     340          decl = cr_declaration_new (stmt, name, a_value);
     341          g_return_if_fail (decl);
     342          decl->important = a_important;
     343          status = cr_statement_ruleset_append_decl (stmt, decl);
     344          g_return_if_fail (status == CR_OK);
     345  }
     346  
     347  static void
     348  parse_at_media_end_selector_cb (CRDocHandler * a_this, 
     349                                  CRSelector * a_sellist)
     350  {
     351          enum CRStatus status = CR_OK;
     352  
     353          /*
     354           *the current ruleset stmt, child of the 
     355           *current at-media being parsed.
     356           */
     357          CRStatement *stmt = NULL;
     358          CRStatement **stmtptr = NULL;
     359  
     360          g_return_if_fail (a_this && a_sellist);
     361  
     362  	stmtptr = &stmt;
     363          status = cr_doc_handler_get_ctxt (a_this, (gpointer *) stmtptr);
     364          g_return_if_fail (status == CR_OK && stmt
     365                            && stmt->type == RULESET_STMT);
     366          g_return_if_fail (stmt->kind.ruleset->parent_media_rule);
     367  
     368          status = cr_doc_handler_set_ctxt
     369                  (a_this, stmt->kind.ruleset->parent_media_rule);
     370          g_return_if_fail (status == CR_OK);
     371  }
     372  
     373  static void
     374  parse_at_media_end_media_cb (CRDocHandler * a_this, 
     375                               GList * a_media_list)
     376  {
     377          enum CRStatus status = CR_OK;
     378          CRStatement *at_media = NULL;
     379          CRStatement **at_media_ptr = NULL;
     380  
     381          g_return_if_fail (a_this && a_this->priv);
     382  
     383  	at_media_ptr = &at_media;
     384          status = cr_doc_handler_get_ctxt (a_this, 
     385                                            (gpointer *) at_media_ptr);
     386          g_return_if_fail (status == CR_OK && at_media);
     387          status = cr_doc_handler_set_result (a_this, at_media);
     388  }
     389  
     390  static void
     391  parse_ruleset_start_selector_cb (CRDocHandler * a_this,
     392                                   CRSelector * a_sellist)
     393  {
     394          CRStatement *ruleset = NULL;
     395  
     396          g_return_if_fail (a_this && a_this->priv && a_sellist);
     397  
     398          ruleset = cr_statement_new_ruleset (NULL, a_sellist, NULL, NULL);
     399          g_return_if_fail (ruleset);
     400  
     401          cr_doc_handler_set_result (a_this, ruleset);
     402  }
     403  
     404  static void
     405  parse_ruleset_unrecoverable_error_cb (CRDocHandler * a_this)
     406  {
     407          CRStatement *stmt = NULL;
     408          CRStatement **stmtptr = NULL;
     409          enum CRStatus status = CR_OK;
     410  
     411  	stmtptr = &stmt;
     412          status = cr_doc_handler_get_result (a_this, (gpointer *) stmtptr);
     413          if (status != CR_OK) {
     414                  cr_utils_trace_info ("Couldn't get parsing context. "
     415                                       "This may lead to some memory leaks.");
     416                  return;
     417          }
     418          if (stmt) {
     419                  cr_statement_destroy (stmt);
     420                  stmt = NULL;
     421                  cr_doc_handler_set_result (a_this, NULL);
     422          }
     423  }
     424  
     425  static void
     426  parse_ruleset_property_cb (CRDocHandler * a_this,
     427                             CRString * a_name,
     428                             CRTerm * a_value, gboolean a_important)
     429  {
     430          enum CRStatus status = CR_OK;
     431          CRStatement *ruleset = NULL;
     432          CRStatement **rulesetptr = NULL;
     433          CRDeclaration *decl = NULL;
     434          CRString *stringue = NULL;
     435  
     436          g_return_if_fail (a_this && a_this->priv && a_name);
     437  
     438          stringue = cr_string_dup (a_name);
     439          g_return_if_fail (stringue);
     440  
     441  	rulesetptr = &ruleset;
     442          status = cr_doc_handler_get_result (a_this, (gpointer *) rulesetptr);
     443          g_return_if_fail (status == CR_OK
     444                            && ruleset 
     445                            && ruleset->type == RULESET_STMT);
     446  
     447          decl = cr_declaration_new (ruleset, stringue, a_value);
     448          g_return_if_fail (decl);
     449          decl->important = a_important;
     450          status = cr_statement_ruleset_append_decl (ruleset, decl);
     451          g_return_if_fail (status == CR_OK);
     452  }
     453  
     454  static void
     455  parse_ruleset_end_selector_cb (CRDocHandler * a_this, 
     456                                 CRSelector * a_sellist)
     457  {
     458          CRStatement *result = NULL;
     459          CRStatement **resultptr = NULL;
     460          enum CRStatus status = CR_OK;
     461  
     462          g_return_if_fail (a_this && a_sellist);
     463  
     464  	resultptr = &result;
     465          status = cr_doc_handler_get_result (a_this, (gpointer *) resultptr);
     466  
     467          g_return_if_fail (status == CR_OK
     468                            && result 
     469                            && result->type == RULESET_STMT);
     470  }
     471  
     472  static void
     473  cr_statement_clear (CRStatement * a_this)
     474  {
     475          g_return_if_fail (a_this);
     476  
     477          switch (a_this->type) {
     478          case AT_RULE_STMT:
     479                  break;
     480          case RULESET_STMT:
     481                  if (!a_this->kind.ruleset)
     482                          return;
     483                  if (a_this->kind.ruleset->sel_list) {
     484                          cr_selector_unref (a_this->kind.ruleset->sel_list);
     485                          a_this->kind.ruleset->sel_list = NULL;
     486                  }
     487                  if (a_this->kind.ruleset->decl_list) {
     488                          cr_declaration_destroy
     489                                  (a_this->kind.ruleset->decl_list);
     490                          a_this->kind.ruleset->decl_list = NULL;
     491                  }
     492                  g_free (a_this->kind.ruleset);
     493                  a_this->kind.ruleset = NULL;
     494                  break;
     495  
     496          case AT_IMPORT_RULE_STMT:
     497                  if (!a_this->kind.import_rule)
     498                          return;
     499                  if (a_this->kind.import_rule->url) {
     500                          cr_string_destroy 
     501                                  (a_this->kind.import_rule->url) ;
     502                          a_this->kind.import_rule->url = NULL;
     503                  }
     504                  g_free (a_this->kind.import_rule);
     505                  a_this->kind.import_rule = NULL;
     506                  break;
     507  
     508          case AT_MEDIA_RULE_STMT:
     509                  if (!a_this->kind.media_rule)
     510                          return;
     511                  if (a_this->kind.media_rule->rulesets) {
     512                          cr_statement_destroy
     513                                  (a_this->kind.media_rule->rulesets);
     514                          a_this->kind.media_rule->rulesets = NULL;
     515                  }
     516                  if (a_this->kind.media_rule->media_list) {
     517                          GList *cur = NULL;
     518  
     519                          for (cur = a_this->kind.media_rule->media_list;
     520                               cur; cur = cur->next) {
     521                                  if (cur->data) {
     522                                          cr_string_destroy ((CRString *) cur->data);
     523                                          cur->data = NULL;
     524                                  }
     525  
     526                          }
     527                          g_list_free (a_this->kind.media_rule->media_list);
     528                          a_this->kind.media_rule->media_list = NULL;
     529                  }
     530                  g_free (a_this->kind.media_rule);
     531                  a_this->kind.media_rule = NULL;
     532                  break;
     533  
     534          case AT_PAGE_RULE_STMT:
     535                  if (!a_this->kind.page_rule)
     536                          return;
     537  
     538                  if (a_this->kind.page_rule->decl_list) {
     539                          cr_declaration_destroy
     540                                  (a_this->kind.page_rule->decl_list);
     541                          a_this->kind.page_rule->decl_list = NULL;
     542                  }
     543                  if (a_this->kind.page_rule->name) {
     544                          cr_string_destroy 
     545                                  (a_this->kind.page_rule->name);
     546                          a_this->kind.page_rule->name = NULL;
     547                  }
     548                  if (a_this->kind.page_rule->pseudo) {
     549                          cr_string_destroy
     550                                  (a_this->kind.page_rule->pseudo);
     551                          a_this->kind.page_rule->pseudo = NULL;
     552                  }
     553                  g_free (a_this->kind.page_rule);
     554                  a_this->kind.page_rule = NULL;
     555                  break;
     556  
     557          case AT_CHARSET_RULE_STMT:
     558                  if (!a_this->kind.charset_rule)
     559                          return;
     560  
     561                  if (a_this->kind.charset_rule->charset) {
     562                          cr_string_destroy
     563                                  (a_this->kind.charset_rule->charset);
     564                          a_this->kind.charset_rule->charset = NULL;
     565                  }
     566                  g_free (a_this->kind.charset_rule);
     567                  a_this->kind.charset_rule = NULL;
     568                  break;
     569  
     570          case AT_FONT_FACE_RULE_STMT:
     571                  if (!a_this->kind.font_face_rule)
     572                          return;
     573  
     574                  if (a_this->kind.font_face_rule->decl_list) {
     575                          cr_declaration_unref
     576                                  (a_this->kind.font_face_rule->decl_list);
     577                          a_this->kind.font_face_rule->decl_list = NULL;
     578                  }
     579                  g_free (a_this->kind.font_face_rule);
     580                  a_this->kind.font_face_rule = NULL;
     581                  break;
     582  
     583          default:
     584                  break;
     585          }
     586  }
     587  
     588  /**
     589   * cr_statement_ruleset_to_string:
     590   *
     591   *@a_this: the current instance of #CRStatement
     592   *@a_indent: the number of whitespace to use for indentation
     593   *
     594   *Serializes the ruleset statement into a string
     595   *
     596   *Returns the newly allocated serialised string. Must be freed
     597   *by the caller, using g_free().
     598   */
     599  static gchar *
     600  cr_statement_ruleset_to_string (CRStatement const * a_this, glong a_indent)
     601  {
     602          GString *stringue = NULL;
     603          gchar *tmp_str = NULL,
     604                  *result = NULL;
     605  
     606          g_return_val_if_fail (a_this && a_this->type == RULESET_STMT, NULL);
     607  
     608          stringue = g_string_new (NULL);
     609  
     610          if (a_this->kind.ruleset->sel_list) {
     611                  if (a_indent)
     612                          cr_utils_dump_n_chars2 (' ', stringue, a_indent);
     613  
     614                  tmp_str =
     615                          (gchar *) cr_selector_to_string (a_this->kind.ruleset->
     616                                                 sel_list);
     617                  if (tmp_str) {
     618                          g_string_append (stringue, tmp_str);
     619                          g_free (tmp_str);
     620                          tmp_str = NULL;
     621                  }
     622          }
     623          g_string_append (stringue, " {\n");
     624          if (a_this->kind.ruleset->decl_list) {
     625                  tmp_str = (gchar *) cr_declaration_list_to_string2
     626                          (a_this->kind.ruleset->decl_list,
     627                           a_indent + DECLARATION_INDENT_NB, TRUE);
     628                  if (tmp_str) {
     629                          g_string_append (stringue, tmp_str);
     630                          g_free (tmp_str);
     631                          tmp_str = NULL;
     632                  }
     633                  g_string_append (stringue, "\n");
     634                  cr_utils_dump_n_chars2 (' ', stringue, a_indent);
     635          }
     636          g_string_append (stringue, "}");
     637          result = stringue->str;
     638  
     639          if (stringue) {
     640                  g_string_free (stringue, FALSE);
     641                  stringue = NULL;
     642          }
     643          if (tmp_str) {
     644                  g_free (tmp_str);
     645                  tmp_str = NULL;
     646          }
     647          return result;
     648  }
     649  
     650  
     651  /**
     652   * cr_statement_font_face_rule_to_string:
     653   *
     654   *@a_this: the current instance of #CRStatement to consider
     655   *It must be a font face rule statement.
     656   *@a_indent: the number of white spaces of indentation.
     657   *
     658   *Serializes a font face rule statement into a string.
     659   *
     660   *Returns the serialized string. Must be deallocated by the caller
     661   *using g_free().
     662   */
     663  static gchar *
     664  cr_statement_font_face_rule_to_string (CRStatement const * a_this,
     665                                         glong a_indent)
     666  {
     667          gchar *result = NULL, *tmp_str = NULL ;
     668          GString *stringue = NULL ;
     669  
     670          g_return_val_if_fail (a_this 
     671                                && a_this->type == AT_FONT_FACE_RULE_STMT,
     672                                NULL);
     673  
     674          if (a_this->kind.font_face_rule->decl_list) {
     675                  stringue = g_string_new (NULL) ;
     676                  g_return_val_if_fail (stringue, NULL) ;
     677                  if (a_indent)
     678                          cr_utils_dump_n_chars2 (' ', stringue, 
     679                                          a_indent);
     680                  g_string_append (stringue, "@font-face {\n");
     681                  tmp_str = (gchar *) cr_declaration_list_to_string2 
     682                          (a_this->kind.font_face_rule->decl_list,
     683                           a_indent + DECLARATION_INDENT_NB, TRUE) ;
     684                  if (tmp_str) {
     685                          g_string_append (stringue,
     686                                           tmp_str) ;
     687                          g_free (tmp_str) ;
     688                          tmp_str = NULL ;
     689                  }
     690                  g_string_append (stringue, "\n}");
     691          }
     692          if (stringue) {
     693                  result = stringue->str ;
     694                  g_string_free (stringue, FALSE) ;
     695                  stringue = NULL ;
     696          }
     697          return result ;
     698  }
     699  
     700  
     701  /**
     702   * cr_statement_charset_to_string:
     703   *
     704   *Serialises an \@charset statement into a string.
     705   *@a_this: the statement to serialize.
     706   *@a_indent: the number of indentation spaces
     707   *
     708   *Returns the serialized charset statement. Must be
     709   *freed by the caller using g_free().
     710   */
     711  static gchar *
     712  cr_statement_charset_to_string (CRStatement const *a_this,
     713                                  gulong a_indent)
     714  {
     715          gchar *str = NULL ;
     716          GString *stringue = NULL ;
     717  
     718          g_return_val_if_fail (a_this
     719                                && a_this->type == AT_CHARSET_RULE_STMT,
     720                                NULL) ;
     721  
     722          if (a_this->kind.charset_rule
     723              && a_this->kind.charset_rule->charset
     724              && a_this->kind.charset_rule->charset->stryng
     725              && a_this->kind.charset_rule->charset->stryng->str) {
     726                  str = g_strndup (a_this->kind.charset_rule->charset->stryng->str,
     727                                   a_this->kind.charset_rule->charset->stryng->len);
     728                  g_return_val_if_fail (str, NULL);
     729                  stringue = g_string_new (NULL) ;
     730                  g_return_val_if_fail (stringue, NULL) ;
     731                  cr_utils_dump_n_chars2 (' ', stringue, a_indent);
     732                  g_string_append_printf (stringue, 
     733                                          "@charset \"%s\" ;", str);
     734                  if (str) {
     735                          g_free (str);
     736                          str = NULL;
     737                  }
     738          }
     739          if (stringue) {
     740                  str = stringue->str ;
     741                  g_string_free (stringue, FALSE) ;
     742          }
     743          return str ;
     744  }
     745  
     746  
     747  /**
     748   * cr_statement_at_page_rule_to_string:
     749   *
     750   *Serialises the at page rule statement into a string
     751   *@a_this: the current instance of #CRStatement. Must
     752   *be an "\@page" rule statement.
     753   *
     754   *Returns the serialized string. Must be freed by the caller
     755   */
     756  static gchar *
     757  cr_statement_at_page_rule_to_string (CRStatement const *a_this,
     758                                       gulong a_indent)
     759  {
     760          GString *stringue = NULL;
     761          gchar *result = NULL ;
     762  
     763          stringue = g_string_new (NULL) ;
     764  
     765          cr_utils_dump_n_chars2 (' ', stringue, a_indent) ;
     766          g_string_append (stringue, "@page");
     767  	if (a_this->kind.page_rule->name
     768  	    && a_this->kind.page_rule->name->stryng) {
     769  		g_string_append_printf 
     770  		  (stringue, " %s",
     771  		   a_this->kind.page_rule->name->stryng->str) ;
     772          } else {
     773                  g_string_append (stringue, " ");
     774          }
     775  	if (a_this->kind.page_rule->pseudo
     776  	    && a_this->kind.page_rule->pseudo->stryng) {
     777  		g_string_append_printf 
     778  		  (stringue,  " :%s",
     779  		   a_this->kind.page_rule->pseudo->stryng->str) ;
     780          }
     781          if (a_this->kind.page_rule->decl_list) {
     782                  gchar *str = NULL ;
     783                  g_string_append (stringue, " {\n");
     784                  str = (gchar *) cr_declaration_list_to_string2
     785                          (a_this->kind.page_rule->decl_list,
     786                           a_indent + DECLARATION_INDENT_NB, TRUE) ;
     787                  if (str) {
     788                          g_string_append (stringue, str) ;
     789                          g_free (str) ;
     790                          str = NULL ;
     791                  }
     792                  g_string_append (stringue, "\n}\n");
     793          }
     794          result = stringue->str ;
     795          g_string_free (stringue, FALSE) ;
     796          stringue = NULL ;
     797          return result ;
     798  }
     799  
     800  
     801  /**
     802   *Serializes an \@media statement.
     803   *@param a_this the current instance of #CRStatement
     804   *@param a_indent the number of spaces of indentation.
     805   *@return the serialized \@media statement. Must be freed
     806   *by the caller using g_free().
     807   */
     808  static gchar *
     809  cr_statement_media_rule_to_string (CRStatement const *a_this,
     810                                     gulong a_indent)
     811  {
     812          gchar *str = NULL ;
     813          GString *stringue = NULL ;
     814          GList const *cur = NULL;
     815  
     816          g_return_val_if_fail (a_this->type == AT_MEDIA_RULE_STMT,
     817                                NULL);
     818  
     819          if (a_this->kind.media_rule) {
     820                  stringue = g_string_new (NULL) ;                
     821                  cr_utils_dump_n_chars2 (' ', stringue, a_indent);
     822                  g_string_append (stringue, "@media");
     823  
     824                  for (cur = a_this->kind.media_rule->media_list; cur;
     825                       cur = cur->next) {
     826                          if (cur->data) {
     827                                  gchar *str2 = cr_string_dup2
     828                                          ((CRString const *) cur->data);
     829  
     830                                  if (str2) {
     831                                          if (cur->prev) {
     832                                                  g_string_append
     833                                                          (stringue, 
     834                                                           ",");
     835                                          }
     836                                          g_string_append_printf 
     837                                                  (stringue, 
     838                                                   " %s", str2);
     839                                          g_free (str2);
     840                                          str2 = NULL;
     841                                  }
     842                          }
     843                  }
     844                  g_string_append (stringue, " {\n");
     845                  str = cr_statement_list_to_string
     846                          (a_this->kind.media_rule->rulesets,
     847                           a_indent + DECLARATION_INDENT_NB) ;
     848                  if (str) {
     849                          g_string_append (stringue, str) ;
     850                          g_free (str) ;
     851                          str = NULL ;
     852                  }
     853                  g_string_append (stringue, "\n}");
     854          }
     855          if (stringue) {
     856                  str = stringue->str ;
     857                  g_string_free (stringue, FALSE) ;
     858          }
     859          return str ;
     860  }
     861  
     862  
     863  static gchar *
     864  cr_statement_import_rule_to_string (CRStatement const *a_this,
     865                                      gulong a_indent)
     866  {
     867          GString *stringue = NULL ;
     868          gchar *str = NULL;
     869  
     870          g_return_val_if_fail (a_this
     871                                && a_this->type == AT_IMPORT_RULE_STMT
     872                                && a_this->kind.import_rule,
     873                                NULL) ;
     874  
     875          if (a_this->kind.import_rule->url
     876              && a_this->kind.import_rule->url->stryng) { 
     877                  stringue = g_string_new (NULL) ;
     878                  g_return_val_if_fail (stringue, NULL) ;
     879                  str = g_strndup (a_this->kind.import_rule->url->stryng->str,
     880                                   a_this->kind.import_rule->url->stryng->len);
     881                  cr_utils_dump_n_chars2 (' ', stringue, a_indent);
     882                  if (str) {
     883                          g_string_append_printf (stringue,
     884                                                  "@import url(\"%s\")", 
     885                                                  str);
     886                          g_free (str);
     887                          str = NULL ;
     888                  } else          /*there is no url, so no import rule, get out! */
     889                          return NULL;
     890  
     891                  if (a_this->kind.import_rule->media_list) {
     892                          GList const *cur = NULL;
     893  
     894                          for (cur = a_this->kind.import_rule->media_list;
     895                               cur; cur = cur->next) {
     896                                  if (cur->data) {
     897                                          CRString const *crstr = cur->data;
     898  
     899                                          if (cur->prev) {
     900                                                  g_string_append 
     901                                                          (stringue, ", ");
     902                                          }
     903                                          if (crstr 
     904                                              && crstr->stryng
     905                                              && crstr->stryng->str) {
     906                                                  g_string_append_len 
     907                                                          (stringue,
     908                                                           crstr->stryng->str,
     909                                                           crstr->stryng->len) ;
     910                                          }
     911                                  }
     912                          }
     913                  }
     914                  g_string_append (stringue, " ;");
     915          }
     916          if (stringue) {
     917                  str = stringue->str ;
     918                  g_string_free (stringue, FALSE) ;
     919                  stringue = NULL ;
     920          }
     921          return str ;
     922  }
     923  
     924  
     925  /*******************
     926   *public functions
     927   ******************/
     928  
     929  /**
     930   * cr_statement_does_buf_parses_against_core:
     931   *
     932   *@a_buf: the buffer to parse.
     933   *@a_encoding: the character encoding of a_buf.
     934   *
     935   *Tries to parse a buffer and says whether if the content of the buffer
     936   *is a css statement as defined by the "Core CSS Grammar" (chapter 4 of the
     937   *css spec) or not.
     938   *
     939   *Returns TRUE if the buffer parses against the core grammar, false otherwise.
     940   */
     941  gboolean
     942  cr_statement_does_buf_parses_against_core (const guchar * a_buf,
     943                                             enum CREncoding a_encoding)
     944  {
     945          CRParser *parser = NULL;
     946          enum CRStatus status = CR_OK;
     947          gboolean result = FALSE;
     948  
     949          parser = cr_parser_new_from_buf ((guchar*)a_buf, strlen ((const char *) a_buf),
     950                                           a_encoding, FALSE);
     951          g_return_val_if_fail (parser, FALSE);
     952  
     953          status = cr_parser_set_use_core_grammar (parser, TRUE);
     954          if (status != CR_OK) {
     955                  goto cleanup;
     956          }
     957  
     958          status = cr_parser_parse_statement_core (parser);
     959          if (status == CR_OK) {
     960                  result = TRUE;
     961          }
     962  
     963        cleanup:
     964          if (parser) {
     965                  cr_parser_destroy (parser);
     966          }
     967  
     968          return result;
     969  }
     970  
     971  /**
     972   * cr_statement_parse_from_buf:
     973   *
     974   *@a_buf: the buffer to parse.
     975   *@a_encoding: the character encoding of a_buf.
     976   *
     977   *Parses a buffer that contains a css statement and returns 
     978   *an instance of #CRStatement in case of successful parsing.
     979   *TODO: at support of "\@import" rules.
     980   *
     981   *Returns the newly built instance of #CRStatement in case
     982   *of successful parsing, NULL otherwise.
     983   */
     984  CRStatement *
     985  cr_statement_parse_from_buf (const guchar * a_buf, enum CREncoding a_encoding)
     986  {
     987          CRStatement *result = NULL;
     988  
     989          /*
     990           *The strategy of this function is "brute force".
     991           *It tries to parse all the types of CRStatement it knows about.
     992           *I could do this a smarter way but I don't have the time now.
     993           *I think I will revisit this when time of performances and
     994           *pull based incremental parsing comes.
     995           */
     996  
     997          result = cr_statement_ruleset_parse_from_buf (a_buf, a_encoding);
     998          if (!result) {
     999                  result = cr_statement_at_charset_rule_parse_from_buf
    1000                          (a_buf, a_encoding);
    1001          } else {
    1002                  goto out;
    1003          }
    1004  
    1005          if (!result) {
    1006                  result = cr_statement_at_media_rule_parse_from_buf
    1007                          (a_buf, a_encoding);
    1008          } else {
    1009                  goto out;
    1010          }
    1011  
    1012          if (!result) {
    1013                  result = cr_statement_at_charset_rule_parse_from_buf
    1014                          (a_buf, a_encoding);
    1015          } else {
    1016                  goto out;
    1017          }
    1018  
    1019          if (!result) {
    1020                  result = cr_statement_font_face_rule_parse_from_buf
    1021                          (a_buf, a_encoding);
    1022  
    1023          } else {
    1024                  goto out;
    1025          }
    1026  
    1027          if (!result) {
    1028                  result = cr_statement_at_page_rule_parse_from_buf
    1029                          (a_buf, a_encoding);
    1030          } else {
    1031                  goto out;
    1032          }
    1033  
    1034          if (!result) {
    1035                  result = cr_statement_at_import_rule_parse_from_buf
    1036                          (a_buf, a_encoding);
    1037          } else {
    1038                  goto out;
    1039          }
    1040  
    1041        out:
    1042          return result;
    1043  }
    1044  
    1045  /**
    1046   * cr_statement_ruleset_parse_from_buf:
    1047   *
    1048   *@a_buf: the buffer to parse.
    1049   *@a_enc: the character encoding of a_buf.
    1050   *
    1051   *Parses a buffer that contains a ruleset statement an instanciates
    1052   *a #CRStatement of type RULESET_STMT.
    1053   *
    1054   *Returns the newly built instance of #CRStatement in case of successful parsing,
    1055   *NULL otherwise.
    1056   */
    1057  CRStatement *
    1058  cr_statement_ruleset_parse_from_buf (const guchar * a_buf,
    1059                                       enum CREncoding a_enc)
    1060  {
    1061          enum CRStatus status = CR_OK;
    1062          CRStatement *result = NULL;
    1063          CRStatement **resultptr = NULL;
    1064          CRParser *parser = NULL;
    1065          CRDocHandler *sac_handler = NULL;
    1066  
    1067          g_return_val_if_fail (a_buf, NULL);
    1068  
    1069          parser = cr_parser_new_from_buf ((guchar*)a_buf, strlen ((const char *) a_buf), 
    1070                                           a_enc, FALSE);
    1071  
    1072          g_return_val_if_fail (parser, NULL);
    1073  
    1074          sac_handler = cr_doc_handler_new ();
    1075          g_return_val_if_fail (parser, NULL);
    1076  
    1077          sac_handler->start_selector = parse_ruleset_start_selector_cb;
    1078          sac_handler->end_selector = parse_ruleset_end_selector_cb;
    1079          sac_handler->property = parse_ruleset_property_cb;
    1080          sac_handler->unrecoverable_error =
    1081                  parse_ruleset_unrecoverable_error_cb;
    1082  
    1083          cr_parser_set_sac_handler (parser, sac_handler);
    1084          cr_parser_try_to_skip_spaces_and_comments (parser);
    1085          status = cr_parser_parse_ruleset (parser);
    1086          if (status != CR_OK) {
    1087                  goto cleanup;
    1088          }
    1089  
    1090  	resultptr = &result;
    1091          status = cr_doc_handler_get_result (sac_handler,
    1092                                              (gpointer *) resultptr);
    1093          if (!((status == CR_OK) && result)) {
    1094                  if (result) {
    1095                          cr_statement_destroy (result);
    1096                          result = NULL;
    1097                  }
    1098          }
    1099  
    1100        cleanup:
    1101          if (parser) {
    1102                  cr_parser_destroy (parser);
    1103                  parser = NULL;
    1104                  sac_handler = NULL ;
    1105          }
    1106          if (sac_handler) {
    1107                  cr_doc_handler_unref (sac_handler);
    1108                  sac_handler = NULL;
    1109          }
    1110          return result;
    1111  }
    1112  
    1113  /**
    1114   * cr_statement_new_ruleset:
    1115   *
    1116   *@a_sel_list: the list of #CRSimpleSel (selectors)
    1117   *the rule applies to.
    1118   *@a_decl_list: the list of instances of #CRDeclaration
    1119   *that composes the ruleset.
    1120   *@a_media_types: a list of instances of GString that
    1121   *describe the media list this ruleset applies to.
    1122   *
    1123   *Creates a new instance of #CRStatement of type
    1124   *#CRRulSet.
    1125   *
    1126   *Returns the new instance of #CRStatement or NULL if something
    1127   *went wrong.
    1128   */
    1129  CRStatement *
    1130  cr_statement_new_ruleset (CRStyleSheet * a_sheet,
    1131                            CRSelector * a_sel_list,
    1132                            CRDeclaration * a_decl_list,
    1133                            CRStatement * a_parent_media_rule)
    1134  {
    1135          CRStatement *result = NULL;
    1136  
    1137          g_return_val_if_fail (a_sel_list, NULL);
    1138  
    1139          if (a_parent_media_rule) {
    1140                  g_return_val_if_fail
    1141                          (a_parent_media_rule->type == AT_MEDIA_RULE_STMT,
    1142                           NULL);
    1143                  g_return_val_if_fail (a_parent_media_rule->kind.media_rule,
    1144                                        NULL);
    1145          }
    1146  
    1147          result = g_try_malloc (sizeof (CRStatement));
    1148  
    1149          if (!result) {
    1150                  cr_utils_trace_info ("Out of memory");
    1151                  return NULL;
    1152          }
    1153  
    1154          memset (result, 0, sizeof (CRStatement));
    1155          result->type = RULESET_STMT;
    1156          result->kind.ruleset = g_try_malloc (sizeof (CRRuleSet));
    1157  
    1158          if (!result->kind.ruleset) {
    1159                  cr_utils_trace_info ("Out of memory");
    1160                  if (result)
    1161                          g_free (result);
    1162                  return NULL;
    1163          }
    1164  
    1165          memset (result->kind.ruleset, 0, sizeof (CRRuleSet));
    1166          result->kind.ruleset->sel_list = a_sel_list;
    1167          if (a_sel_list)
    1168                  cr_selector_ref (a_sel_list);
    1169          result->kind.ruleset->decl_list = a_decl_list;
    1170  
    1171          if (a_parent_media_rule) {
    1172                  result->kind.ruleset->parent_media_rule = a_parent_media_rule;
    1173                  a_parent_media_rule->kind.media_rule->rulesets =
    1174                          cr_statement_append
    1175                          (a_parent_media_rule->kind.media_rule->rulesets,
    1176                           result);
    1177          }
    1178  
    1179          cr_statement_set_parent_sheet (result, a_sheet);
    1180  
    1181          return result;
    1182  }
    1183  
    1184  /**
    1185   * cr_statement_at_media_rule_parse_from_buf:
    1186   *
    1187   *@a_buf: the input to parse.
    1188   *@a_enc: the encoding of the buffer.
    1189   *
    1190   *Parses a buffer that contains an "\@media" declaration
    1191   *and builds an \@media css statement.
    1192   *
    1193   *Returns the \@media statement, or NULL if the buffer could not
    1194   *be successfully parsed.
    1195   */
    1196  CRStatement *
    1197  cr_statement_at_media_rule_parse_from_buf (const guchar * a_buf,
    1198                                             enum CREncoding a_enc)
    1199  {
    1200          CRParser *parser = NULL;
    1201          CRStatement *result = NULL;
    1202          CRStatement **resultptr = NULL;
    1203          CRDocHandler *sac_handler = NULL;
    1204          enum CRStatus status = CR_OK;
    1205  
    1206          parser = cr_parser_new_from_buf ((guchar*)a_buf, strlen ((const char *) a_buf), 
    1207                                           a_enc, FALSE);
    1208          if (!parser) {
    1209                  cr_utils_trace_info ("Instantiation of the parser failed");
    1210                  goto cleanup;
    1211          }
    1212  
    1213          sac_handler = cr_doc_handler_new ();
    1214          if (!sac_handler) {
    1215                  cr_utils_trace_info
    1216                          ("Instantiation of the sac handler failed");
    1217                  goto cleanup;
    1218          }
    1219  
    1220          sac_handler->start_media = parse_at_media_start_media_cb;
    1221          sac_handler->start_selector = parse_at_media_start_selector_cb;
    1222          sac_handler->property = parse_at_media_property_cb;
    1223          sac_handler->end_selector = parse_at_media_end_selector_cb;
    1224          sac_handler->end_media = parse_at_media_end_media_cb;
    1225          sac_handler->unrecoverable_error =
    1226                  parse_at_media_unrecoverable_error_cb;
    1227  
    1228          status = cr_parser_set_sac_handler (parser, sac_handler);
    1229          if (status != CR_OK)
    1230                  goto cleanup;
    1231  
    1232          status = cr_parser_try_to_skip_spaces_and_comments (parser);
    1233          if (status != CR_OK)
    1234                  goto cleanup;
    1235  
    1236          status = cr_parser_parse_media (parser);
    1237          if (status != CR_OK)
    1238                  goto cleanup;
    1239  
    1240  	resultptr = &result;
    1241          status = cr_doc_handler_get_result (sac_handler,
    1242                                              (gpointer *) resultptr);
    1243          if (status != CR_OK)
    1244                  goto cleanup;
    1245  
    1246        cleanup:
    1247  
    1248          if (parser) {
    1249                  cr_parser_destroy (parser);
    1250                  parser = NULL;
    1251                  sac_handler = NULL ;
    1252          }
    1253          if (sac_handler) {
    1254                  cr_doc_handler_unref (sac_handler);
    1255                  sac_handler = NULL;
    1256          }
    1257  
    1258          return result;
    1259  }
    1260  
    1261  /**
    1262   * cr_statement_new_at_media_rule:
    1263   *
    1264   *@a_ruleset: the ruleset statements contained
    1265   *in the \@media rule.
    1266   *@a_media: the media string list. A list of GString pointers.
    1267   *
    1268   *Instanciates an instance of #CRStatement of type
    1269   *AT_MEDIA_RULE_STMT (\@media ruleset).
    1270   *
    1271   */
    1272  CRStatement *
    1273  cr_statement_new_at_media_rule (CRStyleSheet * a_sheet,
    1274                                  CRStatement * a_rulesets, GList * a_media)
    1275  {
    1276          CRStatement *result = NULL,
    1277                  *cur = NULL;
    1278  
    1279          if (a_rulesets)
    1280                  g_return_val_if_fail (a_rulesets->type == RULESET_STMT, NULL);
    1281  
    1282          result = g_try_malloc (sizeof (CRStatement));
    1283  
    1284          if (!result) {
    1285                  cr_utils_trace_info ("Out of memory");
    1286                  return NULL;
    1287          }
    1288  
    1289          memset (result, 0, sizeof (CRStatement));
    1290          result->type = AT_MEDIA_RULE_STMT;
    1291  
    1292          result->kind.media_rule = g_try_malloc (sizeof (CRAtMediaRule));
    1293          if (!result->kind.media_rule) {
    1294                  cr_utils_trace_info ("Out of memory");
    1295                  g_free (result);
    1296                  return NULL;
    1297          }
    1298          memset (result->kind.media_rule, 0, sizeof (CRAtMediaRule));
    1299          result->kind.media_rule->rulesets = a_rulesets;
    1300          for (cur = a_rulesets; cur; cur = cur->next) {
    1301                  if (cur->type != RULESET_STMT || !cur->kind.ruleset) {
    1302                          cr_utils_trace_info ("Bad parameter a_rulesets. "
    1303                                               "It should be a list of "
    1304                                               "correct ruleset statement only !");
    1305                          goto error;
    1306                  }
    1307                  cur->kind.ruleset->parent_media_rule = result;
    1308          }
    1309  
    1310          result->kind.media_rule->media_list = a_media;
    1311          if (a_sheet) {
    1312                  cr_statement_set_parent_sheet (result, a_sheet);
    1313          }
    1314  
    1315          return result;
    1316  
    1317        error:
    1318          return NULL;
    1319  }
    1320  
    1321  /**
    1322   * cr_statement_new_at_import_rule:
    1323   *
    1324   *@a_url: the url to connect to the get the file
    1325   *to be imported.
    1326   *@a_sheet: the imported parsed stylesheet.
    1327   *
    1328   *Creates a new instance of #CRStatment of type
    1329   *#CRAtImportRule.
    1330   *
    1331   *Returns the newly built instance of #CRStatement.
    1332   */
    1333  CRStatement *
    1334  cr_statement_new_at_import_rule (CRStyleSheet * a_container_sheet,
    1335                                   CRString * a_url,
    1336                                   GList * a_media_list,
    1337                                   CRStyleSheet * a_imported_sheet)
    1338  {
    1339          CRStatement *result = NULL;
    1340  
    1341          result = g_try_malloc (sizeof (CRStatement));
    1342  
    1343          if (!result) {
    1344                  cr_utils_trace_info ("Out of memory");
    1345                  return NULL;
    1346          }
    1347  
    1348          memset (result, 0, sizeof (CRStatement));
    1349          result->type = AT_IMPORT_RULE_STMT;
    1350  
    1351          result->kind.import_rule = g_try_malloc (sizeof (CRAtImportRule));
    1352  
    1353          if (!result->kind.import_rule) {
    1354                  cr_utils_trace_info ("Out of memory");
    1355                  g_free (result);
    1356                  return NULL;
    1357          }
    1358  
    1359          memset (result->kind.import_rule, 0, sizeof (CRAtImportRule));
    1360          result->kind.import_rule->url = a_url;
    1361          result->kind.import_rule->media_list = a_media_list;
    1362          result->kind.import_rule->sheet = a_imported_sheet;
    1363          if (a_container_sheet)
    1364                  cr_statement_set_parent_sheet (result, a_container_sheet);
    1365  
    1366          return result;
    1367  }
    1368  
    1369  /**
    1370   * cr_statement_at_import_rule_parse_from_buf:
    1371   *
    1372   *@a_buf: the buffer to parse.
    1373   *@a_encoding: the encoding of a_buf.
    1374   *
    1375   *Parses a buffer that contains an "\@import" rule and
    1376   *instanciate a #CRStatement of type AT_IMPORT_RULE_STMT
    1377   *
    1378   *Returns the newly built instance of #CRStatement in case of 
    1379   *a successful parsing, NULL otherwise.
    1380   */
    1381  CRStatement *
    1382  cr_statement_at_import_rule_parse_from_buf (const guchar * a_buf,
    1383                                              enum CREncoding a_encoding)
    1384  {
    1385          enum CRStatus status = CR_OK;
    1386          CRParser *parser = NULL;
    1387          CRStatement *result = NULL;
    1388          GList *media_list = NULL;
    1389          CRString *import_string = NULL;
    1390          CRParsingLocation location = {0} ;
    1391  
    1392          parser = cr_parser_new_from_buf ((guchar*)a_buf, strlen ((const char *) a_buf),
    1393                                           a_encoding, FALSE);
    1394          if (!parser) {
    1395                  cr_utils_trace_info ("Instantiation of parser failed.");
    1396                  goto cleanup;
    1397          }
    1398  
    1399          status = cr_parser_try_to_skip_spaces_and_comments (parser);
    1400          if (status != CR_OK)
    1401                  goto cleanup;
    1402  
    1403          status = cr_parser_parse_import (parser,
    1404                                           &media_list, 
    1405                                           &import_string,
    1406                                           &location);
    1407          if (status != CR_OK || !import_string)
    1408                  goto cleanup;
    1409  
    1410          result = cr_statement_new_at_import_rule (NULL, import_string,
    1411                                                    media_list, NULL);
    1412          if (result) {
    1413                  cr_parsing_location_copy (&result->location,
    1414                                            &location) ;
    1415                  import_string = NULL;
    1416                  media_list = NULL;
    1417          }
    1418  
    1419   cleanup:
    1420          if (parser) {
    1421                  cr_parser_destroy (parser);
    1422                  parser = NULL;
    1423          }
    1424          if (media_list) {
    1425                  for (; media_list;
    1426                       media_list = g_list_next (media_list)) {
    1427                          if (media_list->data) {
    1428                                  cr_string_destroy ((CRString*)media_list->data);
    1429                                  media_list->data = NULL;
    1430                          }
    1431                  }
    1432                  g_list_free (media_list);
    1433                  media_list = NULL;
    1434          }
    1435          if (import_string) {
    1436                  cr_string_destroy (import_string);
    1437                  import_string = NULL;
    1438          }
    1439  
    1440          return result;
    1441  }
    1442  
    1443  /**
    1444   * cr_statement_new_at_page_rule:
    1445   *
    1446   *@a_decl_list: a list of instances of #CRDeclarations
    1447   *which is actually the list of declarations that applies to
    1448   *this page rule.
    1449   *@a_selector: the page rule selector.
    1450   *
    1451   *Creates a new instance of #CRStatement of type
    1452   *#CRAtPageRule.
    1453   *
    1454   *Returns the newly built instance of #CRStatement or NULL
    1455   *in case of error.
    1456   */
    1457  CRStatement *
    1458  cr_statement_new_at_page_rule (CRStyleSheet * a_sheet,
    1459                                 CRDeclaration * a_decl_list,
    1460                                 CRString * a_name, CRString * a_pseudo)
    1461  {
    1462          CRStatement *result = NULL;
    1463  
    1464          result = g_try_malloc (sizeof (CRStatement));
    1465  
    1466          if (!result) {
    1467                  cr_utils_trace_info ("Out of memory");
    1468                  return NULL;
    1469          }
    1470  
    1471          memset (result, 0, sizeof (CRStatement));
    1472          result->type = AT_PAGE_RULE_STMT;
    1473  
    1474          result->kind.page_rule = g_try_malloc (sizeof (CRAtPageRule));
    1475  
    1476          if (!result->kind.page_rule) {
    1477                  cr_utils_trace_info ("Out of memory");
    1478                  g_free (result);
    1479                  return NULL;
    1480          }
    1481  
    1482          memset (result->kind.page_rule, 0, sizeof (CRAtPageRule));
    1483          if (a_decl_list) {
    1484                  result->kind.page_rule->decl_list = a_decl_list;
    1485                  cr_declaration_ref (a_decl_list);
    1486          }
    1487          result->kind.page_rule->name = a_name;
    1488          result->kind.page_rule->pseudo = a_pseudo;
    1489          if (a_sheet)
    1490                  cr_statement_set_parent_sheet (result, a_sheet);
    1491  
    1492          return result;
    1493  }
    1494  
    1495  /**
    1496   * cr_statement_at_page_rule_parse_from_buf:
    1497   *
    1498   *@a_buf: the character buffer to parse.
    1499   *@a_encoding: the character encoding of a_buf.
    1500   *
    1501   *Parses a buffer that contains an "\@page" production and,
    1502   *if the parsing succeeds, builds the page statement.
    1503   *
    1504   *Returns the newly built at page statement in case of successful parsing,
    1505   *NULL otherwise.
    1506   */
    1507  CRStatement *
    1508  cr_statement_at_page_rule_parse_from_buf (const guchar * a_buf,
    1509                                            enum CREncoding a_encoding)
    1510  {
    1511          enum CRStatus status = CR_OK;
    1512          CRParser *parser = NULL;
    1513          CRDocHandler *sac_handler = NULL;
    1514          CRStatement *result = NULL;
    1515          CRStatement **resultptr = NULL;
    1516  
    1517          g_return_val_if_fail (a_buf, NULL);
    1518  
    1519          parser = cr_parser_new_from_buf ((guchar*)a_buf, strlen ((const char *) a_buf),
    1520                                           a_encoding, FALSE);
    1521          if (!parser) {
    1522                  cr_utils_trace_info ("Instantiation of the parser failed.");
    1523                  goto cleanup;
    1524          }
    1525  
    1526          sac_handler = cr_doc_handler_new ();
    1527          if (!sac_handler) {
    1528                  cr_utils_trace_info
    1529                          ("Instantiation of the sac handler failed.");
    1530                  goto cleanup;
    1531          }
    1532  
    1533          sac_handler->start_page = parse_page_start_page_cb;
    1534          sac_handler->property = parse_page_property_cb;
    1535          sac_handler->end_page = parse_page_end_page_cb;
    1536          sac_handler->unrecoverable_error = parse_page_unrecoverable_error_cb;
    1537  
    1538          status = cr_parser_set_sac_handler (parser, sac_handler);
    1539          if (status != CR_OK)
    1540                  goto cleanup;
    1541  
    1542          /*Now, invoke the parser to parse the "@page production" */
    1543          cr_parser_try_to_skip_spaces_and_comments (parser);
    1544          if (status != CR_OK)
    1545                  goto cleanup;
    1546          status = cr_parser_parse_page (parser);
    1547          if (status != CR_OK)
    1548                  goto cleanup;
    1549  
    1550  	resultptr = &result;
    1551          status = cr_doc_handler_get_result (sac_handler,
    1552                                              (gpointer *) resultptr);
    1553  
    1554        cleanup:
    1555  
    1556          if (parser) {
    1557                  cr_parser_destroy (parser);
    1558                  parser = NULL;
    1559                  sac_handler = NULL ;
    1560          }
    1561          if (sac_handler) {
    1562                  cr_doc_handler_unref (sac_handler);
    1563                  sac_handler = NULL;
    1564          }
    1565          return result;
    1566  }
    1567  
    1568  /**
    1569   * cr_statement_new_at_charset_rule:
    1570   *
    1571   *@a_charset: the string representing the charset.
    1572   *Note that the newly built instance of #CRStatement becomes
    1573   *the owner of a_charset. The caller must not free a_charset !!!.
    1574   *
    1575   *Creates a new instance of #CRStatement of type
    1576   *#CRAtCharsetRule.
    1577   *
    1578   *Returns the newly built instance of #CRStatement or NULL
    1579   *if an error arises.
    1580   */
    1581  CRStatement *
    1582  cr_statement_new_at_charset_rule (CRStyleSheet * a_sheet, 
    1583                                    CRString * a_charset)
    1584  {
    1585          CRStatement *result = NULL;
    1586  
    1587          g_return_val_if_fail (a_charset, NULL);
    1588  
    1589          result = g_try_malloc (sizeof (CRStatement));
    1590  
    1591          if (!result) {
    1592                  cr_utils_trace_info ("Out of memory");
    1593                  return NULL;
    1594          }
    1595  
    1596          memset (result, 0, sizeof (CRStatement));
    1597          result->type = AT_CHARSET_RULE_STMT;
    1598  
    1599          result->kind.charset_rule = g_try_malloc (sizeof (CRAtCharsetRule));
    1600  
    1601          if (!result->kind.charset_rule) {
    1602                  cr_utils_trace_info ("Out of memory");
    1603                  g_free (result);
    1604                  return NULL;
    1605          }
    1606          memset (result->kind.charset_rule, 0, sizeof (CRAtCharsetRule));
    1607          result->kind.charset_rule->charset = a_charset;
    1608          cr_statement_set_parent_sheet (result, a_sheet);
    1609  
    1610          return result;
    1611  }
    1612  
    1613  /**
    1614   * cr_statement_at_charset_rule_parse_from_buf:
    1615   *
    1616   *@a_buf: the buffer to parse.
    1617   *@a_encoding: the character encoding of the buffer.
    1618   *
    1619   *Parses a buffer that contains an '\@charset' rule and
    1620   *creates an instance of #CRStatement of type AT_CHARSET_RULE_STMT.
    1621   *
    1622   *Returns the newly built instance of #CRStatement.
    1623   */
    1624  CRStatement *
    1625  cr_statement_at_charset_rule_parse_from_buf (const guchar * a_buf,
    1626                                               enum CREncoding a_encoding)
    1627  {
    1628          enum CRStatus status = CR_OK;
    1629          CRParser *parser = NULL;
    1630          CRStatement *result = NULL;
    1631          CRString *charset = NULL;
    1632  
    1633          g_return_val_if_fail (a_buf, NULL);
    1634  
    1635          parser = cr_parser_new_from_buf ((guchar*)a_buf, strlen ((const char *) a_buf),
    1636                                           a_encoding, FALSE);
    1637          if (!parser) {
    1638                  cr_utils_trace_info ("Instantiation of the parser failed.");
    1639                  goto cleanup;
    1640          }
    1641  
    1642          /*Now, invoke the parser to parse the "@charset production" */
    1643          cr_parser_try_to_skip_spaces_and_comments (parser);
    1644          if (status != CR_OK)
    1645                  goto cleanup;
    1646          status = cr_parser_parse_charset (parser, &charset, NULL);
    1647          if (status != CR_OK || !charset)
    1648                  goto cleanup;
    1649  
    1650          result = cr_statement_new_at_charset_rule (NULL, charset);
    1651          if (result)
    1652                  charset = NULL;
    1653  
    1654        cleanup:
    1655  
    1656          if (parser) {
    1657                  cr_parser_destroy (parser);
    1658                  parser = NULL;
    1659          }
    1660          if (charset) {
    1661                  cr_string_destroy (charset);
    1662          }
    1663  
    1664          return result;
    1665  }
    1666  
    1667  /**
    1668   * cr_statement_new_at_font_face_rule:
    1669   *
    1670   *@a_font_decls: a list of instances of #CRDeclaration. Each declaration
    1671   *is actually a font declaration.
    1672   *
    1673   *Creates an instance of #CRStatement of type #CRAtFontFaceRule.
    1674   *
    1675   *Returns the newly built instance of #CRStatement.
    1676   */
    1677  CRStatement *
    1678  cr_statement_new_at_font_face_rule (CRStyleSheet * a_sheet,
    1679                                      CRDeclaration * a_font_decls)
    1680  {
    1681          CRStatement *result = NULL;
    1682  
    1683          result = g_try_malloc (sizeof (CRStatement));
    1684  
    1685          if (!result) {
    1686                  cr_utils_trace_info ("Out of memory");
    1687                  return NULL;
    1688          }
    1689          memset (result, 0, sizeof (CRStatement));
    1690          result->type = AT_FONT_FACE_RULE_STMT;
    1691  
    1692          result->kind.font_face_rule = g_try_malloc
    1693                  (sizeof (CRAtFontFaceRule));
    1694  
    1695          if (!result->kind.font_face_rule) {
    1696                  cr_utils_trace_info ("Out of memory");
    1697                  g_free (result);
    1698                  return NULL;
    1699          }
    1700          memset (result->kind.font_face_rule, 0, sizeof (CRAtFontFaceRule));
    1701  
    1702          result->kind.font_face_rule->decl_list = a_font_decls;
    1703          if (a_sheet)
    1704                  cr_statement_set_parent_sheet (result, a_sheet);
    1705  
    1706          return result;
    1707  }
    1708  
    1709  /**
    1710   * cr_statement_font_face_rule_parse_from_buf:
    1711   *
    1712   *
    1713   *@a_buf: the buffer to parse.
    1714   *@a_encoding: the character encoding of a_buf.
    1715   *
    1716   *Parses a buffer that contains an "\@font-face" rule and builds
    1717   *an instance of #CRStatement of type AT_FONT_FACE_RULE_STMT out of it.
    1718   *
    1719   *Returns the newly built instance of #CRStatement in case of successufull
    1720   *parsing, NULL otherwise.
    1721   */
    1722  CRStatement *
    1723  cr_statement_font_face_rule_parse_from_buf (const guchar * a_buf,
    1724                                              enum CREncoding a_encoding)
    1725  {
    1726          CRStatement *result = NULL;
    1727          CRStatement **resultptr = NULL;
    1728          CRParser *parser = NULL;
    1729          CRDocHandler *sac_handler = NULL;
    1730          enum CRStatus status = CR_OK;
    1731  
    1732          parser = cr_parser_new_from_buf ((guchar*)a_buf, strlen ((const char *) a_buf),
    1733                                           a_encoding, FALSE);
    1734          if (!parser)
    1735                  goto cleanup;
    1736  
    1737          sac_handler = cr_doc_handler_new ();
    1738          if (!sac_handler)
    1739                  goto cleanup;
    1740  
    1741          /*
    1742           *set sac callbacks here
    1743           */
    1744          sac_handler->start_font_face = parse_font_face_start_font_face_cb;
    1745          sac_handler->property = parse_font_face_property_cb;
    1746          sac_handler->end_font_face = parse_font_face_end_font_face_cb;
    1747          sac_handler->unrecoverable_error =
    1748                  parse_font_face_unrecoverable_error_cb;
    1749  
    1750          status = cr_parser_set_sac_handler (parser, sac_handler);
    1751          if (status != CR_OK)
    1752                  goto cleanup;
    1753  
    1754          /*
    1755           *cleanup spaces of comment that may be there before the real
    1756           *"@font-face" thing.
    1757           */
    1758          status = cr_parser_try_to_skip_spaces_and_comments (parser);
    1759          if (status != CR_OK)
    1760                  goto cleanup;
    1761  
    1762          status = cr_parser_parse_font_face (parser);
    1763          if (status != CR_OK)
    1764                  goto cleanup;
    1765  
    1766  	resultptr = &result;
    1767          status = cr_doc_handler_get_result (sac_handler,
    1768                                              (gpointer *) resultptr);
    1769          if (status != CR_OK || !result)
    1770                  goto cleanup;
    1771  
    1772        cleanup:
    1773          if (parser) {
    1774                  cr_parser_destroy (parser);
    1775                  parser = NULL;
    1776                  sac_handler = NULL ;
    1777          }
    1778          if (sac_handler) {
    1779                  cr_doc_handler_unref (sac_handler);
    1780                  sac_handler = NULL;
    1781          }
    1782          return result;
    1783  }
    1784  
    1785  /**
    1786   * cr_statement_set_parent_sheet:
    1787   *
    1788   *@a_this: the current instance of #CRStatement.
    1789   *@a_sheet: the sheet that contains the current statement.
    1790   *
    1791   *Sets the container stylesheet.
    1792   *
    1793   *Returns CR_OK upon successful completion, an error code otherwise.
    1794   */
    1795  enum CRStatus
    1796  cr_statement_set_parent_sheet (CRStatement * a_this, CRStyleSheet * a_sheet)
    1797  {
    1798          g_return_val_if_fail (a_this, CR_BAD_PARAM_ERROR);
    1799          a_this->parent_sheet = a_sheet;
    1800          return CR_OK;
    1801  }
    1802  
    1803  /**
    1804   * cr_statement_get_parent_sheet:
    1805   *
    1806   *@a_this: the current #CRStatement.
    1807   *@a_sheet: out parameter. A pointer to the sheets that
    1808   *
    1809   *Gets the sheets that contains the current statement.
    1810   *
    1811   *Returns CR_OK upon successful completion, an error code otherwise.
    1812   */
    1813  enum CRStatus
    1814  cr_statement_get_parent_sheet (CRStatement * a_this, CRStyleSheet ** a_sheet)
    1815  {
    1816          g_return_val_if_fail (a_this && a_sheet, CR_BAD_PARAM_ERROR);
    1817          *a_sheet = a_this->parent_sheet;
    1818          return CR_OK;
    1819  }
    1820  
    1821  /**
    1822   * cr_statement_append:
    1823   *
    1824   *@a_this: the current instance of the statement list.
    1825   *@a_new: a_new the new instance of #CRStatement to append.
    1826   *
    1827   *Appends a new statement to the statement list.
    1828   *
    1829   *Returns the new list statement list, or NULL in cas of failure.
    1830   */
    1831  CRStatement *
    1832  cr_statement_append (CRStatement * a_this, CRStatement * a_new)
    1833  {
    1834          CRStatement *cur = NULL;
    1835  
    1836          g_return_val_if_fail (a_new, NULL);
    1837  
    1838          if (!a_this) {
    1839                  return a_new;
    1840          }
    1841  
    1842          /*walk forward in the current list to find the tail list element */
    1843          for (cur = a_this; cur && cur->next; cur = cur->next) ;
    1844  
    1845          cur->next = a_new;
    1846          a_new->prev = cur;
    1847  
    1848          return a_this;
    1849  }
    1850  
    1851  /**
    1852   * cr_statement_prepend:
    1853   *
    1854   *@a_this: the current instance of #CRStatement.
    1855   *@a_new: the new statement to prepend.
    1856   *
    1857   *Prepends the an instance of #CRStatement to
    1858   *the current statement list.
    1859   *
    1860   *Returns the new list with the new statement prepended,
    1861   *or NULL in case of an error.
    1862   */
    1863  CRStatement *
    1864  cr_statement_prepend (CRStatement * a_this, CRStatement * a_new)
    1865  {
    1866          CRStatement *cur = NULL;
    1867  
    1868          g_return_val_if_fail (a_new, NULL);
    1869  
    1870          if (!a_this)
    1871                  return a_new;
    1872  
    1873          a_new->next = a_this;
    1874          a_this->prev = a_new;
    1875  
    1876          /*walk backward in the prepended list to find the head list element */
    1877          for (cur = a_new; cur && cur->prev; cur = cur->prev) ;
    1878  
    1879          return cur;
    1880  }
    1881  
    1882  /**
    1883   * cr_statement_unlink:
    1884   *
    1885   *@a_this: the current statements list.
    1886   *@a_to_unlink: the statement to unlink from the list.
    1887   *
    1888   *Unlinks a statement from the statements list.
    1889   *
    1890   *Returns the new list where a_to_unlink has been unlinked
    1891   *from, or NULL in case of error.
    1892   */
    1893  CRStatement *
    1894  cr_statement_unlink (CRStatement * a_stmt)
    1895  {
    1896          CRStatement *result = a_stmt;
    1897  
    1898          g_return_val_if_fail (result, NULL);
    1899  
    1900          /**
    1901           *Some sanity checks first
    1902           */
    1903          if (a_stmt->next) {
    1904                  g_return_val_if_fail (a_stmt->next->prev == a_stmt, NULL);
    1905          }
    1906          if (a_stmt->prev) {
    1907                  g_return_val_if_fail (a_stmt->prev->next == a_stmt, NULL);
    1908          }
    1909  
    1910          /**
    1911           *Now, the real unlinking job.
    1912           */
    1913          if (a_stmt->next) {
    1914                  a_stmt->next->prev = a_stmt->prev;
    1915          }
    1916          if (a_stmt->prev) {
    1917                  a_stmt->prev->next = a_stmt->next;
    1918          }
    1919  
    1920          if (a_stmt->parent_sheet
    1921              && a_stmt->parent_sheet->statements == a_stmt) {
    1922                  a_stmt->parent_sheet->statements =
    1923                          a_stmt->parent_sheet->statements->next;
    1924          }
    1925  
    1926          a_stmt->next = NULL;
    1927          a_stmt->prev = NULL;
    1928          a_stmt->parent_sheet = NULL;
    1929  
    1930          return result;
    1931  }
    1932  
    1933  /**
    1934   * cr_statement_nr_rules:
    1935   *
    1936   *@a_this: the current instance of #CRStatement.
    1937   *
    1938   *Gets the number of rules in the statement list;
    1939   *
    1940   *Returns number of rules in the statement list.
    1941   */
    1942  gint
    1943  cr_statement_nr_rules (CRStatement const * a_this)
    1944  {
    1945          CRStatement const *cur = NULL;
    1946          int nr = 0;
    1947  
    1948          g_return_val_if_fail (a_this, -1);
    1949  
    1950          for (cur = a_this; cur; cur = cur->next)
    1951                  nr++;
    1952          return nr;
    1953  }
    1954  
    1955  /**
    1956   * cr_statement_get_from_list:
    1957   *
    1958   *@a_this: the current instance of #CRStatement.
    1959   *@itemnr: the index into the statement list.
    1960   *
    1961   *Use an index to get a CRStatement from the statement list.
    1962   *
    1963   *Returns CRStatement at position itemnr, if itemnr > number of statements - 1,
    1964   *it will return NULL.
    1965   */
    1966  CRStatement *
    1967  cr_statement_get_from_list (CRStatement * a_this, int itemnr)
    1968  {
    1969          CRStatement *cur = NULL;
    1970          int nr = 0;
    1971  
    1972          g_return_val_if_fail (a_this, NULL);
    1973  
    1974          for (cur = a_this; cur; cur = cur->next)
    1975                  if (nr++ == itemnr)
    1976                          return cur;
    1977          return NULL;
    1978  }
    1979  
    1980  /**
    1981   * cr_statement_ruleset_set_sel_list:
    1982   *
    1983   *@a_this: the current ruleset statement.
    1984   *@a_sel_list: the selector list to set. Note
    1985   *that this function increments the ref count of a_sel_list.
    1986   *The sel list will be destroyed at the destruction of the
    1987   *current instance of #CRStatement.
    1988   *
    1989   *Sets a selector list to a ruleset statement.
    1990   *
    1991   *Returns CR_OK upon successful completion, an error code otherwise.
    1992   */
    1993  enum CRStatus
    1994  cr_statement_ruleset_set_sel_list (CRStatement * a_this,
    1995                                     CRSelector * a_sel_list)
    1996  {
    1997          g_return_val_if_fail (a_this && a_this->type == RULESET_STMT,
    1998                                CR_BAD_PARAM_ERROR);
    1999  
    2000          if (a_this->kind.ruleset->sel_list)
    2001                  cr_selector_unref (a_this->kind.ruleset->sel_list);
    2002  
    2003          a_this->kind.ruleset->sel_list = a_sel_list;
    2004  
    2005          if (a_sel_list)
    2006                  cr_selector_ref (a_sel_list);
    2007  
    2008          return CR_OK;
    2009  }
    2010  
    2011  /**
    2012   * cr_statement_ruleset_get_declarations:
    2013   *
    2014   *@a_this: the current instance of #CRStatement.
    2015   *@a_decl_list: out parameter. A pointer to the the returned
    2016   *list of declaration. Must not be NULL.
    2017   *
    2018   *Gets a pointer to the list of declaration contained
    2019   *in the ruleset statement.
    2020   *
    2021   *Returns CR_OK upon successful completion, an error code if something
    2022   *bad happened.
    2023   */
    2024  enum CRStatus
    2025  cr_statement_ruleset_get_declarations (CRStatement * a_this,
    2026                                         CRDeclaration ** a_decl_list)
    2027  {
    2028          g_return_val_if_fail (a_this
    2029                                && a_this->type == RULESET_STMT
    2030                                && a_this->kind.ruleset
    2031                                && a_decl_list, CR_BAD_PARAM_ERROR);
    2032  
    2033          *a_decl_list = a_this->kind.ruleset->decl_list;
    2034  
    2035          return CR_OK;
    2036  }
    2037  
    2038  /**
    2039   * cr_statement_ruleset_get_sel_list:
    2040   *
    2041   *@a_this: the current ruleset statement.
    2042   *@a_list: out parameter. The returned selector list,
    2043   *if and only if the function returned CR_OK.
    2044   *
    2045   *Gets a pointer to the selector list contained in
    2046   *the current ruleset statement.
    2047   *
    2048   *Returns CR_OK upon successful completion, an error code otherwise.
    2049   */
    2050  enum CRStatus
    2051  cr_statement_ruleset_get_sel_list (CRStatement const * a_this, CRSelector ** a_list)
    2052  {
    2053          g_return_val_if_fail (a_this && a_this->type == RULESET_STMT
    2054                                && a_this->kind.ruleset, CR_BAD_PARAM_ERROR);
    2055  
    2056          *a_list = a_this->kind.ruleset->sel_list;
    2057  
    2058          return CR_OK;
    2059  }
    2060  
    2061  /**
    2062   * cr_statement_ruleset_set_decl_list:
    2063   *
    2064   *@a_this: the current ruleset statement.
    2065   *@a_list: the declaration list to be added to the current
    2066   *ruleset statement.
    2067   *
    2068   *Sets a declaration list to the current ruleset statement.
    2069   *
    2070   *Returns CR_OK upon successful completion, an error code otherwise.
    2071   */
    2072  enum CRStatus
    2073  cr_statement_ruleset_set_decl_list (CRStatement * a_this,
    2074                                      CRDeclaration * a_list)
    2075  {
    2076          g_return_val_if_fail (a_this && a_this->type == RULESET_STMT
    2077                                && a_this->kind.ruleset, CR_BAD_PARAM_ERROR);
    2078  
    2079          if (a_this->kind.ruleset->decl_list == a_list)
    2080                  return CR_OK;
    2081  
    2082          if (a_this->kind.ruleset->sel_list) {
    2083                  cr_declaration_destroy (a_this->kind.ruleset->decl_list);
    2084          }
    2085  
    2086          a_this->kind.ruleset->sel_list = NULL;
    2087  
    2088          return CR_OK;
    2089  }
    2090  
    2091  /**
    2092   * cr_statement_ruleset_append_decl2:
    2093   *
    2094   *@a_this: the current statement.
    2095   *@a_prop: the property of the declaration.
    2096   *@a_value: the value of the declaration.
    2097   *
    2098   *Appends a declaration to the current ruleset statement.
    2099   *
    2100   *Returns CR_OK upon successful completion, an error code
    2101   *otherwise.
    2102   */
    2103  enum CRStatus
    2104  cr_statement_ruleset_append_decl2 (CRStatement * a_this,
    2105                                     CRString * a_prop, 
    2106                                     CRTerm * a_value)
    2107  {
    2108          CRDeclaration *new_decls = NULL;
    2109  
    2110          g_return_val_if_fail (a_this && a_this->type == RULESET_STMT
    2111                                && a_this->kind.ruleset, CR_BAD_PARAM_ERROR);
    2112  
    2113          new_decls = cr_declaration_append2
    2114                  (a_this->kind.ruleset->decl_list, 
    2115                   a_prop, a_value);
    2116          g_return_val_if_fail (new_decls, CR_ERROR);
    2117          a_this->kind.ruleset->decl_list = new_decls;
    2118  
    2119          return CR_OK;
    2120  }
    2121  
    2122  /**
    2123   * cr_statement_ruleset_append_decl:
    2124   *
    2125   *Appends a declaration to the current statement.
    2126   *
    2127   *@a_this: the current statement.
    2128   *@a_declaration: the declaration to append.
    2129   *
    2130   *Returns CR_OK upon sucessful completion, an error code
    2131   *otherwise.
    2132   */
    2133  enum CRStatus
    2134  cr_statement_ruleset_append_decl (CRStatement * a_this,
    2135                                    CRDeclaration * a_decl)
    2136  {
    2137          CRDeclaration *new_decls = NULL;
    2138  
    2139          g_return_val_if_fail (a_this && a_this->type == RULESET_STMT
    2140                                && a_this->kind.ruleset, CR_BAD_PARAM_ERROR);
    2141  
    2142          new_decls = cr_declaration_append
    2143                  (a_this->kind.ruleset->decl_list, a_decl);
    2144          g_return_val_if_fail (new_decls, CR_ERROR);
    2145          a_this->kind.ruleset->decl_list = new_decls;
    2146  
    2147          return CR_OK;
    2148  }
    2149  
    2150  /**
    2151   * cr_statement_at_import_rule_set_imported_sheet:
    2152   *
    2153   *Sets a stylesheet to the current \@import rule.
    2154   *@a_this: the current \@import rule.
    2155   *@a_sheet: the stylesheet. The stylesheet is owned
    2156   *by the current instance of #CRStatement, that is, the 
    2157   *stylesheet will be destroyed when the current instance
    2158   *of #CRStatement is destroyed.
    2159   *
    2160   *Returns CR_OK upon successful completion, an error code otherwise.
    2161   */
    2162  enum CRStatus
    2163  cr_statement_at_import_rule_set_imported_sheet (CRStatement * a_this,
    2164                                                  CRStyleSheet * a_sheet)
    2165  {
    2166          g_return_val_if_fail (a_this
    2167                                && a_this->type == AT_IMPORT_RULE_STMT
    2168                                && a_this->kind.import_rule,
    2169                                CR_BAD_PARAM_ERROR);
    2170  
    2171          a_this->kind.import_rule->sheet = a_sheet;
    2172  
    2173          return CR_OK;
    2174  }
    2175  
    2176  /**
    2177   * cr_statement_at_import_rule_get_imported_sheet:
    2178   *
    2179   *@a_this: the current \@import rule statement.
    2180   *@a_sheet: out parameter. The returned stylesheet if and
    2181   *only if the function returns CR_OK.
    2182   *
    2183   *Gets the stylesheet contained by the \@import rule statement.
    2184   *Returns CR_OK upon sucessful completion, an error code otherwise.
    2185   */
    2186  enum CRStatus
    2187  cr_statement_at_import_rule_get_imported_sheet (CRStatement * a_this,
    2188                                                  CRStyleSheet ** a_sheet)
    2189  {
    2190          g_return_val_if_fail (a_this
    2191                                && a_this->type == AT_IMPORT_RULE_STMT
    2192                                && a_this->kind.import_rule,
    2193                                CR_BAD_PARAM_ERROR);
    2194          *a_sheet = a_this->kind.import_rule->sheet;
    2195          return CR_OK;
    2196  
    2197  }
    2198  
    2199  /**
    2200   * cr_statement_at_import_rule_set_url:
    2201   *
    2202   *@a_this: the current \@import rule statement.
    2203   *@a_url: the url to set.
    2204   *
    2205   *Sets an url to the current \@import rule statement.
    2206   *
    2207   *Returns CR_OK upon successful completion, an error code otherwise.
    2208   */
    2209  enum CRStatus
    2210  cr_statement_at_import_rule_set_url (CRStatement * a_this, 
    2211                                       CRString * a_url)
    2212  {
    2213          g_return_val_if_fail (a_this
    2214                                && a_this->type == AT_IMPORT_RULE_STMT
    2215                                && a_this->kind.import_rule,
    2216                                CR_BAD_PARAM_ERROR);
    2217  
    2218          if (a_this->kind.import_rule->url) {
    2219                  cr_string_destroy (a_this->kind.import_rule->url);
    2220          }
    2221  
    2222          a_this->kind.import_rule->url = a_url;
    2223  
    2224          return CR_OK;
    2225  }
    2226  
    2227  /**
    2228   * cr_statement_at_import_rule_get_url:
    2229   *
    2230   *@a_this: the current \@import rule statement.
    2231   *@a_url: out parameter. The returned url if
    2232   *and only if the function returned CR_OK.
    2233   *
    2234   *Gets the url of the \@import rule statement.
    2235   *Returns CR_OK upon successful completion, an error code otherwise.
    2236   */
    2237  enum CRStatus
    2238  cr_statement_at_import_rule_get_url (CRStatement const * a_this,
    2239                                       CRString ** a_url)
    2240  {
    2241          g_return_val_if_fail (a_this
    2242                                && a_this->type == AT_IMPORT_RULE_STMT
    2243                                && a_this->kind.import_rule,
    2244                                CR_BAD_PARAM_ERROR);
    2245  
    2246          *a_url = a_this->kind.import_rule->url;
    2247  
    2248          return CR_OK;
    2249  }
    2250  
    2251  /**
    2252   * cr_statement_at_media_nr_rules:
    2253   *
    2254   *@a_this: the current instance of #CRStatement.
    2255   *
    2256   *Returns the number of rules in the media rule;
    2257   */
    2258  int
    2259  cr_statement_at_media_nr_rules (CRStatement const * a_this)
    2260  {
    2261          g_return_val_if_fail (a_this
    2262                                && a_this->type == AT_MEDIA_RULE_STMT
    2263                                && a_this->kind.media_rule, CR_BAD_PARAM_ERROR);
    2264  
    2265          return cr_statement_nr_rules (a_this->kind.media_rule->rulesets);
    2266  }
    2267  
    2268  /**
    2269   * cr_statement_at_media_get_from_list:
    2270   *
    2271   *@a_this: the current instance of #CRStatement.
    2272   *@itemnr: the index into the media rule list of rules.
    2273   *
    2274   *Use an index to get a CRStatement from the media rule list of rules.
    2275   *
    2276   *Returns CRStatement at position itemnr, if itemnr > number of rules - 1,
    2277   *it will return NULL.
    2278   */
    2279  CRStatement *
    2280  cr_statement_at_media_get_from_list (CRStatement * a_this, int itemnr)
    2281  {
    2282          g_return_val_if_fail (a_this
    2283                                && a_this->type == AT_MEDIA_RULE_STMT
    2284                                && a_this->kind.media_rule, NULL);
    2285  
    2286          return cr_statement_get_from_list (a_this->kind.media_rule->rulesets,
    2287                                             itemnr);
    2288  }
    2289  
    2290  /**
    2291   * cr_statement_at_page_rule_set_declarations:
    2292   *
    2293   *@a_this: the current \@page rule statement.
    2294   *@a_decl_list: the declaration list to add. Will be freed
    2295   *by the current instance of #CRStatement when it is destroyed.
    2296   *
    2297   *Sets a declaration list to the current \@page rule statement.
    2298   *
    2299   *Returns CR_OK upon successful completion, an error code otherwise.
    2300   */
    2301  enum CRStatus
    2302  cr_statement_at_page_rule_set_declarations (CRStatement * a_this,
    2303                                              CRDeclaration * a_decl_list)
    2304  {
    2305          g_return_val_if_fail (a_this
    2306                                && a_this->type == AT_PAGE_RULE_STMT
    2307                                && a_this->kind.page_rule, CR_BAD_PARAM_ERROR);
    2308  
    2309          if (a_this->kind.page_rule->decl_list) {
    2310                  cr_declaration_unref (a_this->kind.page_rule->decl_list);
    2311          }
    2312  
    2313          a_this->kind.page_rule->decl_list = a_decl_list;
    2314  
    2315          if (a_decl_list) {
    2316                  cr_declaration_ref (a_decl_list);
    2317          }
    2318  
    2319          return CR_OK;
    2320  }
    2321  
    2322  /**
    2323   * cr_statement_at_page_rule_get_declarations:
    2324   *
    2325   *@a_this: the current \@page rule statement.
    2326   *@a_decl_list: out parameter. The returned declaration list.
    2327   *
    2328   *Gets the declaration list associated to the current \@page rule
    2329   *statement.
    2330   *
    2331   *Returns CR_OK upon successful completion, an error code otherwise.
    2332   */
    2333  enum CRStatus
    2334  cr_statement_at_page_rule_get_declarations (CRStatement * a_this,
    2335                                              CRDeclaration ** a_decl_list)
    2336  {
    2337          g_return_val_if_fail (a_this
    2338                                && a_this->type == AT_PAGE_RULE_STMT
    2339                                && a_this->kind.page_rule, CR_BAD_PARAM_ERROR);
    2340  
    2341          *a_decl_list = a_this->kind.page_rule->decl_list;
    2342  
    2343          return CR_OK;
    2344  }
    2345  
    2346  /**
    2347   * cr_statement_at_charset_rule_set_charset:
    2348   *
    2349   *
    2350   *@a_this: the current \@charset rule statement.
    2351   *@a_charset: the charset to set.
    2352   *
    2353   *Sets the charset of the current \@charset rule statement.
    2354   *
    2355   *Returns CR_OK upon successful completion, an error code otherwise.
    2356   */
    2357  enum CRStatus
    2358  cr_statement_at_charset_rule_set_charset (CRStatement * a_this,
    2359                                            CRString * a_charset)
    2360  {
    2361          g_return_val_if_fail (a_this
    2362                                && a_this->type == AT_CHARSET_RULE_STMT
    2363                                && a_this->kind.charset_rule,
    2364                                CR_BAD_PARAM_ERROR);
    2365  
    2366          if (a_this->kind.charset_rule->charset) {
    2367                  cr_string_destroy (a_this->kind.charset_rule->charset);
    2368          }
    2369          a_this->kind.charset_rule->charset = a_charset;
    2370          return CR_OK;
    2371  }
    2372  
    2373  /**
    2374   * cr_statement_at_charset_rule_get_charset:
    2375   *@a_this: the current \@charset rule statement.
    2376   *@a_charset: out parameter. The returned charset string if
    2377   *and only if the function returned CR_OK.
    2378   *
    2379   *Gets the charset string associated to the current
    2380   *\@charset rule statement.
    2381   *
    2382   * Returns CR_OK upon successful completion, an error code otherwise.
    2383   */
    2384  enum CRStatus
    2385  cr_statement_at_charset_rule_get_charset (CRStatement const * a_this,
    2386                                            CRString ** a_charset)
    2387  {
    2388          g_return_val_if_fail (a_this
    2389                                && a_this->type == AT_CHARSET_RULE_STMT
    2390                                && a_this->kind.charset_rule,
    2391                                CR_BAD_PARAM_ERROR);
    2392  
    2393          *a_charset = a_this->kind.charset_rule->charset;
    2394  
    2395          return CR_OK;
    2396  }
    2397  
    2398  /**
    2399   * cr_statement_at_font_face_rule_set_decls:
    2400   *
    2401   *@a_this: the current \@font-face rule statement.
    2402   *@a_decls: the declarations list to set.
    2403   *
    2404   *Sets a declaration list to the current \@font-face rule statement.
    2405   *
    2406   *Returns CR_OK upon successful completion, an error code otherwise.
    2407   */
    2408  enum CRStatus
    2409  cr_statement_at_font_face_rule_set_decls (CRStatement * a_this,
    2410                                            CRDeclaration * a_decls)
    2411  {
    2412          g_return_val_if_fail (a_this
    2413                                && a_this->type == AT_FONT_FACE_RULE_STMT
    2414                                && a_this->kind.font_face_rule,
    2415                                CR_BAD_PARAM_ERROR);
    2416  
    2417          if (a_this->kind.font_face_rule->decl_list) {
    2418                  cr_declaration_unref (a_this->kind.font_face_rule->decl_list);
    2419          }
    2420  
    2421          a_this->kind.font_face_rule->decl_list = a_decls;
    2422          cr_declaration_ref (a_decls);
    2423  
    2424          return CR_OK;
    2425  }
    2426  
    2427  /**
    2428   * cr_statement_at_font_face_rule_get_decls:
    2429   *
    2430   *@a_this: the current \@font-face rule statement.
    2431   *@a_decls: out parameter. The returned declaration list if
    2432   *and only if this function returns CR_OK.
    2433   *
    2434   *Gets the declaration list associated to the current instance
    2435   *of \@font-face rule statement.
    2436   *
    2437   *Returns CR_OK upon successful completion, an error code otherwise.
    2438   */
    2439  enum CRStatus
    2440  cr_statement_at_font_face_rule_get_decls (CRStatement * a_this,
    2441                                            CRDeclaration ** a_decls)
    2442  {
    2443          g_return_val_if_fail (a_this
    2444                                && a_this->type == AT_FONT_FACE_RULE_STMT
    2445                                && a_this->kind.font_face_rule,
    2446                                CR_BAD_PARAM_ERROR);
    2447  
    2448          *a_decls = a_this->kind.font_face_rule->decl_list;
    2449  
    2450          return CR_OK;
    2451  }
    2452  
    2453  /**
    2454   * cr_statement_at_font_face_rule_add_decl:
    2455   *
    2456   *@a_this: the current \@font-face rule statement.
    2457   *@a_prop: the property of the declaration.
    2458   *@a_value: the value of the declaration.
    2459   *
    2460   *Adds a declaration to the current \@font-face rule
    2461   *statement.
    2462   *
    2463   *Returns CR_OK upon successful completion, an error code otherwise.
    2464   */
    2465  enum CRStatus
    2466  cr_statement_at_font_face_rule_add_decl (CRStatement * a_this,
    2467                                           CRString * a_prop, CRTerm * a_value)
    2468  {
    2469          CRDeclaration *decls = NULL;
    2470  
    2471          g_return_val_if_fail (a_this
    2472                                && a_this->type == AT_FONT_FACE_RULE_STMT
    2473                                && a_this->kind.font_face_rule,
    2474                                CR_BAD_PARAM_ERROR);
    2475  
    2476          decls = cr_declaration_append2
    2477                  (a_this->kind.font_face_rule->decl_list, 
    2478                   a_prop, a_value);
    2479  
    2480          g_return_val_if_fail (decls, CR_ERROR);
    2481  
    2482          if (a_this->kind.font_face_rule->decl_list == NULL)
    2483                  cr_declaration_ref (decls);
    2484  
    2485          a_this->kind.font_face_rule->decl_list = decls;
    2486  
    2487          return CR_OK;
    2488  }
    2489  
    2490  
    2491  /**
    2492   * cr_statement_to_string:
    2493   *
    2494   *@a_this: the current statement to serialize
    2495   *@a_indent: the number of white space of indentation.
    2496   *
    2497   *Serializes a css statement into a string
    2498   *
    2499   *Returns the serialized statement. Must be freed by the caller
    2500   *using g_free().
    2501   */
    2502  gchar *
    2503  cr_statement_to_string (CRStatement const * a_this, gulong a_indent)
    2504  {
    2505          gchar *str = NULL ;
    2506  
    2507          if (!a_this)
    2508                  return NULL;
    2509  
    2510          switch (a_this->type) {
    2511          case RULESET_STMT:
    2512                  str = cr_statement_ruleset_to_string 
    2513                          (a_this, a_indent);
    2514                  break;
    2515  
    2516          case AT_FONT_FACE_RULE_STMT:
    2517                  str = cr_statement_font_face_rule_to_string 
    2518                          (a_this, a_indent) ;
    2519                  break;
    2520  
    2521          case AT_CHARSET_RULE_STMT:
    2522                  str = cr_statement_charset_to_string
    2523                          (a_this, a_indent);                
    2524                  break;
    2525  
    2526          case AT_PAGE_RULE_STMT:
    2527                  str = cr_statement_at_page_rule_to_string
    2528                          (a_this, a_indent);
    2529                  break;
    2530  
    2531          case AT_MEDIA_RULE_STMT:
    2532                  str = cr_statement_media_rule_to_string
    2533                          (a_this, a_indent);
    2534                  break;
    2535  
    2536          case AT_IMPORT_RULE_STMT:
    2537                  str = cr_statement_import_rule_to_string
    2538                          (a_this, a_indent);
    2539                  break;
    2540  
    2541          default:
    2542                  cr_utils_trace_info ("Statement unrecognized");
    2543                  break;
    2544          }
    2545          return str ;
    2546  }
    2547  
    2548  gchar*
    2549  cr_statement_list_to_string (CRStatement const *a_this, gulong a_indent)
    2550  {
    2551          CRStatement const *cur_stmt = NULL ;
    2552          GString *stringue = NULL ;
    2553          gchar *str = NULL ;
    2554  
    2555          g_return_val_if_fail (a_this, NULL) ;
    2556  
    2557          stringue = g_string_new (NULL) ;
    2558          if (!stringue) {
    2559                  cr_utils_trace_info ("Out of memory") ;
    2560                  return NULL ;
    2561          }
    2562          for (cur_stmt = a_this ; cur_stmt;
    2563               cur_stmt = cur_stmt->next) {
    2564                  str = cr_statement_to_string (cur_stmt, a_indent) ;
    2565                  if (str) {
    2566                          if (!cur_stmt->prev) {
    2567                                  g_string_append (stringue, str) ;
    2568                          } else {
    2569                                  g_string_append_printf 
    2570                                          (stringue, "\n%s", str) ;
    2571                          }
    2572                          g_free (str) ;
    2573                          str = NULL ;
    2574                  }                
    2575          }
    2576          str = stringue->str ;
    2577          g_string_free (stringue, FALSE) ;
    2578          return str ;
    2579  }
    2580  
    2581  /**
    2582   * cr_statement_dump:
    2583   *
    2584   *@a_this: the current css2 statement.
    2585   *@a_fp: the destination file pointer.
    2586   *@a_indent: the number of white space indentation characters.
    2587   *
    2588   *Dumps the css2 statement to a file.
    2589   */
    2590  void
    2591  cr_statement_dump (CRStatement const * a_this, FILE * a_fp, gulong a_indent)
    2592  {
    2593          gchar *str = NULL ;
    2594  
    2595          if (!a_this)
    2596                  return;
    2597  
    2598          str = cr_statement_to_string (a_this, a_indent) ;
    2599          if (str) {
    2600                  fprintf (a_fp, "%s",str) ;
    2601                  g_free (str) ;
    2602                  str = NULL ;
    2603          }
    2604  }
    2605  
    2606  /**
    2607   * cr_statement_dump_ruleset:
    2608   *
    2609   *@a_this: the current instance of #CRStatement.
    2610   *@a_fp: the destination file pointer.
    2611   *@a_indent: the number of indentation white spaces to add.
    2612   *
    2613   *Dumps a ruleset statement to a file.
    2614   */
    2615  void
    2616  cr_statement_dump_ruleset (CRStatement const * a_this, FILE * a_fp, glong a_indent)
    2617  {
    2618          gchar *str = NULL;
    2619  
    2620          g_return_if_fail (a_fp && a_this);
    2621          str = cr_statement_ruleset_to_string (a_this, a_indent);
    2622          if (str) {
    2623                  fprintf (a_fp, "%s", str);
    2624                  g_free (str);
    2625                  str = NULL;
    2626          }
    2627  }
    2628  
    2629  /**
    2630   * cr_statement_dump_font_face_rule:
    2631   *
    2632   *@a_this: the current instance of font face rule statement.
    2633   *@a_fp: the destination file pointer.
    2634   *@a_indent: the number of white space indentation.
    2635   *
    2636   *Dumps a font face rule statement to a file.
    2637   */
    2638  void
    2639  cr_statement_dump_font_face_rule (CRStatement const * a_this, FILE * a_fp,
    2640                                    glong a_indent)
    2641  {
    2642          gchar *str = NULL ;
    2643          g_return_if_fail (a_this 
    2644                            && a_this->type == AT_FONT_FACE_RULE_STMT);
    2645  
    2646          str = cr_statement_font_face_rule_to_string (a_this,
    2647                                                       a_indent) ;
    2648          if (str) {
    2649                  fprintf (a_fp, "%s", str) ;
    2650                  g_free (str) ;
    2651                  str = NULL ;
    2652          }
    2653  }
    2654  
    2655  /**
    2656   * cr_statement_dump_charset:
    2657   *
    2658   *@a_this: the current instance of the \@charset rule statement.
    2659   *@a_fp: the destination file pointer.
    2660   *@a_indent: the number of indentation white spaces.
    2661   *
    2662   *Dumps an \@charset rule statement to a file.
    2663   */
    2664  void
    2665  cr_statement_dump_charset (CRStatement const * a_this, FILE * a_fp, gulong a_indent)
    2666  {
    2667          gchar *str = NULL;
    2668  
    2669          g_return_if_fail (a_this && a_this->type == AT_CHARSET_RULE_STMT);
    2670  
    2671          str = cr_statement_charset_to_string (a_this,
    2672                                                a_indent) ;
    2673          if (str) {
    2674                  fprintf (a_fp, "%s", str) ;
    2675                  g_free (str) ;
    2676                  str = NULL ;
    2677          }
    2678  }
    2679  
    2680  
    2681  /**
    2682   * cr_statement_dump_page:
    2683   *
    2684   *@a_this: the statement to dump on stdout.
    2685   *@a_fp: the destination file pointer.
    2686   *@a_indent: the number of indentation white spaces.
    2687   *
    2688   *Dumps an \@page rule statement on stdout.
    2689   */
    2690  void
    2691  cr_statement_dump_page (CRStatement const * a_this, FILE * a_fp, gulong a_indent)
    2692  {
    2693          gchar *str = NULL;
    2694  
    2695          g_return_if_fail (a_this
    2696                            && a_this->type == AT_PAGE_RULE_STMT
    2697                            && a_this->kind.page_rule);
    2698  
    2699          str = cr_statement_at_page_rule_to_string (a_this, a_indent) ;
    2700          if (str) {
    2701                  fprintf (a_fp, "%s", str);
    2702                  g_free (str) ;
    2703                  str = NULL ; 
    2704          }
    2705  }
    2706  
    2707  
    2708  /**
    2709   * cr_statement_dump_media_rule:
    2710   *
    2711   *@a_this: the statement to dump.
    2712   *@a_fp: the destination file pointer
    2713   *@a_indent: the number of white spaces indentation.
    2714   *
    2715   *Dumps an \@media rule statement to a file.
    2716   */
    2717  void
    2718  cr_statement_dump_media_rule (CRStatement const * a_this,
    2719                                FILE * a_fp,
    2720                                gulong a_indent)
    2721  {
    2722          gchar *str = NULL ;
    2723          g_return_if_fail (a_this->type == AT_MEDIA_RULE_STMT);
    2724  
    2725          str = cr_statement_media_rule_to_string (a_this, a_indent) ;
    2726          if (str) {
    2727                  fprintf (a_fp, "%s", str) ;
    2728                  g_free (str) ;
    2729                  str = NULL ;
    2730          }
    2731  }
    2732  
    2733  /**
    2734   * cr_statement_dump_import_rule:
    2735   *
    2736   *@a_fp: the destination file pointer.
    2737   *@a_indent: the number of white space indentations.
    2738   *
    2739   *Dumps an \@import rule statement to a file.
    2740   */
    2741  void
    2742  cr_statement_dump_import_rule (CRStatement const * a_this, FILE * a_fp,
    2743                                 gulong a_indent)
    2744  {
    2745          gchar *str = NULL ;
    2746          g_return_if_fail (a_this
    2747                            && a_this->type == AT_IMPORT_RULE_STMT
    2748                            && a_fp
    2749                            && a_this->kind.import_rule);
    2750  
    2751          str = cr_statement_import_rule_to_string (a_this, a_indent) ;
    2752          if (str) {
    2753                  fprintf (a_fp, "%s", str) ;
    2754                  g_free (str) ;
    2755                  str = NULL ;
    2756          }
    2757  }
    2758  
    2759  /**
    2760   * cr_statement_destroy:
    2761   *
    2762   * @a_this: the current instance of #CRStatement.
    2763   *
    2764   *Destructor of #CRStatement.
    2765   */
    2766  void
    2767  cr_statement_destroy (CRStatement * a_this)
    2768  {
    2769          CRStatement *cur = NULL;
    2770  
    2771          g_return_if_fail (a_this);
    2772  
    2773          /*go get the tail of the list */
    2774          for (cur = a_this; cur && cur->next; cur = cur->next) {
    2775                  cr_statement_clear (cur);
    2776          }
    2777  
    2778          if (cur)
    2779                  cr_statement_clear (cur);
    2780  
    2781          if (cur->prev == NULL) {
    2782                  g_free (a_this);
    2783                  return;
    2784          }
    2785  
    2786          /*walk backward and free next element */
    2787          for (cur = cur->prev; cur && cur->prev; cur = cur->prev) {
    2788                  if (cur->next) {
    2789                          g_free (cur->next);
    2790                          cur->next = NULL;
    2791                  }
    2792          }
    2793  
    2794          if (!cur)
    2795                  return;
    2796  
    2797          /*free the one remaining list */
    2798          if (cur->next) {
    2799                  g_free (cur->next);
    2800                  cur->next = NULL;
    2801          }
    2802  
    2803          g_free (cur);
    2804          cur = NULL;
    2805  }