| /* -*- Mode: C; indent-tabs-mode: nil; c-basic-offset: 8 -*- */ |
| |
| /* libcroco - Library for parsing and applying CSS |
| * Copyright (C) 2006-2019 Free Software Foundation, Inc. |
| * |
| * This file is not part of the GNU gettext program, but is used with |
| * GNU gettext. |
| * |
| * The original copyright notice is as follows: |
| */ |
| |
| /* |
| * This file is part of The Croco Library |
| * |
| * Copyright (C) 2003-2004 Dodji Seketeli. All Rights Reserved. |
| * |
| * This program is free software; you can redistribute it and/or |
| * modify it under the terms of version 2.1 of the GNU Lesser General Public |
| * License as published by the Free Software Foundation. |
| * |
| * This program is distributed in the hope that it will be useful, |
| * but WITHOUT ANY WARRANTY; without even the implied warranty of |
| * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| * GNU General Public License for more details. |
| * |
| * You should have received a copy of the GNU Lesser General Public License |
| * along with this program; if not, write to the Free Software |
| * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 |
| * USA |
| * |
| * Author: Dodji Seketeli. |
| */ |
| |
| #include <config.h> |
| #include <string.h> |
| #include "cr-statement.h" |
| #include "cr-parser.h" |
| |
| /** |
| *@file |
| *Definition of the #CRStatement class. |
| */ |
| |
| #define DECLARATION_INDENT_NB 2 |
| |
| static void cr_statement_clear (CRStatement * a_this); |
| |
| static void |
| parse_font_face_start_font_face_cb (CRDocHandler * a_this, |
| CRParsingLocation *a_location) |
| { |
| CRStatement *stmt = NULL; |
| enum CRStatus status = CR_OK; |
| |
| stmt = cr_statement_new_at_font_face_rule (NULL, NULL); |
| g_return_if_fail (stmt); |
| |
| status = cr_doc_handler_set_ctxt (a_this, stmt); |
| g_return_if_fail (status == CR_OK); |
| } |
| |
| static void |
| parse_font_face_unrecoverable_error_cb (CRDocHandler * a_this) |
| { |
| CRStatement *stmt = NULL; |
| CRStatement **stmtptr = NULL; |
| enum CRStatus status = CR_OK; |
| |
| g_return_if_fail (a_this); |
| |
| stmtptr = &stmt; |
| status = cr_doc_handler_get_ctxt (a_this, (gpointer *) stmtptr); |
| if (status != CR_OK) { |
| cr_utils_trace_info ("Couldn't get parsing context. " |
| "This may lead to some memory leaks."); |
| return; |
| } |
| if (stmt) { |
| cr_statement_destroy (stmt); |
| cr_doc_handler_set_ctxt (a_this, NULL); |
| return; |
| } |
| } |
| |
| static void |
| parse_font_face_property_cb (CRDocHandler * a_this, |
| CRString * a_name, |
| CRTerm * a_value, gboolean a_important) |
| { |
| enum CRStatus status = CR_OK; |
| CRString *name = NULL; |
| CRDeclaration *decl = NULL; |
| CRStatement *stmt = NULL; |
| CRStatement **stmtptr = NULL; |
| |
| g_return_if_fail (a_this && a_name); |
| |
| stmtptr = &stmt; |
| status = cr_doc_handler_get_ctxt (a_this, (gpointer *) stmtptr); |
| g_return_if_fail (status == CR_OK && stmt); |
| g_return_if_fail (stmt->type == AT_FONT_FACE_RULE_STMT); |
| |
| name = cr_string_dup (a_name) ; |
| g_return_if_fail (name); |
| decl = cr_declaration_new (stmt, name, a_value); |
| if (!decl) { |
| cr_utils_trace_info ("cr_declaration_new () failed."); |
| goto error; |
| } |
| name = NULL; |
| |
| stmt->kind.font_face_rule->decl_list = |
| cr_declaration_append (stmt->kind.font_face_rule->decl_list, |
| decl); |
| if (!stmt->kind.font_face_rule->decl_list) |
| goto error; |
| decl = NULL; |
| |
| error: |
| if (decl) { |
| cr_declaration_unref (decl); |
| decl = NULL; |
| } |
| if (name) { |
| cr_string_destroy (name); |
| name = NULL; |
| } |
| } |
| |
| static void |
| parse_font_face_end_font_face_cb (CRDocHandler * a_this) |
| { |
| CRStatement *result = NULL; |
| CRStatement **resultptr = NULL; |
| enum CRStatus status = CR_OK; |
| |
| g_return_if_fail (a_this); |
| |
| resultptr = &result; |
| status = cr_doc_handler_get_ctxt (a_this, (gpointer *) resultptr); |
| g_return_if_fail (status == CR_OK && result); |
| g_return_if_fail (result->type == AT_FONT_FACE_RULE_STMT); |
| |
| status = cr_doc_handler_set_result (a_this, result); |
| g_return_if_fail (status == CR_OK); |
| } |
| |
| static void |
| parse_page_start_page_cb (CRDocHandler * a_this, |
| CRString * a_name, |
| CRString * a_pseudo_page, |
| CRParsingLocation *a_location) |
| { |
| CRStatement *stmt = NULL; |
| enum CRStatus status = CR_OK; |
| CRString *page_name = NULL, *pseudo_name = NULL ; |
| |
| if (a_name) |
| page_name = cr_string_dup (a_name) ; |
| if (a_pseudo_page) |
| pseudo_name = cr_string_dup (a_pseudo_page) ; |
| |
| stmt = cr_statement_new_at_page_rule (NULL, NULL, |
| page_name, |
| pseudo_name); |
| page_name = NULL ; |
| pseudo_name = NULL ; |
| g_return_if_fail (stmt); |
| status = cr_doc_handler_set_ctxt (a_this, stmt); |
| g_return_if_fail (status == CR_OK); |
| } |
| |
| static void |
| parse_page_unrecoverable_error_cb (CRDocHandler * a_this) |
| { |
| CRStatement *stmt = NULL; |
| CRStatement **stmtptr = NULL; |
| enum CRStatus status = CR_OK; |
| |
| g_return_if_fail (a_this); |
| |
| stmtptr = &stmt; |
| status = cr_doc_handler_get_ctxt (a_this, (gpointer *) stmtptr); |
| if (status != CR_OK) { |
| cr_utils_trace_info ("Couldn't get parsing context. " |
| "This may lead to some memory leaks."); |
| return; |
| } |
| if (stmt) { |
| cr_statement_destroy (stmt); |
| stmt = NULL; |
| cr_doc_handler_set_ctxt (a_this, NULL); |
| } |
| } |
| |
| static void |
| parse_page_property_cb (CRDocHandler * a_this, |
| CRString * a_name, |
| CRTerm * a_expression, gboolean a_important) |
| { |
| CRString *name = NULL; |
| CRStatement *stmt = NULL; |
| CRStatement **stmtptr = NULL; |
| CRDeclaration *decl = NULL; |
| enum CRStatus status = CR_OK; |
| |
| stmtptr = &stmt; |
| status = cr_doc_handler_get_ctxt (a_this, (gpointer *) stmtptr); |
| g_return_if_fail (status == CR_OK && stmt->type == AT_PAGE_RULE_STMT); |
| |
| name = cr_string_dup (a_name); |
| g_return_if_fail (name); |
| |
| decl = cr_declaration_new (stmt, name, a_expression); |
| g_return_if_fail (decl); |
| decl->important = a_important; |
| stmt->kind.page_rule->decl_list = |
| cr_declaration_append (stmt->kind.page_rule->decl_list, decl); |
| g_return_if_fail (stmt->kind.page_rule->decl_list); |
| } |
| |
| static void |
| parse_page_end_page_cb (CRDocHandler * a_this, |
| CRString * a_name, |
| CRString * a_pseudo_page) |
| { |
| enum CRStatus status = CR_OK; |
| CRStatement *stmt = NULL; |
| CRStatement **stmtptr = NULL; |
| |
| stmtptr = &stmt; |
| status = cr_doc_handler_get_ctxt (a_this, (gpointer *) stmtptr); |
| g_return_if_fail (status == CR_OK && stmt); |
| g_return_if_fail (stmt->type == AT_PAGE_RULE_STMT); |
| |
| status = cr_doc_handler_set_result (a_this, stmt); |
| g_return_if_fail (status == CR_OK); |
| } |
| |
| static void |
| parse_at_media_start_media_cb (CRDocHandler * a_this, |
| GList * a_media_list, |
| CRParsingLocation *a_location) |
| { |
| enum CRStatus status = CR_OK; |
| CRStatement *at_media = NULL; |
| GList *media_list = NULL; |
| |
| g_return_if_fail (a_this && a_this->priv); |
| |
| if (a_media_list) { |
| /*duplicate media list */ |
| media_list = cr_utils_dup_glist_of_cr_string |
| (a_media_list); |
| } |
| |
| g_return_if_fail (media_list); |
| |
| /*make sure cr_statement_new_at_media_rule works in this case. */ |
| at_media = cr_statement_new_at_media_rule (NULL, NULL, media_list); |
| |
| status = cr_doc_handler_set_ctxt (a_this, at_media); |
| g_return_if_fail (status == CR_OK); |
| status = cr_doc_handler_set_result (a_this, at_media); |
| g_return_if_fail (status == CR_OK); |
| } |
| |
| static void |
| parse_at_media_unrecoverable_error_cb (CRDocHandler * a_this) |
| { |
| enum CRStatus status = CR_OK; |
| CRStatement *stmt = NULL; |
| CRStatement **stmtptr = NULL; |
| |
| g_return_if_fail (a_this); |
| |
| stmtptr = &stmt; |
| status = cr_doc_handler_get_result (a_this, (gpointer *) stmtptr); |
| if (status != CR_OK) { |
| cr_utils_trace_info ("Couldn't get parsing context. " |
| "This may lead to some memory leaks."); |
| return; |
| } |
| if (stmt) { |
| cr_statement_destroy (stmt); |
| stmt = NULL; |
| cr_doc_handler_set_ctxt (a_this, NULL); |
| cr_doc_handler_set_result (a_this, NULL); |
| } |
| } |
| |
| static void |
| parse_at_media_start_selector_cb (CRDocHandler * a_this, |
| CRSelector * a_sellist) |
| { |
| enum CRStatus status = CR_OK; |
| CRStatement *at_media = NULL; |
| CRStatement **at_media_ptr = NULL; |
| CRStatement *ruleset = NULL; |
| |
| g_return_if_fail (a_this && a_this->priv && a_sellist); |
| |
| at_media_ptr = &at_media; |
| status = cr_doc_handler_get_ctxt (a_this, (gpointer *) at_media_ptr); |
| g_return_if_fail (status == CR_OK && at_media); |
| g_return_if_fail (at_media->type == AT_MEDIA_RULE_STMT); |
| ruleset = cr_statement_new_ruleset (NULL, a_sellist, NULL, at_media); |
| g_return_if_fail (ruleset); |
| status = cr_doc_handler_set_ctxt (a_this, ruleset); |
| g_return_if_fail (status == CR_OK); |
| } |
| |
| static void |
| parse_at_media_property_cb (CRDocHandler * a_this, |
| CRString * a_name, CRTerm * a_value, |
| gboolean a_important) |
| { |
| enum CRStatus status = CR_OK; |
| |
| /* |
| *the current ruleset stmt, child of the |
| *current at-media being parsed. |
| */ |
| CRStatement *stmt = NULL; |
| CRStatement **stmtptr = NULL; |
| CRDeclaration *decl = NULL; |
| CRString *name = NULL; |
| |
| g_return_if_fail (a_this && a_name); |
| |
| name = cr_string_dup (a_name) ; |
| g_return_if_fail (name); |
| |
| stmtptr = &stmt; |
| status = cr_doc_handler_get_ctxt (a_this, |
| (gpointer *) stmtptr); |
| g_return_if_fail (status == CR_OK && stmt); |
| g_return_if_fail (stmt->type == RULESET_STMT); |
| |
| decl = cr_declaration_new (stmt, name, a_value); |
| g_return_if_fail (decl); |
| decl->important = a_important; |
| status = cr_statement_ruleset_append_decl (stmt, decl); |
| g_return_if_fail (status == CR_OK); |
| } |
| |
| static void |
| parse_at_media_end_selector_cb (CRDocHandler * a_this, |
| CRSelector * a_sellist) |
| { |
| enum CRStatus status = CR_OK; |
| |
| /* |
| *the current ruleset stmt, child of the |
| *current at-media being parsed. |
| */ |
| CRStatement *stmt = NULL; |
| CRStatement **stmtptr = NULL; |
| |
| g_return_if_fail (a_this && a_sellist); |
| |
| stmtptr = &stmt; |
| status = cr_doc_handler_get_ctxt (a_this, (gpointer *) stmtptr); |
| g_return_if_fail (status == CR_OK && stmt |
| && stmt->type == RULESET_STMT); |
| g_return_if_fail (stmt->kind.ruleset->parent_media_rule); |
| |
| status = cr_doc_handler_set_ctxt |
| (a_this, stmt->kind.ruleset->parent_media_rule); |
| g_return_if_fail (status == CR_OK); |
| } |
| |
| static void |
| parse_at_media_end_media_cb (CRDocHandler * a_this, |
| GList * a_media_list) |
| { |
| enum CRStatus status = CR_OK; |
| CRStatement *at_media = NULL; |
| CRStatement **at_media_ptr = NULL; |
| |
| g_return_if_fail (a_this && a_this->priv); |
| |
| at_media_ptr = &at_media; |
| status = cr_doc_handler_get_ctxt (a_this, |
| (gpointer *) at_media_ptr); |
| g_return_if_fail (status == CR_OK && at_media); |
| status = cr_doc_handler_set_result (a_this, at_media); |
| } |
| |
| static void |
| parse_ruleset_start_selector_cb (CRDocHandler * a_this, |
| CRSelector * a_sellist) |
| { |
| CRStatement *ruleset = NULL; |
| |
| g_return_if_fail (a_this && a_this->priv && a_sellist); |
| |
| ruleset = cr_statement_new_ruleset (NULL, a_sellist, NULL, NULL); |
| g_return_if_fail (ruleset); |
| |
| cr_doc_handler_set_result (a_this, ruleset); |
| } |
| |
| static void |
| parse_ruleset_unrecoverable_error_cb (CRDocHandler * a_this) |
| { |
| CRStatement *stmt = NULL; |
| CRStatement **stmtptr = NULL; |
| enum CRStatus status = CR_OK; |
| |
| stmtptr = &stmt; |
| status = cr_doc_handler_get_result (a_this, (gpointer *) stmtptr); |
| if (status != CR_OK) { |
| cr_utils_trace_info ("Couldn't get parsing context. " |
| "This may lead to some memory leaks."); |
| return; |
| } |
| if (stmt) { |
| cr_statement_destroy (stmt); |
| stmt = NULL; |
| cr_doc_handler_set_result (a_this, NULL); |
| } |
| } |
| |
| static void |
| parse_ruleset_property_cb (CRDocHandler * a_this, |
| CRString * a_name, |
| CRTerm * a_value, gboolean a_important) |
| { |
| enum CRStatus status = CR_OK; |
| CRStatement *ruleset = NULL; |
| CRStatement **rulesetptr = NULL; |
| CRDeclaration *decl = NULL; |
| CRString *stringue = NULL; |
| |
| g_return_if_fail (a_this && a_this->priv && a_name); |
| |
| stringue = cr_string_dup (a_name); |
| g_return_if_fail (stringue); |
| |
| rulesetptr = &ruleset; |
| status = cr_doc_handler_get_result (a_this, (gpointer *) rulesetptr); |
| g_return_if_fail (status == CR_OK |
| && ruleset |
| && ruleset->type == RULESET_STMT); |
| |
| decl = cr_declaration_new (ruleset, stringue, a_value); |
| g_return_if_fail (decl); |
| decl->important = a_important; |
| status = cr_statement_ruleset_append_decl (ruleset, decl); |
| g_return_if_fail (status == CR_OK); |
| } |
| |
| static void |
| parse_ruleset_end_selector_cb (CRDocHandler * a_this, |
| CRSelector * a_sellist) |
| { |
| CRStatement *result = NULL; |
| CRStatement **resultptr = NULL; |
| enum CRStatus status = CR_OK; |
| |
| g_return_if_fail (a_this && a_sellist); |
| |
| resultptr = &result; |
| status = cr_doc_handler_get_result (a_this, (gpointer *) resultptr); |
| |
| g_return_if_fail (status == CR_OK |
| && result |
| && result->type == RULESET_STMT); |
| } |
| |
| static void |
| cr_statement_clear (CRStatement * a_this) |
| { |
| g_return_if_fail (a_this); |
| |
| switch (a_this->type) { |
| case AT_RULE_STMT: |
| break; |
| case RULESET_STMT: |
| if (!a_this->kind.ruleset) |
| return; |
| if (a_this->kind.ruleset->sel_list) { |
| cr_selector_unref (a_this->kind.ruleset->sel_list); |
| a_this->kind.ruleset->sel_list = NULL; |
| } |
| if (a_this->kind.ruleset->decl_list) { |
| cr_declaration_destroy |
| (a_this->kind.ruleset->decl_list); |
| a_this->kind.ruleset->decl_list = NULL; |
| } |
| g_free (a_this->kind.ruleset); |
| a_this->kind.ruleset = NULL; |
| break; |
| |
| case AT_IMPORT_RULE_STMT: |
| if (!a_this->kind.import_rule) |
| return; |
| if (a_this->kind.import_rule->url) { |
| cr_string_destroy |
| (a_this->kind.import_rule->url) ; |
| a_this->kind.import_rule->url = NULL; |
| } |
| g_free (a_this->kind.import_rule); |
| a_this->kind.import_rule = NULL; |
| break; |
| |
| case AT_MEDIA_RULE_STMT: |
| if (!a_this->kind.media_rule) |
| return; |
| if (a_this->kind.media_rule->rulesets) { |
| cr_statement_destroy |
| (a_this->kind.media_rule->rulesets); |
| a_this->kind.media_rule->rulesets = NULL; |
| } |
| if (a_this->kind.media_rule->media_list) { |
| GList *cur = NULL; |
| |
| for (cur = a_this->kind.media_rule->media_list; |
| cur; cur = cur->next) { |
| if (cur->data) { |
| cr_string_destroy ((CRString *) cur->data); |
| cur->data = NULL; |
| } |
| |
| } |
| g_list_free (a_this->kind.media_rule->media_list); |
| a_this->kind.media_rule->media_list = NULL; |
| } |
| g_free (a_this->kind.media_rule); |
| a_this->kind.media_rule = NULL; |
| break; |
| |
| case AT_PAGE_RULE_STMT: |
| if (!a_this->kind.page_rule) |
| return; |
| |
| if (a_this->kind.page_rule->decl_list) { |
| cr_declaration_destroy |
| (a_this->kind.page_rule->decl_list); |
| a_this->kind.page_rule->decl_list = NULL; |
| } |
| if (a_this->kind.page_rule->name) { |
| cr_string_destroy |
| (a_this->kind.page_rule->name); |
| a_this->kind.page_rule->name = NULL; |
| } |
| if (a_this->kind.page_rule->pseudo) { |
| cr_string_destroy |
| (a_this->kind.page_rule->pseudo); |
| a_this->kind.page_rule->pseudo = NULL; |
| } |
| g_free (a_this->kind.page_rule); |
| a_this->kind.page_rule = NULL; |
| break; |
| |
| case AT_CHARSET_RULE_STMT: |
| if (!a_this->kind.charset_rule) |
| return; |
| |
| if (a_this->kind.charset_rule->charset) { |
| cr_string_destroy |
| (a_this->kind.charset_rule->charset); |
| a_this->kind.charset_rule->charset = NULL; |
| } |
| g_free (a_this->kind.charset_rule); |
| a_this->kind.charset_rule = NULL; |
| break; |
| |
| case AT_FONT_FACE_RULE_STMT: |
| if (!a_this->kind.font_face_rule) |
| return; |
| |
| if (a_this->kind.font_face_rule->decl_list) { |
| cr_declaration_unref |
| (a_this->kind.font_face_rule->decl_list); |
| a_this->kind.font_face_rule->decl_list = NULL; |
| } |
| g_free (a_this->kind.font_face_rule); |
| a_this->kind.font_face_rule = NULL; |
| break; |
| |
| default: |
| break; |
| } |
| } |
| |
| /** |
| * cr_statement_ruleset_to_string: |
| * |
| *@a_this: the current instance of #CRStatement |
| *@a_indent: the number of whitespace to use for indentation |
| * |
| *Serializes the ruleset statement into a string |
| * |
| *Returns the newly allocated serialised string. Must be freed |
| *by the caller, using g_free(). |
| */ |
| static gchar * |
| cr_statement_ruleset_to_string (CRStatement const * a_this, glong a_indent) |
| { |
| GString *stringue = NULL; |
| gchar *tmp_str = NULL, |
| *result = NULL; |
| |
| g_return_val_if_fail (a_this && a_this->type == RULESET_STMT, NULL); |
| |
| stringue = g_string_new (NULL); |
| |
| if (a_this->kind.ruleset->sel_list) { |
| if (a_indent) |
| cr_utils_dump_n_chars2 (' ', stringue, a_indent); |
| |
| tmp_str = |
| (gchar *) cr_selector_to_string (a_this->kind.ruleset-> |
| sel_list); |
| if (tmp_str) { |
| g_string_append (stringue, tmp_str); |
| g_free (tmp_str); |
| tmp_str = NULL; |
| } |
| } |
| g_string_append (stringue, " {\n"); |
| if (a_this->kind.ruleset->decl_list) { |
| tmp_str = (gchar *) cr_declaration_list_to_string2 |
| (a_this->kind.ruleset->decl_list, |
| a_indent + DECLARATION_INDENT_NB, TRUE); |
| if (tmp_str) { |
| g_string_append (stringue, tmp_str); |
| g_free (tmp_str); |
| tmp_str = NULL; |
| } |
| g_string_append (stringue, "\n"); |
| cr_utils_dump_n_chars2 (' ', stringue, a_indent); |
| } |
| g_string_append (stringue, "}"); |
| result = stringue->str; |
| |
| if (stringue) { |
| g_string_free (stringue, FALSE); |
| stringue = NULL; |
| } |
| if (tmp_str) { |
| g_free (tmp_str); |
| tmp_str = NULL; |
| } |
| return result; |
| } |
| |
| |
| /** |
| * cr_statement_font_face_rule_to_string: |
| * |
| *@a_this: the current instance of #CRStatement to consider |
| *It must be a font face rule statement. |
| *@a_indent: the number of white spaces of indentation. |
| * |
| *Serializes a font face rule statement into a string. |
| * |
| *Returns the serialized string. Must be deallocated by the caller |
| *using g_free(). |
| */ |
| static gchar * |
| cr_statement_font_face_rule_to_string (CRStatement const * a_this, |
| glong a_indent) |
| { |
| gchar *result = NULL, *tmp_str = NULL ; |
| GString *stringue = NULL ; |
| |
| g_return_val_if_fail (a_this |
| && a_this->type == AT_FONT_FACE_RULE_STMT, |
| NULL); |
| |
| if (a_this->kind.font_face_rule->decl_list) { |
| stringue = g_string_new (NULL) ; |
| g_return_val_if_fail (stringue, NULL) ; |
| if (a_indent) |
| cr_utils_dump_n_chars2 (' ', stringue, |
| a_indent); |
| g_string_append (stringue, "@font-face {\n"); |
| tmp_str = (gchar *) cr_declaration_list_to_string2 |
| (a_this->kind.font_face_rule->decl_list, |
| a_indent + DECLARATION_INDENT_NB, TRUE) ; |
| if (tmp_str) { |
| g_string_append (stringue, |
| tmp_str) ; |
| g_free (tmp_str) ; |
| tmp_str = NULL ; |
| } |
| g_string_append (stringue, "\n}"); |
| } |
| if (stringue) { |
| result = stringue->str ; |
| g_string_free (stringue, FALSE) ; |
| stringue = NULL ; |
| } |
| return result ; |
| } |
| |
| |
| /** |
| * cr_statement_charset_to_string: |
| * |
| *Serialises an \@charset statement into a string. |
| *@a_this: the statement to serialize. |
| *@a_indent: the number of indentation spaces |
| * |
| *Returns the serialized charset statement. Must be |
| *freed by the caller using g_free(). |
| */ |
| static gchar * |
| cr_statement_charset_to_string (CRStatement const *a_this, |
| gulong a_indent) |
| { |
| gchar *str = NULL ; |
| GString *stringue = NULL ; |
| |
| g_return_val_if_fail (a_this |
| && a_this->type == AT_CHARSET_RULE_STMT, |
| NULL) ; |
| |
| if (a_this->kind.charset_rule |
| && a_this->kind.charset_rule->charset |
| && a_this->kind.charset_rule->charset->stryng |
| && a_this->kind.charset_rule->charset->stryng->str) { |
| str = g_strndup (a_this->kind.charset_rule->charset->stryng->str, |
| a_this->kind.charset_rule->charset->stryng->len); |
| g_return_val_if_fail (str, NULL); |
| stringue = g_string_new (NULL) ; |
| g_return_val_if_fail (stringue, NULL) ; |
| cr_utils_dump_n_chars2 (' ', stringue, a_indent); |
| g_string_append_printf (stringue, |
| "@charset \"%s\" ;", str); |
| if (str) { |
| g_free (str); |
| str = NULL; |
| } |
| } |
| if (stringue) { |
| str = stringue->str ; |
| g_string_free (stringue, FALSE) ; |
| } |
| return str ; |
| } |
| |
| |
| /** |
| * cr_statement_at_page_rule_to_string: |
| * |
| *Serialises the at page rule statement into a string |
| *@a_this: the current instance of #CRStatement. Must |
| *be an "\@page" rule statement. |
| * |
| *Returns the serialized string. Must be freed by the caller |
| */ |
| static gchar * |
| cr_statement_at_page_rule_to_string (CRStatement const *a_this, |
| gulong a_indent) |
| { |
| GString *stringue = NULL; |
| gchar *result = NULL ; |
| |
| stringue = g_string_new (NULL) ; |
| |
| cr_utils_dump_n_chars2 (' ', stringue, a_indent) ; |
| g_string_append (stringue, "@page"); |
| if (a_this->kind.page_rule->name |
| && a_this->kind.page_rule->name->stryng) { |
| g_string_append_printf |
| (stringue, " %s", |
| a_this->kind.page_rule->name->stryng->str) ; |
| } else { |
| g_string_append (stringue, " "); |
| } |
| if (a_this->kind.page_rule->pseudo |
| && a_this->kind.page_rule->pseudo->stryng) { |
| g_string_append_printf |
| (stringue, " :%s", |
| a_this->kind.page_rule->pseudo->stryng->str) ; |
| } |
| if (a_this->kind.page_rule->decl_list) { |
| gchar *str = NULL ; |
| g_string_append (stringue, " {\n"); |
| str = (gchar *) cr_declaration_list_to_string2 |
| (a_this->kind.page_rule->decl_list, |
| a_indent + DECLARATION_INDENT_NB, TRUE) ; |
| if (str) { |
| g_string_append (stringue, str) ; |
| g_free (str) ; |
| str = NULL ; |
| } |
| g_string_append (stringue, "\n}\n"); |
| } |
| result = stringue->str ; |
| g_string_free (stringue, FALSE) ; |
| stringue = NULL ; |
| return result ; |
| } |
| |
| |
| /** |
| *Serializes an \@media statement. |
| *@param a_this the current instance of #CRStatement |
| *@param a_indent the number of spaces of indentation. |
| *@return the serialized \@media statement. Must be freed |
| *by the caller using g_free(). |
| */ |
| static gchar * |
| cr_statement_media_rule_to_string (CRStatement const *a_this, |
| gulong a_indent) |
| { |
| gchar *str = NULL ; |
| GString *stringue = NULL ; |
| GList const *cur = NULL; |
| |
| g_return_val_if_fail (a_this->type == AT_MEDIA_RULE_STMT, |
| NULL); |
| |
| if (a_this->kind.media_rule) { |
| stringue = g_string_new (NULL) ; |
| cr_utils_dump_n_chars2 (' ', stringue, a_indent); |
| g_string_append (stringue, "@media"); |
| |
| for (cur = a_this->kind.media_rule->media_list; cur; |
| cur = cur->next) { |
| if (cur->data) { |
| gchar *str2 = cr_string_dup2 |
| ((CRString const *) cur->data); |
| |
| if (str2) { |
| if (cur->prev) { |
| g_string_append |
| (stringue, |
| ","); |
| } |
| g_string_append_printf |
| (stringue, |
| " %s", str2); |
| g_free (str2); |
| str2 = NULL; |
| } |
| } |
| } |
| g_string_append (stringue, " {\n"); |
| str = cr_statement_list_to_string |
| (a_this->kind.media_rule->rulesets, |
| a_indent + DECLARATION_INDENT_NB) ; |
| if (str) { |
| g_string_append (stringue, str) ; |
| g_free (str) ; |
| str = NULL ; |
| } |
| g_string_append (stringue, "\n}"); |
| } |
| if (stringue) { |
| str = stringue->str ; |
| g_string_free (stringue, FALSE) ; |
| } |
| return str ; |
| } |
| |
| |
| static gchar * |
| cr_statement_import_rule_to_string (CRStatement const *a_this, |
| gulong a_indent) |
| { |
| GString *stringue = NULL ; |
| gchar *str = NULL; |
| |
| g_return_val_if_fail (a_this |
| && a_this->type == AT_IMPORT_RULE_STMT |
| && a_this->kind.import_rule, |
| NULL) ; |
| |
| if (a_this->kind.import_rule->url |
| && a_this->kind.import_rule->url->stryng) { |
| stringue = g_string_new (NULL) ; |
| g_return_val_if_fail (stringue, NULL) ; |
| str = g_strndup (a_this->kind.import_rule->url->stryng->str, |
| a_this->kind.import_rule->url->stryng->len); |
| cr_utils_dump_n_chars2 (' ', stringue, a_indent); |
| if (str) { |
| g_string_append_printf (stringue, |
| "@import url(\"%s\")", |
| str); |
| g_free (str); |
| str = NULL ; |
| } else /*there is no url, so no import rule, get out! */ |
| return NULL; |
| |
| if (a_this->kind.import_rule->media_list) { |
| GList const *cur = NULL; |
| |
| for (cur = a_this->kind.import_rule->media_list; |
| cur; cur = cur->next) { |
| if (cur->data) { |
| CRString const *crstr = cur->data; |
| |
| if (cur->prev) { |
| g_string_append |
| (stringue, ", "); |
| } |
| if (crstr |
| && crstr->stryng |
| && crstr->stryng->str) { |
| g_string_append_len |
| (stringue, |
| crstr->stryng->str, |
| crstr->stryng->len) ; |
| } |
| } |
| } |
| } |
| g_string_append (stringue, " ;"); |
| } |
| if (stringue) { |
| str = stringue->str ; |
| g_string_free (stringue, FALSE) ; |
| stringue = NULL ; |
| } |
| return str ; |
| } |
| |
| |
| /******************* |
| *public functions |
| ******************/ |
| |
| /** |
| * cr_statement_does_buf_parses_against_core: |
| * |
| *@a_buf: the buffer to parse. |
| *@a_encoding: the character encoding of a_buf. |
| * |
| *Tries to parse a buffer and says whether if the content of the buffer |
| *is a css statement as defined by the "Core CSS Grammar" (chapter 4 of the |
| *css spec) or not. |
| * |
| *Returns TRUE if the buffer parses against the core grammar, false otherwise. |
| */ |
| gboolean |
| cr_statement_does_buf_parses_against_core (const guchar * a_buf, |
| enum CREncoding a_encoding) |
| { |
| CRParser *parser = NULL; |
| enum CRStatus status = CR_OK; |
| gboolean result = FALSE; |
| |
| parser = cr_parser_new_from_buf ((guchar*)a_buf, strlen ((const char *) a_buf), |
| a_encoding, FALSE); |
| g_return_val_if_fail (parser, FALSE); |
| |
| status = cr_parser_set_use_core_grammar (parser, TRUE); |
| if (status != CR_OK) { |
| goto cleanup; |
| } |
| |
| status = cr_parser_parse_statement_core (parser); |
| if (status == CR_OK) { |
| result = TRUE; |
| } |
| |
| cleanup: |
| if (parser) { |
| cr_parser_destroy (parser); |
| } |
| |
| return result; |
| } |
| |
| /** |
| * cr_statement_parse_from_buf: |
| * |
| *@a_buf: the buffer to parse. |
| *@a_encoding: the character encoding of a_buf. |
| * |
| *Parses a buffer that contains a css statement and returns |
| *an instance of #CRStatement in case of successful parsing. |
| *TODO: at support of "\@import" rules. |
| * |
| *Returns the newly built instance of #CRStatement in case |
| *of successful parsing, NULL otherwise. |
| */ |
| CRStatement * |
| cr_statement_parse_from_buf (const guchar * a_buf, enum CREncoding a_encoding) |
| { |
| CRStatement *result = NULL; |
| |
| /* |
| *The strategy of this function is "brute force". |
| *It tries to parse all the types of CRStatement it knows about. |
| *I could do this a smarter way but I don't have the time now. |
| *I think I will revisit this when time of performances and |
| *pull based incremental parsing comes. |
| */ |
| |
| result = cr_statement_ruleset_parse_from_buf (a_buf, a_encoding); |
| if (!result) { |
| result = cr_statement_at_charset_rule_parse_from_buf |
| (a_buf, a_encoding); |
| } else { |
| goto out; |
| } |
| |
| if (!result) { |
| result = cr_statement_at_media_rule_parse_from_buf |
| (a_buf, a_encoding); |
| } else { |
| goto out; |
| } |
| |
| if (!result) { |
| result = cr_statement_at_charset_rule_parse_from_buf |
| (a_buf, a_encoding); |
| } else { |
| goto out; |
| } |
| |
| if (!result) { |
| result = cr_statement_font_face_rule_parse_from_buf |
| (a_buf, a_encoding); |
| |
| } else { |
| goto out; |
| } |
| |
| if (!result) { |
| result = cr_statement_at_page_rule_parse_from_buf |
| (a_buf, a_encoding); |
| } else { |
| goto out; |
| } |
| |
| if (!result) { |
| result = cr_statement_at_import_rule_parse_from_buf |
| (a_buf, a_encoding); |
| } else { |
| goto out; |
| } |
| |
| out: |
| return result; |
| } |
| |
| /** |
| * cr_statement_ruleset_parse_from_buf: |
| * |
| *@a_buf: the buffer to parse. |
| *@a_enc: the character encoding of a_buf. |
| * |
| *Parses a buffer that contains a ruleset statement an instanciates |
| *a #CRStatement of type RULESET_STMT. |
| * |
| *Returns the newly built instance of #CRStatement in case of successful parsing, |
| *NULL otherwise. |
| */ |
| CRStatement * |
| cr_statement_ruleset_parse_from_buf (const guchar * a_buf, |
| enum CREncoding a_enc) |
| { |
| enum CRStatus status = CR_OK; |
| CRStatement *result = NULL; |
| CRStatement **resultptr = NULL; |
| CRParser *parser = NULL; |
| CRDocHandler *sac_handler = NULL; |
| |
| g_return_val_if_fail (a_buf, NULL); |
| |
| parser = cr_parser_new_from_buf ((guchar*)a_buf, strlen ((const char *) a_buf), |
| a_enc, FALSE); |
| |
| g_return_val_if_fail (parser, NULL); |
| |
| sac_handler = cr_doc_handler_new (); |
| g_return_val_if_fail (parser, NULL); |
| |
| sac_handler->start_selector = parse_ruleset_start_selector_cb; |
| sac_handler->end_selector = parse_ruleset_end_selector_cb; |
| sac_handler->property = parse_ruleset_property_cb; |
| sac_handler->unrecoverable_error = |
| parse_ruleset_unrecoverable_error_cb; |
| |
| cr_parser_set_sac_handler (parser, sac_handler); |
| cr_parser_try_to_skip_spaces_and_comments (parser); |
| status = cr_parser_parse_ruleset (parser); |
| if (status != CR_OK) { |
| goto cleanup; |
| } |
| |
| resultptr = &result; |
| status = cr_doc_handler_get_result (sac_handler, |
| (gpointer *) resultptr); |
| if (!((status == CR_OK) && result)) { |
| if (result) { |
| cr_statement_destroy (result); |
| result = NULL; |
| } |
| } |
| |
| cleanup: |
| if (parser) { |
| cr_parser_destroy (parser); |
| parser = NULL; |
| sac_handler = NULL ; |
| } |
| if (sac_handler) { |
| cr_doc_handler_unref (sac_handler); |
| sac_handler = NULL; |
| } |
| return result; |
| } |
| |
| /** |
| * cr_statement_new_ruleset: |
| * |
| *@a_sel_list: the list of #CRSimpleSel (selectors) |
| *the rule applies to. |
| *@a_decl_list: the list of instances of #CRDeclaration |
| *that composes the ruleset. |
| *@a_media_types: a list of instances of GString that |
| *describe the media list this ruleset applies to. |
| * |
| *Creates a new instance of #CRStatement of type |
| *#CRRulSet. |
| * |
| *Returns the new instance of #CRStatement or NULL if something |
| *went wrong. |
| */ |
| CRStatement * |
| cr_statement_new_ruleset (CRStyleSheet * a_sheet, |
| CRSelector * a_sel_list, |
| CRDeclaration * a_decl_list, |
| CRStatement * a_parent_media_rule) |
| { |
| CRStatement *result = NULL; |
| |
| g_return_val_if_fail (a_sel_list, NULL); |
| |
| if (a_parent_media_rule) { |
| g_return_val_if_fail |
| (a_parent_media_rule->type == AT_MEDIA_RULE_STMT, |
| NULL); |
| g_return_val_if_fail (a_parent_media_rule->kind.media_rule, |
| NULL); |
| } |
| |
| result = g_try_malloc (sizeof (CRStatement)); |
| |
| if (!result) { |
| cr_utils_trace_info ("Out of memory"); |
| return NULL; |
| } |
| |
| memset (result, 0, sizeof (CRStatement)); |
| result->type = RULESET_STMT; |
| result->kind.ruleset = g_try_malloc (sizeof (CRRuleSet)); |
| |
| if (!result->kind.ruleset) { |
| cr_utils_trace_info ("Out of memory"); |
| if (result) |
| g_free (result); |
| return NULL; |
| } |
| |
| memset (result->kind.ruleset, 0, sizeof (CRRuleSet)); |
| result->kind.ruleset->sel_list = a_sel_list; |
| if (a_sel_list) |
| cr_selector_ref (a_sel_list); |
| result->kind.ruleset->decl_list = a_decl_list; |
| |
| if (a_parent_media_rule) { |
| result->kind.ruleset->parent_media_rule = a_parent_media_rule; |
| a_parent_media_rule->kind.media_rule->rulesets = |
| cr_statement_append |
| (a_parent_media_rule->kind.media_rule->rulesets, |
| result); |
| } |
| |
| cr_statement_set_parent_sheet (result, a_sheet); |
| |
| return result; |
| } |
| |
| /** |
| * cr_statement_at_media_rule_parse_from_buf: |
| * |
| *@a_buf: the input to parse. |
| *@a_enc: the encoding of the buffer. |
| * |
| *Parses a buffer that contains an "\@media" declaration |
| *and builds an \@media css statement. |
| * |
| *Returns the \@media statement, or NULL if the buffer could not |
| *be successfully parsed. |
| */ |
| CRStatement * |
| cr_statement_at_media_rule_parse_from_buf (const guchar * a_buf, |
| enum CREncoding a_enc) |
| { |
| CRParser *parser = NULL; |
| CRStatement *result = NULL; |
| CRStatement **resultptr = NULL; |
| CRDocHandler *sac_handler = NULL; |
| enum CRStatus status = CR_OK; |
| |
| parser = cr_parser_new_from_buf ((guchar*)a_buf, strlen ((const char *) a_buf), |
| a_enc, FALSE); |
| if (!parser) { |
| cr_utils_trace_info ("Instantiation of the parser failed"); |
| goto cleanup; |
| } |
| |
| sac_handler = cr_doc_handler_new (); |
| if (!sac_handler) { |
| cr_utils_trace_info |
| ("Instantiation of the sac handler failed"); |
| goto cleanup; |
| } |
| |
| sac_handler->start_media = parse_at_media_start_media_cb; |
| sac_handler->start_selector = parse_at_media_start_selector_cb; |
| sac_handler->property = parse_at_media_property_cb; |
| sac_handler->end_selector = parse_at_media_end_selector_cb; |
| sac_handler->end_media = parse_at_media_end_media_cb; |
| sac_handler->unrecoverable_error = |
| parse_at_media_unrecoverable_error_cb; |
| |
| status = cr_parser_set_sac_handler (parser, sac_handler); |
| if (status != CR_OK) |
| goto cleanup; |
| |
| status = cr_parser_try_to_skip_spaces_and_comments (parser); |
| if (status != CR_OK) |
| goto cleanup; |
| |
| status = cr_parser_parse_media (parser); |
| if (status != CR_OK) |
| goto cleanup; |
| |
| resultptr = &result; |
| status = cr_doc_handler_get_result (sac_handler, |
| (gpointer *) resultptr); |
| if (status != CR_OK) |
| goto cleanup; |
| |
| cleanup: |
| |
| if (parser) { |
| cr_parser_destroy (parser); |
| parser = NULL; |
| sac_handler = NULL ; |
| } |
| if (sac_handler) { |
| cr_doc_handler_unref (sac_handler); |
| sac_handler = NULL; |
| } |
| |
| return result; |
| } |
| |
| /** |
| * cr_statement_new_at_media_rule: |
| * |
| *@a_ruleset: the ruleset statements contained |
| *in the \@media rule. |
| *@a_media: the media string list. A list of GString pointers. |
| * |
| *Instanciates an instance of #CRStatement of type |
| *AT_MEDIA_RULE_STMT (\@media ruleset). |
| * |
| */ |
| CRStatement * |
| cr_statement_new_at_media_rule (CRStyleSheet * a_sheet, |
| CRStatement * a_rulesets, GList * a_media) |
| { |
| CRStatement *result = NULL, |
| *cur = NULL; |
| |
| if (a_rulesets) |
| g_return_val_if_fail (a_rulesets->type == RULESET_STMT, NULL); |
| |
| result = g_try_malloc (sizeof (CRStatement)); |
| |
| if (!result) { |
| cr_utils_trace_info ("Out of memory"); |
| return NULL; |
| } |
| |
| memset (result, 0, sizeof (CRStatement)); |
| result->type = AT_MEDIA_RULE_STMT; |
| |
| result->kind.media_rule = g_try_malloc (sizeof (CRAtMediaRule)); |
| if (!result->kind.media_rule) { |
| cr_utils_trace_info ("Out of memory"); |
| g_free (result); |
| return NULL; |
| } |
| memset (result->kind.media_rule, 0, sizeof (CRAtMediaRule)); |
| result->kind.media_rule->rulesets = a_rulesets; |
| for (cur = a_rulesets; cur; cur = cur->next) { |
| if (cur->type != RULESET_STMT || !cur->kind.ruleset) { |
| cr_utils_trace_info ("Bad parameter a_rulesets. " |
| "It should be a list of " |
| "correct ruleset statement only !"); |
| goto error; |
| } |
| cur->kind.ruleset->parent_media_rule = result; |
| } |
| |
| result->kind.media_rule->media_list = a_media; |
| if (a_sheet) { |
| cr_statement_set_parent_sheet (result, a_sheet); |
| } |
| |
| return result; |
| |
| error: |
| return NULL; |
| } |
| |
| /** |
| * cr_statement_new_at_import_rule: |
| * |
| *@a_url: the url to connect to the get the file |
| *to be imported. |
| *@a_sheet: the imported parsed stylesheet. |
| * |
| *Creates a new instance of #CRStatment of type |
| *#CRAtImportRule. |
| * |
| *Returns the newly built instance of #CRStatement. |
| */ |
| CRStatement * |
| cr_statement_new_at_import_rule (CRStyleSheet * a_container_sheet, |
| CRString * a_url, |
| GList * a_media_list, |
| CRStyleSheet * a_imported_sheet) |
| { |
| CRStatement *result = NULL; |
| |
| result = g_try_malloc (sizeof (CRStatement)); |
| |
| if (!result) { |
| cr_utils_trace_info ("Out of memory"); |
| return NULL; |
| } |
| |
| memset (result, 0, sizeof (CRStatement)); |
| result->type = AT_IMPORT_RULE_STMT; |
| |
| result->kind.import_rule = g_try_malloc (sizeof (CRAtImportRule)); |
| |
| if (!result->kind.import_rule) { |
| cr_utils_trace_info ("Out of memory"); |
| g_free (result); |
| return NULL; |
| } |
| |
| memset (result->kind.import_rule, 0, sizeof (CRAtImportRule)); |
| result->kind.import_rule->url = a_url; |
| result->kind.import_rule->media_list = a_media_list; |
| result->kind.import_rule->sheet = a_imported_sheet; |
| if (a_container_sheet) |
| cr_statement_set_parent_sheet (result, a_container_sheet); |
| |
| return result; |
| } |
| |
| /** |
| * cr_statement_at_import_rule_parse_from_buf: |
| * |
| *@a_buf: the buffer to parse. |
| *@a_encoding: the encoding of a_buf. |
| * |
| *Parses a buffer that contains an "\@import" rule and |
| *instanciate a #CRStatement of type AT_IMPORT_RULE_STMT |
| * |
| *Returns the newly built instance of #CRStatement in case of |
| *a successful parsing, NULL otherwise. |
| */ |
| CRStatement * |
| cr_statement_at_import_rule_parse_from_buf (const guchar * a_buf, |
| enum CREncoding a_encoding) |
| { |
| enum CRStatus status = CR_OK; |
| CRParser *parser = NULL; |
| CRStatement *result = NULL; |
| GList *media_list = NULL; |
| CRString *import_string = NULL; |
| CRParsingLocation location = {0} ; |
| |
| parser = cr_parser_new_from_buf ((guchar*)a_buf, strlen ((const char *) a_buf), |
| a_encoding, FALSE); |
| if (!parser) { |
| cr_utils_trace_info ("Instantiation of parser failed."); |
| goto cleanup; |
| } |
| |
| status = cr_parser_try_to_skip_spaces_and_comments (parser); |
| if (status != CR_OK) |
| goto cleanup; |
| |
| status = cr_parser_parse_import (parser, |
| &media_list, |
| &import_string, |
| &location); |
| if (status != CR_OK || !import_string) |
| goto cleanup; |
| |
| result = cr_statement_new_at_import_rule (NULL, import_string, |
| media_list, NULL); |
| if (result) { |
| cr_parsing_location_copy (&result->location, |
| &location) ; |
| import_string = NULL; |
| media_list = NULL; |
| } |
| |
| cleanup: |
| if (parser) { |
| cr_parser_destroy (parser); |
| parser = NULL; |
| } |
| if (media_list) { |
| for (; media_list; |
| media_list = g_list_next (media_list)) { |
| if (media_list->data) { |
| cr_string_destroy ((CRString*)media_list->data); |
| media_list->data = NULL; |
| } |
| } |
| g_list_free (media_list); |
| media_list = NULL; |
| } |
| if (import_string) { |
| cr_string_destroy (import_string); |
| import_string = NULL; |
| } |
| |
| return result; |
| } |
| |
| /** |
| * cr_statement_new_at_page_rule: |
| * |
| *@a_decl_list: a list of instances of #CRDeclarations |
| *which is actually the list of declarations that applies to |
| *this page rule. |
| *@a_selector: the page rule selector. |
| * |
| *Creates a new instance of #CRStatement of type |
| *#CRAtPageRule. |
| * |
| *Returns the newly built instance of #CRStatement or NULL |
| *in case of error. |
| */ |
| CRStatement * |
| cr_statement_new_at_page_rule (CRStyleSheet * a_sheet, |
| CRDeclaration * a_decl_list, |
| CRString * a_name, CRString * a_pseudo) |
| { |
| CRStatement *result = NULL; |
| |
| result = g_try_malloc (sizeof (CRStatement)); |
| |
| if (!result) { |
| cr_utils_trace_info ("Out of memory"); |
| return NULL; |
| } |
| |
| memset (result, 0, sizeof (CRStatement)); |
| result->type = AT_PAGE_RULE_STMT; |
| |
| result->kind.page_rule = g_try_malloc (sizeof (CRAtPageRule)); |
| |
| if (!result->kind.page_rule) { |
| cr_utils_trace_info ("Out of memory"); |
| g_free (result); |
| return NULL; |
| } |
| |
| memset (result->kind.page_rule, 0, sizeof (CRAtPageRule)); |
| if (a_decl_list) { |
| result->kind.page_rule->decl_list = a_decl_list; |
| cr_declaration_ref (a_decl_list); |
| } |
| result->kind.page_rule->name = a_name; |
| result->kind.page_rule->pseudo = a_pseudo; |
| if (a_sheet) |
| cr_statement_set_parent_sheet (result, a_sheet); |
| |
| return result; |
| } |
| |
| /** |
| * cr_statement_at_page_rule_parse_from_buf: |
| * |
| *@a_buf: the character buffer to parse. |
| *@a_encoding: the character encoding of a_buf. |
| * |
| *Parses a buffer that contains an "\@page" production and, |
| *if the parsing succeeds, builds the page statement. |
| * |
| *Returns the newly built at page statement in case of successful parsing, |
| *NULL otherwise. |
| */ |
| CRStatement * |
| cr_statement_at_page_rule_parse_from_buf (const guchar * a_buf, |
| enum CREncoding a_encoding) |
| { |
| enum CRStatus status = CR_OK; |
| CRParser *parser = NULL; |
| CRDocHandler *sac_handler = NULL; |
| CRStatement *result = NULL; |
| CRStatement **resultptr = NULL; |
| |
| g_return_val_if_fail (a_buf, NULL); |
| |
| parser = cr_parser_new_from_buf ((guchar*)a_buf, strlen ((const char *) a_buf), |
| a_encoding, FALSE); |
| if (!parser) { |
| cr_utils_trace_info ("Instantiation of the parser failed."); |
| goto cleanup; |
| } |
| |
| sac_handler = cr_doc_handler_new (); |
| if (!sac_handler) { |
| cr_utils_trace_info |
| ("Instantiation of the sac handler failed."); |
| goto cleanup; |
| } |
| |
| sac_handler->start_page = parse_page_start_page_cb; |
| sac_handler->property = parse_page_property_cb; |
| sac_handler->end_page = parse_page_end_page_cb; |
| sac_handler->unrecoverable_error = parse_page_unrecoverable_error_cb; |
| |
| status = cr_parser_set_sac_handler (parser, sac_handler); |
| if (status != CR_OK) |
| goto cleanup; |
| |
| /*Now, invoke the parser to parse the "@page production" */ |
| cr_parser_try_to_skip_spaces_and_comments (parser); |
| if (status != CR_OK) |
| goto cleanup; |
| status = cr_parser_parse_page (parser); |
| if (status != CR_OK) |
| goto cleanup; |
| |
| resultptr = &result; |
| status = cr_doc_handler_get_result (sac_handler, |
| (gpointer *) resultptr); |
| |
| cleanup: |
| |
| if (parser) { |
| cr_parser_destroy (parser); |
| parser = NULL; |
| sac_handler = NULL ; |
| } |
| if (sac_handler) { |
| cr_doc_handler_unref (sac_handler); |
| sac_handler = NULL; |
| } |
| return result; |
| } |
| |
| /** |
| * cr_statement_new_at_charset_rule: |
| * |
| *@a_charset: the string representing the charset. |
| *Note that the newly built instance of #CRStatement becomes |
| *the owner of a_charset. The caller must not free a_charset !!!. |
| * |
| *Creates a new instance of #CRStatement of type |
| *#CRAtCharsetRule. |
| * |
| *Returns the newly built instance of #CRStatement or NULL |
| *if an error arises. |
| */ |
| CRStatement * |
| cr_statement_new_at_charset_rule (CRStyleSheet * a_sheet, |
| CRString * a_charset) |
| { |
| CRStatement *result = NULL; |
| |
| g_return_val_if_fail (a_charset, NULL); |
| |
| result = g_try_malloc (sizeof (CRStatement)); |
| |
| if (!result) { |
| cr_utils_trace_info ("Out of memory"); |
| return NULL; |
| } |
| |
| memset (result, 0, sizeof (CRStatement)); |
| result->type = AT_CHARSET_RULE_STMT; |
| |
| result->kind.charset_rule = g_try_malloc (sizeof (CRAtCharsetRule)); |
| |
| if (!result->kind.charset_rule) { |
| cr_utils_trace_info ("Out of memory"); |
| g_free (result); |
| return NULL; |
| } |
| memset (result->kind.charset_rule, 0, sizeof (CRAtCharsetRule)); |
| result->kind.charset_rule->charset = a_charset; |
| cr_statement_set_parent_sheet (result, a_sheet); |
| |
| return result; |
| } |
| |
| /** |
| * cr_statement_at_charset_rule_parse_from_buf: |
| * |
| *@a_buf: the buffer to parse. |
| *@a_encoding: the character encoding of the buffer. |
| * |
| *Parses a buffer that contains an '\@charset' rule and |
| *creates an instance of #CRStatement of type AT_CHARSET_RULE_STMT. |
| * |
| *Returns the newly built instance of #CRStatement. |
| */ |
| CRStatement * |
| cr_statement_at_charset_rule_parse_from_buf (const guchar * a_buf, |
| enum CREncoding a_encoding) |
| { |
| enum CRStatus status = CR_OK; |
| CRParser *parser = NULL; |
| CRStatement *result = NULL; |
| CRString *charset = NULL; |
| |
| g_return_val_if_fail (a_buf, NULL); |
| |
| parser = cr_parser_new_from_buf ((guchar*)a_buf, strlen ((const char *) a_buf), |
| a_encoding, FALSE); |
| if (!parser) { |
| cr_utils_trace_info ("Instantiation of the parser failed."); |
| goto cleanup; |
| } |
| |
| /*Now, invoke the parser to parse the "@charset production" */ |
| cr_parser_try_to_skip_spaces_and_comments (parser); |
| if (status != CR_OK) |
| goto cleanup; |
| status = cr_parser_parse_charset (parser, &charset, NULL); |
| if (status != CR_OK || !charset) |
| goto cleanup; |
| |
| result = cr_statement_new_at_charset_rule (NULL, charset); |
| if (result) |
| charset = NULL; |
| |
| cleanup: |
| |
| if (parser) { |
| cr_parser_destroy (parser); |
| parser = NULL; |
| } |
| if (charset) { |
| cr_string_destroy (charset); |
| } |
| |
| return result; |
| } |
| |
| /** |
| * cr_statement_new_at_font_face_rule: |
| * |
| *@a_font_decls: a list of instances of #CRDeclaration. Each declaration |
| *is actually a font declaration. |
| * |
| *Creates an instance of #CRStatement of type #CRAtFontFaceRule. |
| * |
| *Returns the newly built instance of #CRStatement. |
| */ |
| CRStatement * |
| cr_statement_new_at_font_face_rule (CRStyleSheet * a_sheet, |
| CRDeclaration * a_font_decls) |
| { |
| CRStatement *result = NULL; |
| |
| result = g_try_malloc (sizeof (CRStatement)); |
| |
| if (!result) { |
| cr_utils_trace_info ("Out of memory"); |
| return NULL; |
| } |
| memset (result, 0, sizeof (CRStatement)); |
| result->type = AT_FONT_FACE_RULE_STMT; |
| |
| result->kind.font_face_rule = g_try_malloc |
| (sizeof (CRAtFontFaceRule)); |
| |
| if (!result->kind.font_face_rule) { |
| cr_utils_trace_info ("Out of memory"); |
| g_free (result); |
| return NULL; |
| } |
| memset (result->kind.font_face_rule, 0, sizeof (CRAtFontFaceRule)); |
| |
| result->kind.font_face_rule->decl_list = a_font_decls; |
| if (a_sheet) |
| cr_statement_set_parent_sheet (result, a_sheet); |
| |
| return result; |
| } |
| |
| /** |
| * cr_statement_font_face_rule_parse_from_buf: |
| * |
| * |
| *@a_buf: the buffer to parse. |
| *@a_encoding: the character encoding of a_buf. |
| * |
| *Parses a buffer that contains an "\@font-face" rule and builds |
| *an instance of #CRStatement of type AT_FONT_FACE_RULE_STMT out of it. |
| * |
| *Returns the newly built instance of #CRStatement in case of successufull |
| *parsing, NULL otherwise. |
| */ |
| CRStatement * |
| cr_statement_font_face_rule_parse_from_buf (const guchar * a_buf, |
| enum CREncoding a_encoding) |
| { |
| CRStatement *result = NULL; |
| CRStatement **resultptr = NULL; |
| CRParser *parser = NULL; |
| CRDocHandler *sac_handler = NULL; |
| enum CRStatus status = CR_OK; |
| |
| parser = cr_parser_new_from_buf ((guchar*)a_buf, strlen ((const char *) a_buf), |
| a_encoding, FALSE); |
| if (!parser) |
| goto cleanup; |
| |
| sac_handler = cr_doc_handler_new (); |
| if (!sac_handler) |
| goto cleanup; |
| |
| /* |
| *set sac callbacks here |
| */ |
| sac_handler->start_font_face = parse_font_face_start_font_face_cb; |
| sac_handler->property = parse_font_face_property_cb; |
| sac_handler->end_font_face = parse_font_face_end_font_face_cb; |
| sac_handler->unrecoverable_error = |
| parse_font_face_unrecoverable_error_cb; |
| |
| status = cr_parser_set_sac_handler (parser, sac_handler); |
| if (status != CR_OK) |
| goto cleanup; |
| |
| /* |
| *cleanup spaces of comment that may be there before the real |
| *"@font-face" thing. |
| */ |
| status = cr_parser_try_to_skip_spaces_and_comments (parser); |
| if (status != CR_OK) |
| goto cleanup; |
| |
| status = cr_parser_parse_font_face (parser); |
| if (status != CR_OK) |
| goto cleanup; |
| |
| resultptr = &result; |
| status = cr_doc_handler_get_result (sac_handler, |
| (gpointer *) resultptr); |
| if (status != CR_OK || !result) |
| goto cleanup; |
| |
| cleanup: |
| if (parser) { |
| cr_parser_destroy (parser); |
| parser = NULL; |
| sac_handler = NULL ; |
| } |
| if (sac_handler) { |
| cr_doc_handler_unref (sac_handler); |
| sac_handler = NULL; |
| } |
| return result; |
| } |
| |
| /** |
| * cr_statement_set_parent_sheet: |
| * |
| *@a_this: the current instance of #CRStatement. |
| *@a_sheet: the sheet that contains the current statement. |
| * |
| *Sets the container stylesheet. |
| * |
| *Returns CR_OK upon successful completion, an error code otherwise. |
| */ |
| enum CRStatus |
| cr_statement_set_parent_sheet (CRStatement * a_this, CRStyleSheet * a_sheet) |
| { |
| g_return_val_if_fail (a_this, CR_BAD_PARAM_ERROR); |
| a_this->parent_sheet = a_sheet; |
| return CR_OK; |
| } |
| |
| /** |
| * cr_statement_get_parent_sheet: |
| * |
| *@a_this: the current #CRStatement. |
| *@a_sheet: out parameter. A pointer to the sheets that |
| * |
| *Gets the sheets that contains the current statement. |
| * |
| *Returns CR_OK upon successful completion, an error code otherwise. |
| */ |
| enum CRStatus |
| cr_statement_get_parent_sheet (CRStatement * a_this, CRStyleSheet ** a_sheet) |
| { |
| g_return_val_if_fail (a_this && a_sheet, CR_BAD_PARAM_ERROR); |
| *a_sheet = a_this->parent_sheet; |
| return CR_OK; |
| } |
| |
| /** |
| * cr_statement_append: |
| * |
| *@a_this: the current instance of the statement list. |
| *@a_new: a_new the new instance of #CRStatement to append. |
| * |
| *Appends a new statement to the statement list. |
| * |
| *Returns the new list statement list, or NULL in cas of failure. |
| */ |
| CRStatement * |
| cr_statement_append (CRStatement * a_this, CRStatement * a_new) |
| { |
| CRStatement *cur = NULL; |
| |
| g_return_val_if_fail (a_new, NULL); |
| |
| if (!a_this) { |
| return a_new; |
| } |
| |
| /*walk forward in the current list to find the tail list element */ |
| for (cur = a_this; cur && cur->next; cur = cur->next) ; |
| |
| cur->next = a_new; |
| a_new->prev = cur; |
| |
| return a_this; |
| } |
| |
| /** |
| * cr_statement_prepend: |
| * |
| *@a_this: the current instance of #CRStatement. |
| *@a_new: the new statement to prepend. |
| * |
| *Prepends the an instance of #CRStatement to |
| *the current statement list. |
| * |
| *Returns the new list with the new statement prepended, |
| *or NULL in case of an error. |
| */ |
| CRStatement * |
| cr_statement_prepend (CRStatement * a_this, CRStatement * a_new) |
| { |
| CRStatement *cur = NULL; |
| |
| g_return_val_if_fail (a_new, NULL); |
| |
| if (!a_this) |
| return a_new; |
| |
| a_new->next = a_this; |
| a_this->prev = a_new; |
| |
| /*walk backward in the prepended list to find the head list element */ |
| for (cur = a_new; cur && cur->prev; cur = cur->prev) ; |
| |
| return cur; |
| } |
| |
| /** |
| * cr_statement_unlink: |
| * |
| *@a_this: the current statements list. |
| *@a_to_unlink: the statement to unlink from the list. |
| * |
| *Unlinks a statement from the statements list. |
| * |
| *Returns the new list where a_to_unlink has been unlinked |
| *from, or NULL in case of error. |
| */ |
| CRStatement * |
| cr_statement_unlink (CRStatement * a_stmt) |
| { |
| CRStatement *result = a_stmt; |
| |
| g_return_val_if_fail (result, NULL); |
| |
| /** |
| *Some sanity checks first |
| */ |
| if (a_stmt->next) { |
| g_return_val_if_fail (a_stmt->next->prev == a_stmt, NULL); |
| } |
| if (a_stmt->prev) { |
| g_return_val_if_fail (a_stmt->prev->next == a_stmt, NULL); |
| } |
| |
| /** |
| *Now, the real unlinking job. |
| */ |
| if (a_stmt->next) { |
| a_stmt->next->prev = a_stmt->prev; |
| } |
| if (a_stmt->prev) { |
| a_stmt->prev->next = a_stmt->next; |
| } |
| |
| if (a_stmt->parent_sheet |
| && a_stmt->parent_sheet->statements == a_stmt) { |
| a_stmt->parent_sheet->statements = |
| a_stmt->parent_sheet->statements->next; |
| } |
| |
| a_stmt->next = NULL; |
| a_stmt->prev = NULL; |
| a_stmt->parent_sheet = NULL; |
| |
| return result; |
| } |
| |
| /** |
| * cr_statement_nr_rules: |
| * |
| *@a_this: the current instance of #CRStatement. |
| * |
| *Gets the number of rules in the statement list; |
| * |
| *Returns number of rules in the statement list. |
| */ |
| gint |
| cr_statement_nr_rules (CRStatement const * a_this) |
| { |
| CRStatement const *cur = NULL; |
| int nr = 0; |
| |
| g_return_val_if_fail (a_this, -1); |
| |
| for (cur = a_this; cur; cur = cur->next) |
| nr++; |
| return nr; |
| } |
| |
| /** |
| * cr_statement_get_from_list: |
| * |
| *@a_this: the current instance of #CRStatement. |
| *@itemnr: the index into the statement list. |
| * |
| *Use an index to get a CRStatement from the statement list. |
| * |
| *Returns CRStatement at position itemnr, if itemnr > number of statements - 1, |
| *it will return NULL. |
| */ |
| CRStatement * |
| cr_statement_get_from_list (CRStatement * a_this, int itemnr) |
| { |
| CRStatement *cur = NULL; |
| int nr = 0; |
| |
| g_return_val_if_fail (a_this, NULL); |
| |
| for (cur = a_this; cur; cur = cur->next) |
| if (nr++ == itemnr) |
| return cur; |
| return NULL; |
| } |
| |
| /** |
| * cr_statement_ruleset_set_sel_list: |
| * |
| *@a_this: the current ruleset statement. |
| *@a_sel_list: the selector list to set. Note |
| *that this function increments the ref count of a_sel_list. |
| *The sel list will be destroyed at the destruction of the |
| *current instance of #CRStatement. |
| * |
| *Sets a selector list to a ruleset statement. |
| * |
| *Returns CR_OK upon successful completion, an error code otherwise. |
| */ |
| enum CRStatus |
| cr_statement_ruleset_set_sel_list (CRStatement * a_this, |
| CRSelector * a_sel_list) |
| { |
| g_return_val_if_fail (a_this && a_this->type == RULESET_STMT, |
| CR_BAD_PARAM_ERROR); |
| |
| if (a_this->kind.ruleset->sel_list) |
| cr_selector_unref (a_this->kind.ruleset->sel_list); |
| |
| a_this->kind.ruleset->sel_list = a_sel_list; |
| |
| if (a_sel_list) |
| cr_selector_ref (a_sel_list); |
| |
| return CR_OK; |
| } |
| |
| /** |
| * cr_statement_ruleset_get_declarations: |
| * |
| *@a_this: the current instance of #CRStatement. |
| *@a_decl_list: out parameter. A pointer to the the returned |
| *list of declaration. Must not be NULL. |
| * |
| *Gets a pointer to the list of declaration contained |
| *in the ruleset statement. |
| * |
| *Returns CR_OK upon successful completion, an error code if something |
| *bad happened. |
| */ |
| enum CRStatus |
| cr_statement_ruleset_get_declarations (CRStatement * a_this, |
| CRDeclaration ** a_decl_list) |
| { |
| g_return_val_if_fail (a_this |
| && a_this->type == RULESET_STMT |
| && a_this->kind.ruleset |
| && a_decl_list, CR_BAD_PARAM_ERROR); |
| |
| *a_decl_list = a_this->kind.ruleset->decl_list; |
| |
| return CR_OK; |
| } |
| |
| /** |
| * cr_statement_ruleset_get_sel_list: |
| * |
| *@a_this: the current ruleset statement. |
| *@a_list: out parameter. The returned selector list, |
| *if and only if the function returned CR_OK. |
| * |
| *Gets a pointer to the selector list contained in |
| *the current ruleset statement. |
| * |
| *Returns CR_OK upon successful completion, an error code otherwise. |
| */ |
| enum CRStatus |
| cr_statement_ruleset_get_sel_list (CRStatement const * a_this, CRSelector ** a_list) |
| { |
| g_return_val_if_fail (a_this && a_this->type == RULESET_STMT |
| && a_this->kind.ruleset, CR_BAD_PARAM_ERROR); |
| |
| *a_list = a_this->kind.ruleset->sel_list; |
| |
| return CR_OK; |
| } |
| |
| /** |
| * cr_statement_ruleset_set_decl_list: |
| * |
| *@a_this: the current ruleset statement. |
| *@a_list: the declaration list to be added to the current |
| *ruleset statement. |
| * |
| *Sets a declaration list to the current ruleset statement. |
| * |
| *Returns CR_OK upon successful completion, an error code otherwise. |
| */ |
| enum CRStatus |
| cr_statement_ruleset_set_decl_list (CRStatement * a_this, |
| CRDeclaration * a_list) |
| { |
| g_return_val_if_fail (a_this && a_this->type == RULESET_STMT |
| && a_this->kind.ruleset, CR_BAD_PARAM_ERROR); |
| |
| if (a_this->kind.ruleset->decl_list == a_list) |
| return CR_OK; |
| |
| if (a_this->kind.ruleset->sel_list) { |
| cr_declaration_destroy (a_this->kind.ruleset->decl_list); |
| } |
| |
| a_this->kind.ruleset->sel_list = NULL; |
| |
| return CR_OK; |
| } |
| |
| /** |
| * cr_statement_ruleset_append_decl2: |
| * |
| *@a_this: the current statement. |
| *@a_prop: the property of the declaration. |
| *@a_value: the value of the declaration. |
| * |
| *Appends a declaration to the current ruleset statement. |
| * |
| *Returns CR_OK upon successful completion, an error code |
| *otherwise. |
| */ |
| enum CRStatus |
| cr_statement_ruleset_append_decl2 (CRStatement * a_this, |
| CRString * a_prop, |
| CRTerm * a_value) |
| { |
| CRDeclaration *new_decls = NULL; |
| |
| g_return_val_if_fail (a_this && a_this->type == RULESET_STMT |
| && a_this->kind.ruleset, CR_BAD_PARAM_ERROR); |
| |
| new_decls = cr_declaration_append2 |
| (a_this->kind.ruleset->decl_list, |
| a_prop, a_value); |
| g_return_val_if_fail (new_decls, CR_ERROR); |
| a_this->kind.ruleset->decl_list = new_decls; |
| |
| return CR_OK; |
| } |
| |
| /** |
| * cr_statement_ruleset_append_decl: |
| * |
| *Appends a declaration to the current statement. |
| * |
| *@a_this: the current statement. |
| *@a_declaration: the declaration to append. |
| * |
| *Returns CR_OK upon sucessful completion, an error code |
| *otherwise. |
| */ |
| enum CRStatus |
| cr_statement_ruleset_append_decl (CRStatement * a_this, |
| CRDeclaration * a_decl) |
| { |
| CRDeclaration *new_decls = NULL; |
| |
| g_return_val_if_fail (a_this && a_this->type == RULESET_STMT |
| && a_this->kind.ruleset, CR_BAD_PARAM_ERROR); |
| |
| new_decls = cr_declaration_append |
| (a_this->kind.ruleset->decl_list, a_decl); |
| g_return_val_if_fail (new_decls, CR_ERROR); |
| a_this->kind.ruleset->decl_list = new_decls; |
| |
| return CR_OK; |
| } |
| |
| /** |
| * cr_statement_at_import_rule_set_imported_sheet: |
| * |
| *Sets a stylesheet to the current \@import rule. |
| *@a_this: the current \@import rule. |
| *@a_sheet: the stylesheet. The stylesheet is owned |
| *by the current instance of #CRStatement, that is, the |
| *stylesheet will be destroyed when the current instance |
| *of #CRStatement is destroyed. |
| * |
| *Returns CR_OK upon successful completion, an error code otherwise. |
| */ |
| enum CRStatus |
| cr_statement_at_import_rule_set_imported_sheet (CRStatement * a_this, |
| CRStyleSheet * a_sheet) |
| { |
| g_return_val_if_fail (a_this |
| && a_this->type == AT_IMPORT_RULE_STMT |
| && a_this->kind.import_rule, |
| CR_BAD_PARAM_ERROR); |
| |
| a_this->kind.import_rule->sheet = a_sheet; |
| |
| return CR_OK; |
| } |
| |
| /** |
| * cr_statement_at_import_rule_get_imported_sheet: |
| * |
| *@a_this: the current \@import rule statement. |
| *@a_sheet: out parameter. The returned stylesheet if and |
| *only if the function returns CR_OK. |
| * |
| *Gets the stylesheet contained by the \@import rule statement. |
| *Returns CR_OK upon sucessful completion, an error code otherwise. |
| */ |
| enum CRStatus |
| cr_statement_at_import_rule_get_imported_sheet (CRStatement * a_this, |
| CRStyleSheet ** a_sheet) |
| { |
| g_return_val_if_fail (a_this |
| && a_this->type == AT_IMPORT_RULE_STMT |
| && a_this->kind.import_rule, |
| CR_BAD_PARAM_ERROR); |
| *a_sheet = a_this->kind.import_rule->sheet; |
| return CR_OK; |
| |
| } |
| |
| /** |
| * cr_statement_at_import_rule_set_url: |
| * |
| *@a_this: the current \@import rule statement. |
| *@a_url: the url to set. |
| * |
| *Sets an url to the current \@import rule statement. |
| * |
| *Returns CR_OK upon successful completion, an error code otherwise. |
| */ |
| enum CRStatus |
| cr_statement_at_import_rule_set_url (CRStatement * a_this, |
| CRString * a_url) |
| { |
| g_return_val_if_fail (a_this |
| && a_this->type == AT_IMPORT_RULE_STMT |
| && a_this->kind.import_rule, |
| CR_BAD_PARAM_ERROR); |
| |
| if (a_this->kind.import_rule->url) { |
| cr_string_destroy (a_this->kind.import_rule->url); |
| } |
| |
| a_this->kind.import_rule->url = a_url; |
| |
| return CR_OK; |
| } |
| |
| /** |
| * cr_statement_at_import_rule_get_url: |
| * |
| *@a_this: the current \@import rule statement. |
| *@a_url: out parameter. The returned url if |
| *and only if the function returned CR_OK. |
| * |
| *Gets the url of the \@import rule statement. |
| *Returns CR_OK upon successful completion, an error code otherwise. |
| */ |
| enum CRStatus |
| cr_statement_at_import_rule_get_url (CRStatement const * a_this, |
| CRString ** a_url) |
| { |
| g_return_val_if_fail (a_this |
| && a_this->type == AT_IMPORT_RULE_STMT |
| && a_this->kind.import_rule, |
| CR_BAD_PARAM_ERROR); |
| |
| *a_url = a_this->kind.import_rule->url; |
| |
| return CR_OK; |
| } |
| |
| /** |
| * cr_statement_at_media_nr_rules: |
| * |
| *@a_this: the current instance of #CRStatement. |
| * |
| *Returns the number of rules in the media rule; |
| */ |
| int |
| cr_statement_at_media_nr_rules (CRStatement const * a_this) |
| { |
| g_return_val_if_fail (a_this |
| && a_this->type == AT_MEDIA_RULE_STMT |
| && a_this->kind.media_rule, CR_BAD_PARAM_ERROR); |
| |
| return cr_statement_nr_rules (a_this->kind.media_rule->rulesets); |
| } |
| |
| /** |
| * cr_statement_at_media_get_from_list: |
| * |
| *@a_this: the current instance of #CRStatement. |
| *@itemnr: the index into the media rule list of rules. |
| * |
| *Use an index to get a CRStatement from the media rule list of rules. |
| * |
| *Returns CRStatement at position itemnr, if itemnr > number of rules - 1, |
| *it will return NULL. |
| */ |
| CRStatement * |
| cr_statement_at_media_get_from_list (CRStatement * a_this, int itemnr) |
| { |
| g_return_val_if_fail (a_this |
| && a_this->type == AT_MEDIA_RULE_STMT |
| && a_this->kind.media_rule, NULL); |
| |
| return cr_statement_get_from_list (a_this->kind.media_rule->rulesets, |
| itemnr); |
| } |
| |
| /** |
| * cr_statement_at_page_rule_set_declarations: |
| * |
| *@a_this: the current \@page rule statement. |
| *@a_decl_list: the declaration list to add. Will be freed |
| *by the current instance of #CRStatement when it is destroyed. |
| * |
| *Sets a declaration list to the current \@page rule statement. |
| * |
| *Returns CR_OK upon successful completion, an error code otherwise. |
| */ |
| enum CRStatus |
| cr_statement_at_page_rule_set_declarations (CRStatement * a_this, |
| CRDeclaration * a_decl_list) |
| { |
| g_return_val_if_fail (a_this |
| && a_this->type == AT_PAGE_RULE_STMT |
| && a_this->kind.page_rule, CR_BAD_PARAM_ERROR); |
| |
| if (a_this->kind.page_rule->decl_list) { |
| cr_declaration_unref (a_this->kind.page_rule->decl_list); |
| } |
| |
| a_this->kind.page_rule->decl_list = a_decl_list; |
| |
| if (a_decl_list) { |
| cr_declaration_ref (a_decl_list); |
| } |
| |
| return CR_OK; |
| } |
| |
| /** |
| * cr_statement_at_page_rule_get_declarations: |
| * |
| *@a_this: the current \@page rule statement. |
| *@a_decl_list: out parameter. The returned declaration list. |
| * |
| *Gets the declaration list associated to the current \@page rule |
| *statement. |
| * |
| *Returns CR_OK upon successful completion, an error code otherwise. |
| */ |
| enum CRStatus |
| cr_statement_at_page_rule_get_declarations (CRStatement * a_this, |
| CRDeclaration ** a_decl_list) |
| { |
| g_return_val_if_fail (a_this |
| && a_this->type == AT_PAGE_RULE_STMT |
| && a_this->kind.page_rule, CR_BAD_PARAM_ERROR); |
| |
| *a_decl_list = a_this->kind.page_rule->decl_list; |
| |
| return CR_OK; |
| } |
| |
| /** |
| * cr_statement_at_charset_rule_set_charset: |
| * |
| * |
| *@a_this: the current \@charset rule statement. |
| *@a_charset: the charset to set. |
| * |
| *Sets the charset of the current \@charset rule statement. |
| * |
| *Returns CR_OK upon successful completion, an error code otherwise. |
| */ |
| enum CRStatus |
| cr_statement_at_charset_rule_set_charset (CRStatement * a_this, |
| CRString * a_charset) |
| { |
| g_return_val_if_fail (a_this |
| && a_this->type == AT_CHARSET_RULE_STMT |
| && a_this->kind.charset_rule, |
| CR_BAD_PARAM_ERROR); |
| |
| if (a_this->kind.charset_rule->charset) { |
| cr_string_destroy (a_this->kind.charset_rule->charset); |
| } |
| a_this->kind.charset_rule->charset = a_charset; |
| return CR_OK; |
| } |
| |
| /** |
| * cr_statement_at_charset_rule_get_charset: |
| *@a_this: the current \@charset rule statement. |
| *@a_charset: out parameter. The returned charset string if |
| *and only if the function returned CR_OK. |
| * |
| *Gets the charset string associated to the current |
| *\@charset rule statement. |
| * |
| * Returns CR_OK upon successful completion, an error code otherwise. |
| */ |
| enum CRStatus |
| cr_statement_at_charset_rule_get_charset (CRStatement const * a_this, |
| CRString ** a_charset) |
| { |
| g_return_val_if_fail (a_this |
| && a_this->type == AT_CHARSET_RULE_STMT |
| && a_this->kind.charset_rule, |
| CR_BAD_PARAM_ERROR); |
| |
| *a_charset = a_this->kind.charset_rule->charset; |
| |
| return CR_OK; |
| } |
| |
| /** |
| * cr_statement_at_font_face_rule_set_decls: |
| * |
| *@a_this: the current \@font-face rule statement. |
| *@a_decls: the declarations list to set. |
| * |
| *Sets a declaration list to the current \@font-face rule statement. |
| * |
| *Returns CR_OK upon successful completion, an error code otherwise. |
| */ |
| enum CRStatus |
| cr_statement_at_font_face_rule_set_decls (CRStatement * a_this, |
| CRDeclaration * a_decls) |
| { |
| g_return_val_if_fail (a_this |
| && a_this->type == AT_FONT_FACE_RULE_STMT |
| && a_this->kind.font_face_rule, |
| CR_BAD_PARAM_ERROR); |
| |
| if (a_this->kind.font_face_rule->decl_list) { |
| cr_declaration_unref (a_this->kind.font_face_rule->decl_list); |
| } |
| |
| a_this->kind.font_face_rule->decl_list = a_decls; |
| cr_declaration_ref (a_decls); |
| |
| return CR_OK; |
| } |
| |
| /** |
| * cr_statement_at_font_face_rule_get_decls: |
| * |
| *@a_this: the current \@font-face rule statement. |
| *@a_decls: out parameter. The returned declaration list if |
| *and only if this function returns CR_OK. |
| * |
| *Gets the declaration list associated to the current instance |
| *of \@font-face rule statement. |
| * |
| *Returns CR_OK upon successful completion, an error code otherwise. |
| */ |
| enum CRStatus |
| cr_statement_at_font_face_rule_get_decls (CRStatement * a_this, |
| CRDeclaration ** a_decls) |
| { |
| g_return_val_if_fail (a_this |
| && a_this->type == AT_FONT_FACE_RULE_STMT |
| && a_this->kind.font_face_rule, |
| CR_BAD_PARAM_ERROR); |
| |
| *a_decls = a_this->kind.font_face_rule->decl_list; |
| |
| return CR_OK; |
| } |
| |
| /** |
| * cr_statement_at_font_face_rule_add_decl: |
| * |
| *@a_this: the current \@font-face rule statement. |
| *@a_prop: the property of the declaration. |
| *@a_value: the value of the declaration. |
| * |
| *Adds a declaration to the current \@font-face rule |
| *statement. |
| * |
| *Returns CR_OK upon successful completion, an error code otherwise. |
| */ |
| enum CRStatus |
| cr_statement_at_font_face_rule_add_decl (CRStatement * a_this, |
| CRString * a_prop, CRTerm * a_value) |
| { |
| CRDeclaration *decls = NULL; |
| |
| g_return_val_if_fail (a_this |
| && a_this->type == AT_FONT_FACE_RULE_STMT |
| && a_this->kind.font_face_rule, |
| CR_BAD_PARAM_ERROR); |
| |
| decls = cr_declaration_append2 |
| (a_this->kind.font_face_rule->decl_list, |
| a_prop, a_value); |
| |
| g_return_val_if_fail (decls, CR_ERROR); |
| |
| if (a_this->kind.font_face_rule->decl_list == NULL) |
| cr_declaration_ref (decls); |
| |
| a_this->kind.font_face_rule->decl_list = decls; |
| |
| return CR_OK; |
| } |
| |
| |
| /** |
| * cr_statement_to_string: |
| * |
| *@a_this: the current statement to serialize |
| *@a_indent: the number of white space of indentation. |
| * |
| *Serializes a css statement into a string |
| * |
| *Returns the serialized statement. Must be freed by the caller |
| *using g_free(). |
| */ |
| gchar * |
| cr_statement_to_string (CRStatement const * a_this, gulong a_indent) |
| { |
| gchar *str = NULL ; |
| |
| if (!a_this) |
| return NULL; |
| |
| switch (a_this->type) { |
| case RULESET_STMT: |
| str = cr_statement_ruleset_to_string |
| (a_this, a_indent); |
| break; |
| |
| case AT_FONT_FACE_RULE_STMT: |
| str = cr_statement_font_face_rule_to_string |
| (a_this, a_indent) ; |
| break; |
| |
| case AT_CHARSET_RULE_STMT: |
| str = cr_statement_charset_to_string |
| (a_this, a_indent); |
| break; |
| |
| case AT_PAGE_RULE_STMT: |
| str = cr_statement_at_page_rule_to_string |
| (a_this, a_indent); |
| break; |
| |
| case AT_MEDIA_RULE_STMT: |
| str = cr_statement_media_rule_to_string |
| (a_this, a_indent); |
| break; |
| |
| case AT_IMPORT_RULE_STMT: |
| str = cr_statement_import_rule_to_string |
| (a_this, a_indent); |
| break; |
| |
| default: |
| cr_utils_trace_info ("Statement unrecognized"); |
| break; |
| } |
| return str ; |
| } |
| |
| gchar* |
| cr_statement_list_to_string (CRStatement const *a_this, gulong a_indent) |
| { |
| CRStatement const *cur_stmt = NULL ; |
| GString *stringue = NULL ; |
| gchar *str = NULL ; |
| |
| g_return_val_if_fail (a_this, NULL) ; |
| |
| stringue = g_string_new (NULL) ; |
| if (!stringue) { |
| cr_utils_trace_info ("Out of memory") ; |
| return NULL ; |
| } |
| for (cur_stmt = a_this ; cur_stmt; |
| cur_stmt = cur_stmt->next) { |
| str = cr_statement_to_string (cur_stmt, a_indent) ; |
| if (str) { |
| if (!cur_stmt->prev) { |
| g_string_append (stringue, str) ; |
| } else { |
| g_string_append_printf |
| (stringue, "\n%s", str) ; |
| } |
| g_free (str) ; |
| str = NULL ; |
| } |
| } |
| str = stringue->str ; |
| g_string_free (stringue, FALSE) ; |
| return str ; |
| } |
| |
| /** |
| * cr_statement_dump: |
| * |
| *@a_this: the current css2 statement. |
| *@a_fp: the destination file pointer. |
| *@a_indent: the number of white space indentation characters. |
| * |
| *Dumps the css2 statement to a file. |
| */ |
| void |
| cr_statement_dump (CRStatement const * a_this, FILE * a_fp, gulong a_indent) |
| { |
| gchar *str = NULL ; |
| |
| if (!a_this) |
| return; |
| |
| str = cr_statement_to_string (a_this, a_indent) ; |
| if (str) { |
| fprintf (a_fp, "%s",str) ; |
| g_free (str) ; |
| str = NULL ; |
| } |
| } |
| |
| /** |
| * cr_statement_dump_ruleset: |
| * |
| *@a_this: the current instance of #CRStatement. |
| *@a_fp: the destination file pointer. |
| *@a_indent: the number of indentation white spaces to add. |
| * |
| *Dumps a ruleset statement to a file. |
| */ |
| void |
| cr_statement_dump_ruleset (CRStatement const * a_this, FILE * a_fp, glong a_indent) |
| { |
| gchar *str = NULL; |
| |
| g_return_if_fail (a_fp && a_this); |
| str = cr_statement_ruleset_to_string (a_this, a_indent); |
| if (str) { |
| fprintf (a_fp, "%s", str); |
| g_free (str); |
| str = NULL; |
| } |
| } |
| |
| /** |
| * cr_statement_dump_font_face_rule: |
| * |
| *@a_this: the current instance of font face rule statement. |
| *@a_fp: the destination file pointer. |
| *@a_indent: the number of white space indentation. |
| * |
| *Dumps a font face rule statement to a file. |
| */ |
| void |
| cr_statement_dump_font_face_rule (CRStatement const * a_this, FILE * a_fp, |
| glong a_indent) |
| { |
| gchar *str = NULL ; |
| g_return_if_fail (a_this |
| && a_this->type == AT_FONT_FACE_RULE_STMT); |
| |
| str = cr_statement_font_face_rule_to_string (a_this, |
| a_indent) ; |
| if (str) { |
| fprintf (a_fp, "%s", str) ; |
| g_free (str) ; |
| str = NULL ; |
| } |
| } |
| |
| /** |
| * cr_statement_dump_charset: |
| * |
| *@a_this: the current instance of the \@charset rule statement. |
| *@a_fp: the destination file pointer. |
| *@a_indent: the number of indentation white spaces. |
| * |
| *Dumps an \@charset rule statement to a file. |
| */ |
| void |
| cr_statement_dump_charset (CRStatement const * a_this, FILE * a_fp, gulong a_indent) |
| { |
| gchar *str = NULL; |
| |
| g_return_if_fail (a_this && a_this->type == AT_CHARSET_RULE_STMT); |
| |
| str = cr_statement_charset_to_string (a_this, |
| a_indent) ; |
| if (str) { |
| fprintf (a_fp, "%s", str) ; |
| g_free (str) ; |
| str = NULL ; |
| } |
| } |
| |
| |
| /** |
| * cr_statement_dump_page: |
| * |
| *@a_this: the statement to dump on stdout. |
| *@a_fp: the destination file pointer. |
| *@a_indent: the number of indentation white spaces. |
| * |
| *Dumps an \@page rule statement on stdout. |
| */ |
| void |
| cr_statement_dump_page (CRStatement const * a_this, FILE * a_fp, gulong a_indent) |
| { |
| gchar *str = NULL; |
| |
| g_return_if_fail (a_this |
| && a_this->type == AT_PAGE_RULE_STMT |
| && a_this->kind.page_rule); |
| |
| str = cr_statement_at_page_rule_to_string (a_this, a_indent) ; |
| if (str) { |
| fprintf (a_fp, "%s", str); |
| g_free (str) ; |
| str = NULL ; |
| } |
| } |
| |
| |
| /** |
| * cr_statement_dump_media_rule: |
| * |
| *@a_this: the statement to dump. |
| *@a_fp: the destination file pointer |
| *@a_indent: the number of white spaces indentation. |
| * |
| *Dumps an \@media rule statement to a file. |
| */ |
| void |
| cr_statement_dump_media_rule (CRStatement const * a_this, |
| FILE * a_fp, |
| gulong a_indent) |
| { |
| gchar *str = NULL ; |
| g_return_if_fail (a_this->type == AT_MEDIA_RULE_STMT); |
| |
| str = cr_statement_media_rule_to_string (a_this, a_indent) ; |
| if (str) { |
| fprintf (a_fp, "%s", str) ; |
| g_free (str) ; |
| str = NULL ; |
| } |
| } |
| |
| /** |
| * cr_statement_dump_import_rule: |
| * |
| *@a_fp: the destination file pointer. |
| *@a_indent: the number of white space indentations. |
| * |
| *Dumps an \@import rule statement to a file. |
| */ |
| void |
| cr_statement_dump_import_rule (CRStatement const * a_this, FILE * a_fp, |
| gulong a_indent) |
| { |
| gchar *str = NULL ; |
| g_return_if_fail (a_this |
| && a_this->type == AT_IMPORT_RULE_STMT |
| && a_fp |
| && a_this->kind.import_rule); |
| |
| str = cr_statement_import_rule_to_string (a_this, a_indent) ; |
| if (str) { |
| fprintf (a_fp, "%s", str) ; |
| g_free (str) ; |
| str = NULL ; |
| } |
| } |
| |
| /** |
| * cr_statement_destroy: |
| * |
| * @a_this: the current instance of #CRStatement. |
| * |
| *Destructor of #CRStatement. |
| */ |
| void |
| cr_statement_destroy (CRStatement * a_this) |
| { |
| CRStatement *cur = NULL; |
| |
| g_return_if_fail (a_this); |
| |
| /*go get the tail of the list */ |
| for (cur = a_this; cur && cur->next; cur = cur->next) { |
| cr_statement_clear (cur); |
| } |
| |
| if (cur) |
| cr_statement_clear (cur); |
| |
| if (cur->prev == NULL) { |
| g_free (a_this); |
| return; |
| } |
| |
| /*walk backward and free next element */ |
| for (cur = cur->prev; cur && cur->prev; cur = cur->prev) { |
| if (cur->next) { |
| g_free (cur->next); |
| cur->next = NULL; |
| } |
| } |
| |
| if (!cur) |
| return; |
| |
| /*free the one remaining list */ |
| if (cur->next) { |
| g_free (cur->next); |
| cur->next = NULL; |
| } |
| |
| g_free (cur); |
| cur = NULL; |
| } |