From d23e071cfe835fb504992d439cd302a2c0e3695b Mon Sep 17 00:00:00 2001 From: wangxiao65 <287608437@qq.com> Date: Thu, 3 Dec 2020 14:48:22 +0800 Subject: [PATCH 1/2] move the libcroco sources directly under src/st, remove the libcroco dependency from the meson.build files. --- ...roco-sources-directly-under-src-st-c.patch | 25201 ++++++++++++++++ gnome-shell.spec | 7 +- 2 files changed, 25207 insertions(+), 1 deletion(-) create mode 100644 0001-Include-the-libcroco-sources-directly-under-src-st-c.patch diff --git a/0001-Include-the-libcroco-sources-directly-under-src-st-c.patch b/0001-Include-the-libcroco-sources-directly-under-src-st-c.patch new file mode 100644 index 0000000..2c7e2cf --- /dev/null +++ b/0001-Include-the-libcroco-sources-directly-under-src-st-c.patch @@ -0,0 +1,25201 @@ +From 47758d16ff0acd9edbd8ff6eb3922e59fb14f8bb Mon Sep 17 00:00:00 2001 +From: Federico Mena Quintero +Date: Thu, 21 Nov 2019 14:24:02 -0600 +Subject: [PATCH] Include the libcroco sources directly under src/st/croco + +This is all of the original libcroco, minus these two which we don't use: + + - cr-sel-eng - the CSS selection engine for xmlNode. + - cr-style. + +Part of https://gitlab.gnome.org/GNOME/gnome-shell/issues/1934 +--- + meson.build | 2 - + src/st/croco/cr-additional-sel.c | 500 +++ + src/st/croco/cr-additional-sel.h | 98 + + src/st/croco/cr-attr-sel.c | 235 ++ + src/st/croco/cr-attr-sel.h | 74 + + src/st/croco/cr-cascade.c | 215 ++ + src/st/croco/cr-cascade.h | 74 + + src/st/croco/cr-declaration.c | 801 +++++ + src/st/croco/cr-declaration.h | 136 + + src/st/croco/cr-doc-handler.c | 276 ++ + src/st/croco/cr-doc-handler.h | 298 ++ + src/st/croco/cr-enc-handler.c | 184 ++ + src/st/croco/cr-enc-handler.h | 94 + + src/st/croco/cr-fonts.c | 949 ++++++ + src/st/croco/cr-fonts.h | 315 ++ + src/st/croco/cr-input.c | 1191 ++++++++ + src/st/croco/cr-input.h | 174 ++ + src/st/croco/cr-num.c | 313 ++ + src/st/croco/cr-num.h | 127 + + src/st/croco/cr-om-parser.c | 1142 +++++++ + src/st/croco/cr-om-parser.h | 98 + + src/st/croco/cr-parser.c | 4525 ++++++++++++++++++++++++++++ + src/st/croco/cr-parser.h | 128 + + src/st/croco/cr-parsing-location.c | 172 ++ + src/st/croco/cr-parsing-location.h | 70 + + src/st/croco/cr-prop-list.c | 404 +++ + src/st/croco/cr-prop-list.h | 80 + + src/st/croco/cr-pseudo.c | 167 + + src/st/croco/cr-pseudo.h | 64 + + src/st/croco/cr-rgb.c | 687 +++++ + src/st/croco/cr-rgb.h | 94 + + src/st/croco/cr-selector.c | 306 ++ + src/st/croco/cr-selector.h | 95 + + src/st/croco/cr-simple-sel.c | 325 ++ + src/st/croco/cr-simple-sel.h | 130 + + src/st/croco/cr-statement.c | 2794 +++++++++++++++++ + src/st/croco/cr-statement.h | 440 +++ + src/st/croco/cr-string.c | 168 ++ + src/st/croco/cr-string.h | 76 + + src/st/croco/cr-stylesheet.c | 178 ++ + src/st/croco/cr-stylesheet.h | 102 + + src/st/croco/cr-term.c | 790 +++++ + src/st/croco/cr-term.h | 190 ++ + src/st/croco/cr-tknzr.c | 2762 +++++++++++++++++ + src/st/croco/cr-tknzr.h | 115 + + src/st/croco/cr-token.c | 636 ++++ + src/st/croco/cr-token.h | 212 ++ + src/st/croco/cr-utils.c | 1330 ++++++++ + src/st/croco/cr-utils.h | 246 ++ + src/st/croco/libcroco-config.h | 13 + + src/st/croco/libcroco.h | 42 + + src/st/meson.build | 62 +- + src/st/st-theme-node-private.h | 2 +- + src/st/st-theme-private.h | 2 +- + 54 files changed, 24696 insertions(+), 7 deletions(-) + create mode 100644 src/st/croco/cr-additional-sel.c + create mode 100644 src/st/croco/cr-additional-sel.h + create mode 100644 src/st/croco/cr-attr-sel.c + create mode 100644 src/st/croco/cr-attr-sel.h + create mode 100644 src/st/croco/cr-cascade.c + create mode 100644 src/st/croco/cr-cascade.h + create mode 100644 src/st/croco/cr-declaration.c + create mode 100644 src/st/croco/cr-declaration.h + create mode 100644 src/st/croco/cr-doc-handler.c + create mode 100644 src/st/croco/cr-doc-handler.h + create mode 100644 src/st/croco/cr-enc-handler.c + create mode 100644 src/st/croco/cr-enc-handler.h + create mode 100644 src/st/croco/cr-fonts.c + create mode 100644 src/st/croco/cr-fonts.h + create mode 100644 src/st/croco/cr-input.c + create mode 100644 src/st/croco/cr-input.h + create mode 100644 src/st/croco/cr-num.c + create mode 100644 src/st/croco/cr-num.h + create mode 100644 src/st/croco/cr-om-parser.c + create mode 100644 src/st/croco/cr-om-parser.h + create mode 100644 src/st/croco/cr-parser.c + create mode 100644 src/st/croco/cr-parser.h + create mode 100644 src/st/croco/cr-parsing-location.c + create mode 100644 src/st/croco/cr-parsing-location.h + create mode 100644 src/st/croco/cr-prop-list.c + create mode 100644 src/st/croco/cr-prop-list.h + create mode 100644 src/st/croco/cr-pseudo.c + create mode 100644 src/st/croco/cr-pseudo.h + create mode 100644 src/st/croco/cr-rgb.c + create mode 100644 src/st/croco/cr-rgb.h + create mode 100644 src/st/croco/cr-selector.c + create mode 100644 src/st/croco/cr-selector.h + create mode 100644 src/st/croco/cr-simple-sel.c + create mode 100644 src/st/croco/cr-simple-sel.h + create mode 100644 src/st/croco/cr-statement.c + create mode 100644 src/st/croco/cr-statement.h + create mode 100644 src/st/croco/cr-string.c + create mode 100644 src/st/croco/cr-string.h + create mode 100644 src/st/croco/cr-stylesheet.c + create mode 100644 src/st/croco/cr-stylesheet.h + create mode 100644 src/st/croco/cr-term.c + create mode 100644 src/st/croco/cr-term.h + create mode 100644 src/st/croco/cr-tknzr.c + create mode 100644 src/st/croco/cr-tknzr.h + create mode 100644 src/st/croco/cr-token.c + create mode 100644 src/st/croco/cr-token.h + create mode 100644 src/st/croco/cr-utils.c + create mode 100644 src/st/croco/cr-utils.h + create mode 100644 src/st/croco/libcroco-config.h + create mode 100644 src/st/croco/libcroco.h + +diff --git a/meson.build b/meson.build +index bfe4ee8a6..9c6d5b946 100644 +--- a/meson.build ++++ b/meson.build +@@ -13,7 +13,6 @@ cogl_pc = 'mutter-cogl-' + mutter_api_version + cogl_pango_pc = 'mutter-cogl-pango-' + mutter_api_version + libmutter_pc = 'libmutter-' + mutter_api_version + +-croco_req = '>= 0.6.8' + ecal_req = '>= 3.5.3' + eds_req = '>= 3.17.2' + gcr_req = '>= 3.7.5' +@@ -89,7 +88,6 @@ gio_unix_dep = dependency('gio-unix-2.0', version: gio_req) + gjs_dep = dependency('gjs-1.0', version: gjs_req) + gtk_dep = dependency('gtk+-3.0', version: gtk_req) + libxml_dep = dependency('libxml-2.0') +-croco_dep = dependency('libcroco-0.6', version: croco_req) + clutter_dep = dependency(clutter_pc, version: mutter_req) + cogl_dep = dependency(cogl_pc, version: mutter_req) + cogl_pango_dep = dependency(cogl_pango_pc, version: mutter_req) +diff --git a/src/st/croco/cr-additional-sel.c b/src/st/croco/cr-additional-sel.c +new file mode 100644 +index 000000000..c34b8d243 +--- /dev/null ++++ b/src/st/croco/cr-additional-sel.c +@@ -0,0 +1,500 @@ ++/* -*- Mode: C; indent-tabs-mode:nil; c-basic-offset: 8-*- */ ++ ++/* ++ * This file is part of The Croco Library ++ * ++ * 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 ++ * See COPYRIGHTS file for copyright information. ++ * ++ */ ++ ++#include "cr-additional-sel.h" ++#include "string.h" ++ ++/** ++ * CRAdditionalSel: ++ * ++ * #CRAdditionalSel abstracts an additionnal selector. ++ * An additional selector is the selector part ++ * that comes after the combination of type selectors. ++ * It can be either "a class selector (the .class part), ++ * a pseudo class selector, an attribute selector ++ * or an id selector. ++ */ ++ ++/** ++ * cr_additional_sel_new: ++ * ++ * Default constructor of #CRAdditionalSel. ++ * Returns the newly build instance of #CRAdditionalSel. ++ */ ++CRAdditionalSel * ++cr_additional_sel_new (void) ++{ ++ CRAdditionalSel *result = NULL; ++ ++ result = g_try_malloc (sizeof (CRAdditionalSel)); ++ ++ if (result == NULL) { ++ cr_utils_trace_debug ("Out of memory"); ++ return NULL; ++ } ++ ++ memset (result, 0, sizeof (CRAdditionalSel)); ++ ++ return result; ++} ++ ++/** ++ * cr_additional_sel_new_with_type: ++ * @a_sel_type: the type of the newly built instance ++ * of #CRAdditionalSel. ++ * ++ * Constructor of #CRAdditionalSel. ++ * Returns the newly built instance of #CRAdditionalSel. ++ */ ++CRAdditionalSel * ++cr_additional_sel_new_with_type (enum AddSelectorType a_sel_type) ++{ ++ CRAdditionalSel *result = NULL; ++ ++ result = cr_additional_sel_new (); ++ ++ g_return_val_if_fail (result, NULL); ++ ++ result->type = a_sel_type; ++ ++ return result; ++} ++ ++/** ++ * cr_additional_sel_set_class_name: ++ * @a_this: the "this pointer" of the current instance ++ * of #CRAdditionalSel . ++ * @a_class_name: the new class name to set. ++ * ++ * Sets a new class name to a ++ * CLASS additional selector. ++ */ ++void ++cr_additional_sel_set_class_name (CRAdditionalSel * a_this, ++ CRString * a_class_name) ++{ ++ g_return_if_fail (a_this && a_this->type == CLASS_ADD_SELECTOR); ++ ++ if (a_this->content.class_name) { ++ cr_string_destroy (a_this->content.class_name); ++ } ++ ++ a_this->content.class_name = a_class_name; ++} ++ ++/** ++ * cr_additional_sel_set_id_name: ++ * @a_this: the "this pointer" of the current instance ++ * of #CRAdditionalSel . ++ * @a_id: the new id to set. ++ * ++ * Sets a new id name to an ++ * ID additional selector. ++ */ ++void ++cr_additional_sel_set_id_name (CRAdditionalSel * a_this, CRString * a_id) ++{ ++ g_return_if_fail (a_this && a_this->type == ID_ADD_SELECTOR); ++ ++ if (a_this->content.id_name) { ++ cr_string_destroy (a_this->content.id_name); ++ } ++ ++ a_this->content.id_name = a_id; ++} ++ ++/** ++ * cr_additional_sel_set_pseudo: ++ * @a_this: the "this pointer" of the current instance ++ * of #CRAdditionalSel . ++ * @a_pseudo: the new pseudo to set. ++ * ++ * Sets a new pseudo to a ++ * PSEUDO additional selector. ++ */ ++void ++cr_additional_sel_set_pseudo (CRAdditionalSel * a_this, CRPseudo * a_pseudo) ++{ ++ g_return_if_fail (a_this ++ && a_this->type == PSEUDO_CLASS_ADD_SELECTOR); ++ ++ if (a_this->content.pseudo) { ++ cr_pseudo_destroy (a_this->content.pseudo); ++ } ++ ++ a_this->content.pseudo = a_pseudo; ++} ++ ++/** ++ * cr_additional_sel_set_attr_sel: ++ * @a_this: the "this pointer" of the current instance ++ * of #CRAdditionalSel . ++ * @a_sel: the new instance of #CRAttrSel to set. ++ * ++ * Sets a new instance of #CRAttrSel to ++ * a ATTRIBUTE additional selector. ++ */ ++void ++cr_additional_sel_set_attr_sel (CRAdditionalSel * a_this, CRAttrSel * a_sel) ++{ ++ g_return_if_fail (a_this && a_this->type == ATTRIBUTE_ADD_SELECTOR); ++ ++ if (a_this->content.attr_sel) { ++ cr_attr_sel_destroy (a_this->content.attr_sel); ++ } ++ ++ a_this->content.attr_sel = a_sel; ++} ++ ++/** ++ * cr_additional_sel_append: ++ * @a_this: the "this pointer" of the current instance ++ * of #CRAdditionalSel . ++ * @a_sel: the new instance to #CRAdditional to append. ++ * ++ * Appends a new instance of #CRAdditional to the ++ * current list of #CRAdditional. ++ * ++ * Returns the new list of CRAdditionalSel or NULL if an error arises. ++ */ ++CRAdditionalSel * ++cr_additional_sel_append (CRAdditionalSel * a_this, CRAdditionalSel * a_sel) ++{ ++ CRAdditionalSel *cur_sel = NULL; ++ ++ g_return_val_if_fail (a_sel, NULL); ++ ++ if (a_this == NULL) { ++ return a_sel; ++ } ++ ++ if (a_sel == NULL) ++ return NULL; ++ ++ for (cur_sel = a_this; ++ cur_sel && cur_sel->next; cur_sel = cur_sel->next) ; ++ ++ g_return_val_if_fail (cur_sel != NULL, NULL); ++ ++ cur_sel->next = a_sel; ++ a_sel->prev = cur_sel; ++ ++ return a_this; ++} ++ ++/** ++ * cr_additional_sel_prepend: ++ * @a_this: the "this pointer" of the current instance ++ * of #CRAdditionalSel . ++ * @a_sel: the new instance to #CRAdditional to preappend. ++ * ++ * Preppends a new instance of #CRAdditional to the ++ * current list of #CRAdditional. ++ * ++ * Returns the new list of CRAdditionalSel or NULL if an error arises. ++ */ ++CRAdditionalSel * ++cr_additional_sel_prepend (CRAdditionalSel * a_this, CRAdditionalSel * a_sel) ++{ ++ g_return_val_if_fail (a_sel, NULL); ++ ++ if (a_this == NULL) { ++ return a_sel; ++ } ++ ++ a_sel->next = a_this; ++ a_this->prev = a_sel; ++ ++ return a_sel; ++} ++ ++guchar * ++cr_additional_sel_to_string (CRAdditionalSel const * a_this) ++{ ++ guchar *result = NULL; ++ GString *str_buf = NULL; ++ CRAdditionalSel const *cur = NULL; ++ ++ g_return_val_if_fail (a_this, NULL); ++ ++ str_buf = g_string_new (NULL); ++ ++ for (cur = a_this; cur; cur = cur->next) { ++ switch (cur->type) { ++ case CLASS_ADD_SELECTOR: ++ { ++ guchar *name = NULL; ++ ++ if (cur->content.class_name) { ++ name = (guchar *) g_strndup ++ (cur->content.class_name->stryng->str, ++ cur->content.class_name->stryng->len); ++ ++ if (name) { ++ g_string_append_printf ++ (str_buf, ".%s", ++ name); ++ g_free (name); ++ name = NULL; ++ } ++ } ++ } ++ break; ++ ++ case ID_ADD_SELECTOR: ++ { ++ guchar *name = NULL; ++ ++ if (cur->content.id_name) { ++ name = (guchar *) g_strndup ++ (cur->content.id_name->stryng->str, ++ cur->content.id_name->stryng->len); ++ ++ if (name) { ++ g_string_append_printf ++ (str_buf, "#%s", ++ name); ++ g_free (name); ++ name = NULL; ++ } ++ } ++ } ++ ++ break; ++ ++ case PSEUDO_CLASS_ADD_SELECTOR: ++ { ++ if (cur->content.pseudo) { ++ guchar *tmp_str = NULL; ++ ++ tmp_str = cr_pseudo_to_string ++ (cur->content.pseudo); ++ if (tmp_str) { ++ g_string_append_printf ++ (str_buf, ":%s", ++ tmp_str); ++ g_free (tmp_str); ++ tmp_str = NULL; ++ } ++ } ++ } ++ break; ++ ++ case ATTRIBUTE_ADD_SELECTOR: ++ if (cur->content.attr_sel) { ++ guchar *tmp_str = NULL; ++ ++ g_string_append_c (str_buf, '['); ++ tmp_str = cr_attr_sel_to_string ++ (cur->content.attr_sel); ++ if (tmp_str) { ++ g_string_append_printf ++ (str_buf, "%s]", tmp_str); ++ g_free (tmp_str); ++ tmp_str = NULL; ++ } ++ } ++ break; ++ ++ default: ++ break; ++ } ++ } ++ ++ if (str_buf) { ++ result = (guchar *) str_buf->str; ++ g_string_free (str_buf, FALSE); ++ str_buf = NULL; ++ } ++ ++ return result; ++} ++ ++guchar * ++cr_additional_sel_one_to_string (CRAdditionalSel const *a_this) ++{ ++ guchar *result = NULL; ++ GString *str_buf = NULL; ++ ++ g_return_val_if_fail (a_this, NULL) ; ++ ++ str_buf = g_string_new (NULL) ; ++ ++ switch (a_this->type) { ++ case CLASS_ADD_SELECTOR: ++ { ++ guchar *name = NULL; ++ ++ if (a_this->content.class_name) { ++ name = (guchar *) g_strndup ++ (a_this->content.class_name->stryng->str, ++ a_this->content.class_name->stryng->len); ++ ++ if (name) { ++ g_string_append_printf ++ (str_buf, ".%s", ++ name); ++ g_free (name); ++ name = NULL; ++ } ++ } ++ } ++ break; ++ ++ case ID_ADD_SELECTOR: ++ { ++ guchar *name = NULL; ++ ++ if (a_this->content.id_name) { ++ name = (guchar *) g_strndup ++ (a_this->content.id_name->stryng->str, ++ a_this->content.id_name->stryng->len); ++ ++ if (name) { ++ g_string_append_printf ++ (str_buf, "#%s", ++ name); ++ g_free (name); ++ name = NULL; ++ } ++ } ++ } ++ ++ break; ++ ++ case PSEUDO_CLASS_ADD_SELECTOR: ++ { ++ if (a_this->content.pseudo) { ++ guchar *tmp_str = NULL; ++ ++ tmp_str = cr_pseudo_to_string ++ (a_this->content.pseudo); ++ if (tmp_str) { ++ g_string_append_printf ++ (str_buf, ":%s", ++ tmp_str); ++ g_free (tmp_str); ++ tmp_str = NULL; ++ } ++ } ++ } ++ break; ++ ++ case ATTRIBUTE_ADD_SELECTOR: ++ if (a_this->content.attr_sel) { ++ guchar *tmp_str = NULL; ++ ++ g_string_append_printf (str_buf, "["); ++ tmp_str = cr_attr_sel_to_string ++ (a_this->content.attr_sel); ++ if (tmp_str) { ++ g_string_append_printf ++ (str_buf, "%s]", tmp_str); ++ g_free (tmp_str); ++ tmp_str = NULL; ++ } ++ } ++ break; ++ ++ default: ++ break; ++ } ++ ++ if (str_buf) { ++ result = (guchar *) str_buf->str; ++ g_string_free (str_buf, FALSE); ++ str_buf = NULL; ++ } ++ ++ return result; ++} ++ ++/** ++ * cr_additional_sel_dump: ++ * @a_this: the "this pointer" of the current instance of ++ * #CRAdditionalSel. ++ * @a_fp: the destination file. ++ * ++ * Dumps the current instance of #CRAdditionalSel to a file ++ */ ++void ++cr_additional_sel_dump (CRAdditionalSel const * a_this, FILE * a_fp) ++{ ++ guchar *tmp_str = NULL; ++ ++ g_return_if_fail (a_fp); ++ ++ if (a_this) { ++ tmp_str = cr_additional_sel_to_string (a_this); ++ if (tmp_str) { ++ fprintf (a_fp, "%s", tmp_str); ++ g_free (tmp_str); ++ tmp_str = NULL; ++ } ++ } ++} ++ ++/** ++ * cr_additional_sel_destroy: ++ * @a_this: the "this pointer" of the current instance ++ * of #CRAdditionalSel . ++ * ++ * Destroys an instance of #CRAdditional. ++ */ ++void ++cr_additional_sel_destroy (CRAdditionalSel * a_this) ++{ ++ g_return_if_fail (a_this); ++ ++ switch (a_this->type) { ++ case CLASS_ADD_SELECTOR: ++ cr_string_destroy (a_this->content.class_name); ++ a_this->content.class_name = NULL; ++ break; ++ ++ case PSEUDO_CLASS_ADD_SELECTOR: ++ cr_pseudo_destroy (a_this->content.pseudo); ++ a_this->content.pseudo = NULL; ++ break; ++ ++ case ID_ADD_SELECTOR: ++ cr_string_destroy (a_this->content.id_name); ++ a_this->content.id_name = NULL; ++ break; ++ ++ case ATTRIBUTE_ADD_SELECTOR: ++ cr_attr_sel_destroy (a_this->content.attr_sel); ++ a_this->content.attr_sel = NULL; ++ break; ++ ++ default: ++ break; ++ } ++ ++ if (a_this->next) { ++ cr_additional_sel_destroy (a_this->next); ++ } ++ ++ g_free (a_this); ++} +diff --git a/src/st/croco/cr-additional-sel.h b/src/st/croco/cr-additional-sel.h +new file mode 100644 +index 000000000..7ca3e07d5 +--- /dev/null ++++ b/src/st/croco/cr-additional-sel.h +@@ -0,0 +1,98 @@ ++/* -*- Mode: C; indent-tabs-mode:nil; c-basic-offset: 8-*- */ ++ ++/* ++ * This file is part of The Croco Library ++ * ++ * 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 ++ * See the COPYRIGHTS file for copyright information. ++ */ ++ ++ ++#ifndef __CR_ADD_SEL_H__ ++#define __CR_ADD_SEL_H__ ++ ++#include ++#include ++#include "cr-utils.h" ++#include "cr-attr-sel.h" ++#include "cr-pseudo.h" ++#include "cr-additional-sel.h" ++ ++G_BEGIN_DECLS ++ ++enum AddSelectorType ++{ ++ NO_ADD_SELECTOR = 0 , ++ CLASS_ADD_SELECTOR = 1 , ++ PSEUDO_CLASS_ADD_SELECTOR = 1 << 1, ++ ID_ADD_SELECTOR = 1 << 3, ++ ATTRIBUTE_ADD_SELECTOR = 1 << 4 ++} ; ++ ++union CRAdditionalSelectorContent ++{ ++ CRString *class_name ; ++ CRString *id_name ; ++ CRPseudo *pseudo ; ++ CRAttrSel *attr_sel ; ++} ; ++ ++typedef struct _CRAdditionalSel CRAdditionalSel ; ++ ++struct _CRAdditionalSel ++{ ++ enum AddSelectorType type ; ++ union CRAdditionalSelectorContent content ; ++ ++ CRAdditionalSel * next ; ++ CRAdditionalSel * prev ; ++ CRParsingLocation location ; ++} ; ++ ++CRAdditionalSel * cr_additional_sel_new (void) ; ++ ++CRAdditionalSel * cr_additional_sel_new_with_type (enum AddSelectorType a_sel_type) ; ++ ++CRAdditionalSel * cr_additional_sel_append (CRAdditionalSel *a_this, ++ CRAdditionalSel *a_sel) ; ++ ++void cr_additional_sel_set_class_name (CRAdditionalSel *a_this, ++ CRString *a_class_name) ; ++ ++void cr_additional_sel_set_id_name (CRAdditionalSel *a_this, ++ CRString *a_id) ; ++ ++void cr_additional_sel_set_pseudo (CRAdditionalSel *a_this, ++ CRPseudo *a_pseudo) ; ++ ++void cr_additional_sel_set_attr_sel (CRAdditionalSel *a_this, ++ CRAttrSel *a_sel) ; ++ ++CRAdditionalSel * cr_additional_sel_prepend (CRAdditionalSel *a_this, ++ CRAdditionalSel *a_sel) ; ++ ++guchar * cr_additional_sel_to_string (CRAdditionalSel const *a_this) ; ++ ++guchar * cr_additional_sel_one_to_string (CRAdditionalSel const *a_this) ; ++ ++void cr_additional_sel_dump (CRAdditionalSel const *a_this, FILE *a_fp) ; ++ ++void cr_additional_sel_destroy (CRAdditionalSel *a_this) ; ++ ++G_END_DECLS ++ ++#endif /*__CR_ADD_SEL_H*/ +diff --git a/src/st/croco/cr-attr-sel.c b/src/st/croco/cr-attr-sel.c +new file mode 100644 +index 000000000..c057bbbf6 +--- /dev/null ++++ b/src/st/croco/cr-attr-sel.c +@@ -0,0 +1,235 @@ ++/* -*- Mode: C; indent-tabs-mode:nil; c-basic-offset: 8-*- */ ++ ++/* ++ * This file is part of The Croco Library ++ * ++ * 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 ++ * ++ * See COPYRIGHTS file for copyrights information. ++ */ ++ ++#include ++#include "cr-attr-sel.h" ++ ++/** ++ * CRAttrSel: ++ * ++ * #CRAdditionalSel abstracts an attribute selector. ++ * Attributes selectors are described in the css2 spec [5.8]. ++ * There are more generally used in the css2 selectors described in ++ * css2 spec [5] . ++ */ ++ ++/** ++ * cr_attr_sel_new: ++ * The constructor of #CRAttrSel. ++ * Returns the newly allocated instance ++ * of #CRAttrSel. ++ */ ++CRAttrSel * ++cr_attr_sel_new (void) ++{ ++ CRAttrSel *result = NULL; ++ ++ result = g_malloc0 (sizeof (CRAttrSel)); ++ ++ return result; ++} ++ ++/** ++ * cr_attr_sel_append_attr_sel: ++ * @a_this: the this pointer of the current instance of #CRAttrSel. ++ * @a_attr_sel: selector to append. ++ * ++ * Appends an attribute selector to the current list of ++ * attribute selectors represented by a_this. ++ * Returns CR_OK upon successfull completion, an error code otherwise. ++ */ ++enum CRStatus ++cr_attr_sel_append_attr_sel (CRAttrSel * a_this, CRAttrSel * a_attr_sel) ++{ ++ CRAttrSel *cur_sel = NULL; ++ ++ g_return_val_if_fail (a_this && a_attr_sel, ++ CR_BAD_PARAM_ERROR); ++ ++ for (cur_sel = a_this; ++ cur_sel->next; ++ cur_sel = cur_sel->next) ; ++ ++ cur_sel->next = a_attr_sel; ++ a_attr_sel->prev = cur_sel; ++ ++ return CR_OK; ++} ++ ++/** ++ * cr_attr_sel_prepend_attr_sel: ++ *@a_this: the "this pointer" of the current instance *of #CRAttrSel. ++ *@a_attr_sel: the attribute selector to append. ++ * ++ *Prepends an attribute selector to the list of ++ *attributes selector represented by a_this. ++ *Returns CR_OK upon successfull completion, an error code otherwise. ++ */ ++enum CRStatus ++cr_attr_sel_prepend_attr_sel (CRAttrSel * a_this, ++ CRAttrSel * a_attr_sel) ++{ ++ g_return_val_if_fail (a_this && a_attr_sel, ++ CR_BAD_PARAM_ERROR); ++ ++ a_attr_sel->next = a_this; ++ a_this->prev = a_attr_sel; ++ ++ return CR_OK; ++} ++ ++/** ++ * cr_attr_sel_to_string: ++ * @a_this: the current instance of #CRAttrSel. ++ * ++ * Serializes an attribute selector into a string ++ * Returns the serialized attribute selector. ++ */ ++guchar * ++cr_attr_sel_to_string (CRAttrSel const * a_this) ++{ ++ CRAttrSel const *cur = NULL; ++ guchar *result = NULL; ++ GString *str_buf = NULL; ++ ++ g_return_val_if_fail (a_this, NULL); ++ ++ str_buf = g_string_new (NULL); ++ ++ for (cur = a_this; cur; cur = cur->next) { ++ if (cur->prev) { ++ g_string_append_c (str_buf, ' '); ++ } ++ ++ if (cur->name) { ++ guchar *name = NULL; ++ ++ name = (guchar *) g_strndup (cur->name->stryng->str, ++ cur->name->stryng->len); ++ if (name) { ++ g_string_append (str_buf, (const gchar *) name); ++ g_free (name); ++ name = NULL; ++ } ++ } ++ ++ if (cur->value) { ++ guchar *value = NULL; ++ ++ value = (guchar *) g_strndup (cur->value->stryng->str, ++ cur->value->stryng->len); ++ if (value) { ++ switch (cur->match_way) { ++ case SET: ++ break; ++ ++ case EQUALS: ++ g_string_append_c (str_buf, '='); ++ break; ++ ++ case INCLUDES: ++ g_string_append (str_buf, "~="); ++ break; ++ ++ case DASHMATCH: ++ g_string_append (str_buf, "|="); ++ break; ++ ++ default: ++ break; ++ } ++ ++ g_string_append_printf ++ (str_buf, "\"%s\"", value); ++ ++ g_free (value); ++ value = NULL; ++ } ++ } ++ } ++ ++ if (str_buf) { ++ result = (guchar *) str_buf->str; ++ g_string_free (str_buf, FALSE); ++ } ++ ++ return result; ++} ++ ++/** ++ * cr_attr_sel_dump: ++ * @a_this: the "this pointer" of the current instance of ++ * #CRAttrSel. ++ * @a_fp: the destination file. ++ * ++ * Dumps the current instance of #CRAttrSel to a file. ++ */ ++void ++cr_attr_sel_dump (CRAttrSel const * a_this, FILE * a_fp) ++{ ++ guchar *tmp_str = NULL; ++ ++ g_return_if_fail (a_this); ++ ++ tmp_str = cr_attr_sel_to_string (a_this); ++ ++ if (tmp_str) { ++ fprintf (a_fp, "%s", tmp_str); ++ g_free (tmp_str); ++ tmp_str = NULL; ++ } ++} ++ ++/** ++ *cr_attr_sel_destroy: ++ *@a_this: the "this pointer" of the current ++ *instance of #CRAttrSel. ++ * ++ *Destroys the current instance of #CRAttrSel. ++ *Frees all the fields if they are non null. ++ */ ++void ++cr_attr_sel_destroy (CRAttrSel * a_this) ++{ ++ g_return_if_fail (a_this); ++ ++ if (a_this->name) { ++ cr_string_destroy (a_this->name); ++ a_this->name = NULL; ++ } ++ ++ if (a_this->value) { ++ cr_string_destroy (a_this->value); ++ a_this->value = NULL; ++ } ++ ++ if (a_this->next) { ++ cr_attr_sel_destroy (a_this->next); ++ a_this->next = NULL; ++ } ++ ++ if (a_this) { ++ g_free (a_this); ++ a_this = NULL; ++ } ++} ++ +diff --git a/src/st/croco/cr-attr-sel.h b/src/st/croco/cr-attr-sel.h +new file mode 100644 +index 000000000..82d5a87d7 +--- /dev/null ++++ b/src/st/croco/cr-attr-sel.h +@@ -0,0 +1,74 @@ ++/* -*- Mode: C; indent-tabs-mode:nil; c-basic-offset: 8-*- */ ++ ++/* ++ * This file is part of The Croco Library ++ * ++ * 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 ++ * See COPYRIGHTS file for copyright information. ++ */ ++ ++#ifndef __CR_ATTR_SEL_H__ ++#define __CR_ATTR_SEL_H__ ++ ++#include ++#include ++#include "cr-utils.h" ++#include "cr-parsing-location.h" ++#include "cr-string.h" ++ ++G_BEGIN_DECLS ++ ++ ++struct _CRAttrSel ; ++typedef struct _CRAttrSel CRAttrSel ; ++ ++enum AttrMatchWay ++{ ++ NO_MATCH = 0, ++ SET, ++ EQUALS, ++ INCLUDES, ++ DASHMATCH ++} ; ++ ++struct _CRAttrSel ++{ ++ CRString *name ; ++ CRString *value ; ++ enum AttrMatchWay match_way ; ++ CRAttrSel *next ; ++ CRAttrSel *prev ; ++ CRParsingLocation location ; ++} ; ++ ++CRAttrSel * cr_attr_sel_new (void) ; ++ ++enum CRStatus cr_attr_sel_append_attr_sel (CRAttrSel * a_this, ++ CRAttrSel *a_attr_sel) ; ++ ++enum CRStatus cr_attr_sel_prepend_attr_sel (CRAttrSel *a_this, ++ CRAttrSel *a_attr_sel) ; ++ ++guchar * cr_attr_sel_to_string (CRAttrSel const *a_this) ; ++ ++void cr_attr_sel_dump (CRAttrSel const *a_this, FILE *a_fp) ; ++ ++void cr_attr_sel_destroy (CRAttrSel *a_this) ; ++ ++G_END_DECLS ++ ++#endif /*__CR_ATTR_SEL_H__*/ +diff --git a/src/st/croco/cr-cascade.c b/src/st/croco/cr-cascade.c +new file mode 100644 +index 000000000..b8f827716 +--- /dev/null ++++ b/src/st/croco/cr-cascade.c +@@ -0,0 +1,215 @@ ++/* -*- Mode: C; indent-tabs-mode:nil; c-basic-offset: 8-*- */ ++ ++/* ++ * This file is part of The Croco Library ++ * ++ * Copyright (C) 2002-2003 Dodji Seketeli ++ * ++ * 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 ++ */ ++ ++/* ++ *$Id$ ++ */ ++ ++#include ++#include "cr-cascade.h" ++ ++#define PRIVATE(a_this) ((a_this)->priv) ++ ++struct _CRCascadePriv { ++ /** ++ *the 3 style sheets of the cascade: ++ *author, user, and useragent sheet. ++ *Intended to be addressed by ++ *sheets[ORIGIN_AUTHOR] or sheets[ORIGIN_USER] ++ *of sheets[ORIGIN_UA] ; ++ */ ++ CRStyleSheet *sheets[3]; ++ guint ref_count; ++}; ++ ++/** ++ * cr_cascade_new: ++ *@a_author_sheet: the author origin style sheet. May be NULL. ++ *@a_user_sheet: the user origin style sheet. May be NULL. ++ *@a_ua_sheet: the user agent origin style sheet. May be NULL. ++ * ++ *Constructor of the #CRCascade class. ++ *Note that all three parameters of this ++ *method are ref counted and their refcount is increased. ++ *Their refcount will be decreased at the destruction of ++ *the instance of #CRCascade. ++ *So the caller should not call their destructor. The caller ++ *should call their ref/unref method instead if it wants ++ * ++ *Returns the newly built instance of CRCascade or NULL if ++ *an error arose during constrution. ++ */ ++CRCascade * ++cr_cascade_new (CRStyleSheet * a_author_sheet, ++ CRStyleSheet * a_user_sheet, CRStyleSheet * a_ua_sheet) ++{ ++ CRCascade *result = NULL; ++ ++ result = g_try_malloc (sizeof (CRCascade)); ++ if (!result) { ++ cr_utils_trace_info ("Out of memory"); ++ return NULL; ++ } ++ memset (result, 0, sizeof (CRCascade)); ++ ++ PRIVATE (result) = g_try_malloc (sizeof (CRCascadePriv)); ++ if (!PRIVATE (result)) { ++ cr_utils_trace_info ("Out of memory"); ++ g_free (result); ++ return NULL; ++ } ++ memset (PRIVATE (result), 0, sizeof (CRCascadePriv)); ++ ++ if (a_author_sheet) { ++ cr_cascade_set_sheet (result, a_author_sheet, ORIGIN_AUTHOR); ++ } ++ if (a_user_sheet) { ++ cr_cascade_set_sheet (result, a_user_sheet, ORIGIN_USER); ++ } ++ if (a_ua_sheet) { ++ cr_cascade_set_sheet (result, a_ua_sheet, ORIGIN_UA); ++ } ++ ++ return result; ++} ++ ++/** ++ * cr_cascade_get_sheet: ++ *@a_this: the current instance of #CRCascade. ++ *@a_origin: the origin of the style sheet as ++ *defined in the css2 spec in chapter 6.4. ++ *Gets a given origin sheet. ++ * ++ *Gets a sheet, part of the cascade. ++ *Note that the returned stylesheet ++ *is refcounted so if the caller wants ++ *to manage it's lifecycle, it must use ++ *cr_stylesheet_ref()/cr_stylesheet_unref() instead ++ *of the cr_stylesheet_destroy() method. ++ *Returns the style sheet, or NULL if it does not ++ *exist. ++ */ ++CRStyleSheet * ++cr_cascade_get_sheet (CRCascade * a_this, enum CRStyleOrigin a_origin) ++{ ++ g_return_val_if_fail (a_this ++ && a_origin >= ORIGIN_UA ++ && a_origin < NB_ORIGINS, NULL); ++ ++ return PRIVATE (a_this)->sheets[a_origin]; ++} ++ ++/** ++ * cr_cascade_set_sheet: ++ *@a_this: the current instance of #CRCascade. ++ *@a_sheet: the stylesheet to set. ++ *@a_origin: the origin of the stylesheet. ++ * ++ *Sets a stylesheet in the cascade ++ * ++ *Returns CR_OK upon successfull completion, an error ++ *code otherwise. ++ */ ++enum CRStatus ++cr_cascade_set_sheet (CRCascade * a_this, ++ CRStyleSheet * a_sheet, enum CRStyleOrigin a_origin) ++{ ++ g_return_val_if_fail (a_this ++ && a_sheet ++ && a_origin >= ORIGIN_UA ++ && a_origin < NB_ORIGINS, CR_BAD_PARAM_ERROR); ++ ++ if (PRIVATE (a_this)->sheets[a_origin]) ++ cr_stylesheet_unref (PRIVATE (a_this)->sheets[a_origin]); ++ PRIVATE (a_this)->sheets[a_origin] = a_sheet; ++ cr_stylesheet_ref (a_sheet); ++ a_sheet->origin = a_origin; ++ return CR_OK; ++} ++ ++/** ++ *cr_cascade_ref: ++ *@a_this: the current instance of #CRCascade ++ * ++ *Increases the reference counter of the current instance ++ *of #CRCascade. ++ */ ++void ++cr_cascade_ref (CRCascade * a_this) ++{ ++ g_return_if_fail (a_this && PRIVATE (a_this)); ++ ++ PRIVATE (a_this)->ref_count++; ++} ++ ++/** ++ * cr_cascade_unref: ++ *@a_this: the current instance of ++ *#CRCascade. ++ * ++ *Decrements the reference counter associated ++ *to this instance of #CRCascade. If the reference ++ *counter reaches zero, the instance is destroyed ++ *using cr_cascade_destroy() ++ */ ++void ++cr_cascade_unref (CRCascade * a_this) ++{ ++ g_return_if_fail (a_this && PRIVATE (a_this)); ++ ++ if (PRIVATE (a_this)->ref_count) ++ PRIVATE (a_this)->ref_count--; ++ if (!PRIVATE (a_this)->ref_count) { ++ cr_cascade_destroy (a_this); ++ } ++} ++ ++/** ++ * cr_cascade_destroy: ++ * @a_this: the current instance of #CRCascade ++ * ++ * Destructor of #CRCascade. ++ */ ++void ++cr_cascade_destroy (CRCascade * a_this) ++{ ++ g_return_if_fail (a_this); ++ ++ if (PRIVATE (a_this)) { ++ gulong i = 0; ++ ++ for (i = 0; PRIVATE (a_this)->sheets && i < NB_ORIGINS; i++) { ++ if (PRIVATE (a_this)->sheets[i]) { ++ if (cr_stylesheet_unref ++ (PRIVATE (a_this)->sheets[i]) ++ == TRUE) { ++ PRIVATE (a_this)->sheets[i] = NULL; ++ } ++ } ++ } ++ g_free (PRIVATE (a_this)); ++ PRIVATE (a_this) = NULL; ++ } ++ g_free (a_this); ++} +diff --git a/src/st/croco/cr-cascade.h b/src/st/croco/cr-cascade.h +new file mode 100644 +index 000000000..3119ae85f +--- /dev/null ++++ b/src/st/croco/cr-cascade.h +@@ -0,0 +1,74 @@ ++/* -*- Mode: C; indent-tabs-mode:nil; c-basic-offset: 8-*- */ ++ ++/* ++ * This file is part of The Croco Library ++ * ++ * 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 ++ * ++ */ ++ ++/* ++ *$Id$ ++ */ ++ ++#ifndef __CR_CASCADE_H__ ++#define __CR_CASCADE_H__ ++ ++#include "cr-stylesheet.h" ++ ++/** ++ *@file ++ *the declaration of the #CRCascade class. ++ */ ++ ++G_BEGIN_DECLS ++ ++ ++typedef struct _CRCascadePriv CRCascadePriv ; ++ ++/** ++ *An abstraction of the "Cascade" defined ++ *in the css2 spec, chapter 6.4. ++ */ ++typedef struct _CRCascade CRCascade ; ++ ++struct _CRCascade ++{ ++ CRCascadePriv *priv ; ++}; ++ ++ ++CRCascade * cr_cascade_new (CRStyleSheet *a_author_sheet, ++ CRStyleSheet *a_user_sheet, ++ CRStyleSheet *a_ua_sheet) ; ++ ++CRStyleSheet * cr_cascade_get_sheet (CRCascade *a_this, ++ enum CRStyleOrigin a_origin) ; ++ ++enum CRStatus cr_cascade_set_sheet (CRCascade *a_this, ++ CRStyleSheet *a_sheet, ++ enum CRStyleOrigin a_origin) ; ++ ++void cr_cascade_ref (CRCascade *a_this) ; ++ ++void cr_cascade_unref (CRCascade *a_this) ; ++ ++void cr_cascade_destroy (CRCascade *a_this) ; ++ ++G_END_DECLS ++ ++#endif /*__CR_CASCADE_H__*/ +diff --git a/src/st/croco/cr-declaration.c b/src/st/croco/cr-declaration.c +new file mode 100644 +index 000000000..2a13c8266 +--- /dev/null ++++ b/src/st/croco/cr-declaration.c +@@ -0,0 +1,801 @@ ++/* -*- Mode: C; indent-tabs-mode: nil; c-basic-offset: 8 -*- */ ++ ++/* ++ * This file is part of The Croco Library ++ * ++ * 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. ++ * See COPYRIGHTS file for copyright information. ++ */ ++ ++ ++#include ++#include "cr-declaration.h" ++#include "cr-statement.h" ++#include "cr-parser.h" ++ ++/** ++ *@CRDeclaration: ++ * ++ *The definition of the #CRDeclaration class. ++ */ ++ ++/** ++ * dump: ++ *@a_this: the current instance of #CRDeclaration. ++ *@a_fp: the destination file pointer. ++ *@a_indent: the number of indentation white char. ++ * ++ *Dumps (serializes) one css declaration to a file. ++ */ ++static void ++dump (CRDeclaration const * a_this, FILE * a_fp, glong a_indent) ++{ ++ guchar *str = NULL; ++ ++ g_return_if_fail (a_this); ++ ++ str = (guchar *) cr_declaration_to_string (a_this, a_indent); ++ if (str) { ++ fprintf (a_fp, "%s", str); ++ g_free (str); ++ str = NULL; ++ } ++} ++ ++/** ++ * cr_declaration_new: ++ * @a_statement: the statement this declaration belongs to. can be NULL. ++ *@a_property: the property string of the declaration ++ *@a_value: the value expression of the declaration. ++ *Constructor of #CRDeclaration. ++ * ++ *Returns the newly built instance of #CRDeclaration, or NULL in ++ *case of error. ++ * ++ *The returned CRDeclaration takes ownership of @a_property and @a_value. ++ *(E.g. cr_declaration_destroy on this CRDeclaration will also free ++ *@a_property and @a_value.) ++ */ ++CRDeclaration * ++cr_declaration_new (CRStatement * a_statement, ++ CRString * a_property, CRTerm * a_value) ++{ ++ CRDeclaration *result = NULL; ++ ++ g_return_val_if_fail (a_property, NULL); ++ ++ if (a_statement) ++ g_return_val_if_fail (a_statement ++ && ((a_statement->type == RULESET_STMT) ++ || (a_statement->type ++ == AT_FONT_FACE_RULE_STMT) ++ || (a_statement->type ++ == AT_PAGE_RULE_STMT)), NULL); ++ ++ result = g_try_malloc (sizeof (CRDeclaration)); ++ if (!result) { ++ cr_utils_trace_info ("Out of memory"); ++ return NULL; ++ } ++ memset (result, 0, sizeof (CRDeclaration)); ++ result->property = a_property; ++ result->value = a_value; ++ ++ if (a_value) { ++ cr_term_ref (a_value); ++ } ++ result->parent_statement = a_statement; ++ return result; ++} ++ ++/** ++ * cr_declaration_parse_from_buf: ++ *@a_statement: the parent css2 statement of this ++ *this declaration. Must be non NULL and of type ++ *RULESET_STMT (must be a ruleset). ++ *@a_str: the string that contains the statement. ++ *@a_enc: the encoding of a_str. ++ * ++ *Parses a text buffer that contains ++ *a css declaration. ++ *Returns the parsed declaration, or NULL in case of error. ++ */ ++CRDeclaration * ++cr_declaration_parse_from_buf (CRStatement * a_statement, ++ const guchar * a_str, enum CREncoding a_enc) ++{ ++ enum CRStatus status = CR_OK; ++ CRTerm *value = NULL; ++ CRString *property = NULL; ++ CRDeclaration *result = NULL; ++ CRParser *parser = NULL; ++ gboolean important = FALSE; ++ ++ g_return_val_if_fail (a_str, NULL); ++ if (a_statement) ++ g_return_val_if_fail (a_statement->type == RULESET_STMT, ++ NULL); ++ ++ parser = cr_parser_new_from_buf ((guchar*)a_str, strlen ((const char *) a_str), a_enc, FALSE); ++ g_return_val_if_fail (parser, NULL); ++ ++ status = cr_parser_try_to_skip_spaces_and_comments (parser); ++ if (status != CR_OK) ++ goto cleanup; ++ ++ status = cr_parser_parse_declaration (parser, &property, ++ &value, &important); ++ if (status != CR_OK || !property) ++ goto cleanup; ++ ++ result = cr_declaration_new (a_statement, property, value); ++ if (result) { ++ property = NULL; ++ value = NULL; ++ result->important = important; ++ } ++ ++ cleanup: ++ ++ if (parser) { ++ cr_parser_destroy (parser); ++ parser = NULL; ++ } ++ ++ if (property) { ++ cr_string_destroy (property); ++ property = NULL; ++ } ++ ++ if (value) { ++ cr_term_destroy (value); ++ value = NULL; ++ } ++ ++ return result; ++} ++ ++/** ++ * cr_declaration_parse_list_from_buf: ++ *@a_str: the input buffer that contains the list of declaration to ++ *parse. ++ *@a_enc: the encoding of a_str ++ * ++ *Parses a ';' separated list of properties declaration. ++ *Returns the parsed list of declaration, NULL if parsing failed. ++ */ ++CRDeclaration * ++cr_declaration_parse_list_from_buf (const guchar * a_str, ++ enum CREncoding a_enc) ++{ ++ ++ enum CRStatus status = CR_OK; ++ CRTerm *value = NULL; ++ CRString *property = NULL; ++ CRDeclaration *result = NULL, ++ *cur_decl = NULL; ++ CRParser *parser = NULL; ++ CRTknzr *tokenizer = NULL; ++ gboolean important = FALSE; ++ ++ g_return_val_if_fail (a_str, NULL); ++ ++ parser = cr_parser_new_from_buf ((guchar*)a_str, strlen ((const char *) a_str), a_enc, FALSE); ++ g_return_val_if_fail (parser, NULL); ++ status = cr_parser_get_tknzr (parser, &tokenizer); ++ if (status != CR_OK || !tokenizer) { ++ if (status == CR_OK) ++ status = CR_ERROR; ++ goto cleanup; ++ } ++ status = cr_parser_try_to_skip_spaces_and_comments (parser); ++ if (status != CR_OK) ++ goto cleanup; ++ ++ status = cr_parser_parse_declaration (parser, &property, ++ &value, &important); ++ if (status != CR_OK || !property) { ++ if (status != CR_OK) ++ status = CR_ERROR; ++ goto cleanup; ++ } ++ result = cr_declaration_new (NULL, property, value); ++ if (result) { ++ property = NULL; ++ value = NULL; ++ result->important = important; ++ } ++ /*now, go parse the other declarations */ ++ for (;;) { ++ guint32 c = 0; ++ ++ cr_parser_try_to_skip_spaces_and_comments (parser); ++ status = cr_tknzr_peek_char (tokenizer, &c); ++ if (status != CR_OK) { ++ if (status == CR_END_OF_INPUT_ERROR) ++ status = CR_OK; ++ goto cleanup; ++ } ++ if (c == ';') { ++ status = cr_tknzr_read_char (tokenizer, &c); ++ } else { ++ break; ++ } ++ important = FALSE; ++ cr_parser_try_to_skip_spaces_and_comments (parser); ++ status = cr_parser_parse_declaration (parser, &property, ++ &value, &important); ++ if (status != CR_OK || !property) { ++ if (status == CR_END_OF_INPUT_ERROR) { ++ status = CR_OK; ++ } ++ break; ++ } ++ cur_decl = cr_declaration_new (NULL, property, value); ++ if (cur_decl) { ++ cur_decl->important = important; ++ result = cr_declaration_append (result, cur_decl); ++ property = NULL; ++ value = NULL; ++ cur_decl = NULL; ++ } else { ++ break; ++ } ++ } ++ ++ cleanup: ++ ++ if (parser) { ++ cr_parser_destroy (parser); ++ parser = NULL; ++ } ++ ++ if (property) { ++ cr_string_destroy (property); ++ property = NULL; ++ } ++ ++ if (value) { ++ cr_term_destroy (value); ++ value = NULL; ++ } ++ ++ if (status != CR_OK && result) { ++ cr_declaration_destroy (result); ++ result = NULL; ++ } ++ return result; ++} ++ ++/** ++ * cr_declaration_append: ++ *@a_this: the current declaration list. ++ *@a_new: the declaration to append. ++ * ++ *Appends a new declaration to the current declarations list. ++ *Returns the declaration list with a_new appended to it, or NULL ++ *in case of error. ++ */ ++CRDeclaration * ++cr_declaration_append (CRDeclaration * a_this, CRDeclaration * a_new) ++{ ++ CRDeclaration *cur = NULL; ++ ++ g_return_val_if_fail (a_new, NULL); ++ ++ if (!a_this) ++ return a_new; ++ ++ for (cur = a_this; cur && cur->next; cur = cur->next) ; ++ ++ cur->next = a_new; ++ a_new->prev = cur; ++ ++ return a_this; ++} ++ ++/** ++ * cr_declaration_unlink: ++ *@a_decls: the declaration to unlink. ++ * ++ *Unlinks the declaration from the declaration list. ++ *case of a successfull completion, NULL otherwise. ++ * ++ *Returns a pointer to the unlinked declaration in ++ */ ++CRDeclaration * ++cr_declaration_unlink (CRDeclaration * a_decl) ++{ ++ CRDeclaration *result = a_decl; ++ ++ g_return_val_if_fail (result, NULL); ++ ++ /* ++ *some sanity checks first ++ */ ++ if (a_decl->prev) { ++ g_return_val_if_fail (a_decl->prev->next == a_decl, NULL); ++ ++ } ++ if (a_decl->next) { ++ g_return_val_if_fail (a_decl->next->prev == a_decl, NULL); ++ } ++ ++ /* ++ *now, the real unlinking job. ++ */ ++ if (a_decl->prev) { ++ a_decl->prev->next = a_decl->next; ++ } ++ if (a_decl->next) { ++ a_decl->next->prev = a_decl->prev; ++ } ++ if (a_decl->parent_statement) { ++ CRDeclaration **children_decl_ptr = NULL; ++ ++ switch (a_decl->parent_statement->type) { ++ case RULESET_STMT: ++ if (a_decl->parent_statement->kind.ruleset) { ++ children_decl_ptr = ++ &a_decl->parent_statement-> ++ kind.ruleset->decl_list; ++ } ++ ++ break; ++ ++ case AT_FONT_FACE_RULE_STMT: ++ if (a_decl->parent_statement->kind.font_face_rule) { ++ children_decl_ptr = ++ &a_decl->parent_statement-> ++ kind.font_face_rule->decl_list; ++ } ++ break; ++ case AT_PAGE_RULE_STMT: ++ if (a_decl->parent_statement->kind.page_rule) { ++ children_decl_ptr = ++ &a_decl->parent_statement-> ++ kind.page_rule->decl_list; ++ } ++ ++ default: ++ break; ++ } ++ if (children_decl_ptr ++ && *children_decl_ptr && *children_decl_ptr == a_decl) ++ *children_decl_ptr = (*children_decl_ptr)->next; ++ } ++ ++ a_decl->next = NULL; ++ a_decl->prev = NULL; ++ a_decl->parent_statement = NULL; ++ ++ return result; ++} ++ ++/** ++ * cr_declaration_prepend: ++ * @a_this: the current declaration list. ++ * @a_new: the declaration to prepend. ++ * ++ * prepends a declaration to the current declaration list. ++ * ++ * Returns the list with a_new prepended or NULL in case of error. ++ */ ++CRDeclaration * ++cr_declaration_prepend (CRDeclaration * a_this, CRDeclaration * a_new) ++{ ++ CRDeclaration *cur = NULL; ++ ++ g_return_val_if_fail (a_new, NULL); ++ ++ if (!a_this) ++ return a_new; ++ ++ a_this->prev = a_new; ++ a_new->next = a_this; ++ ++ for (cur = a_new; cur && cur->prev; cur = cur->prev) ; ++ ++ return cur; ++} ++ ++/** ++ * cr_declaration_append2: ++ *@a_this: the current declaration list. ++ *@a_prop: the property string of the declaration to append. ++ *@a_value: the value of the declaration to append. ++ * ++ *Appends a declaration to the current declaration list. ++ *Returns the list with the new property appended to it, or NULL in ++ *case of an error. ++ */ ++CRDeclaration * ++cr_declaration_append2 (CRDeclaration * a_this, ++ CRString * a_prop, CRTerm * a_value) ++{ ++ CRDeclaration *new_elem = NULL; ++ ++ if (a_this) { ++ new_elem = cr_declaration_new (a_this->parent_statement, ++ a_prop, a_value); ++ } else { ++ new_elem = cr_declaration_new (NULL, a_prop, a_value); ++ } ++ ++ g_return_val_if_fail (new_elem, NULL); ++ ++ return cr_declaration_append (a_this, new_elem); ++} ++ ++/** ++ * cr_declaration_dump: ++ *@a_this: the current instance of #CRDeclaration. ++ *@a_fp: the destination file. ++ *@a_indent: the number of indentation white char. ++ *@a_one_per_line: whether to put one declaration per line of not . ++ * ++ * ++ *Dumps a declaration list to a file. ++ */ ++void ++cr_declaration_dump (CRDeclaration const * a_this, FILE * a_fp, glong a_indent, ++ gboolean a_one_per_line) ++{ ++ CRDeclaration const *cur = NULL; ++ ++ g_return_if_fail (a_this); ++ ++ for (cur = a_this; cur; cur = cur->next) { ++ if (cur->prev) { ++ if (a_one_per_line == TRUE) ++ fprintf (a_fp, ";\n"); ++ else ++ fprintf (a_fp, "; "); ++ } ++ dump (cur, a_fp, a_indent); ++ } ++} ++ ++/** ++ * cr_declaration_dump_one: ++ *@a_this: the current instance of #CRDeclaration. ++ *@a_fp: the destination file. ++ *@a_indent: the number of indentation white char. ++ * ++ *Dumps the first declaration of the declaration list to a file. ++ */ ++void ++cr_declaration_dump_one (CRDeclaration const * a_this, FILE * a_fp, glong a_indent) ++{ ++ g_return_if_fail (a_this); ++ ++ dump (a_this, a_fp, a_indent); ++} ++ ++/** ++ * cr_declaration_to_string: ++ *@a_this: the current instance of #CRDeclaration. ++ *@a_indent: the number of indentation white char ++ *to put before the actual serialisation. ++ * ++ *Serializes the declaration into a string ++ *Returns the serialized form the declaration. The caller must ++ *free the string using g_free(). ++ */ ++gchar * ++cr_declaration_to_string (CRDeclaration const * a_this, gulong a_indent) ++{ ++ GString *stringue = NULL; ++ ++ gchar *str = NULL, ++ *result = NULL; ++ ++ g_return_val_if_fail (a_this, NULL); ++ ++ stringue = g_string_new (NULL); ++ ++ if (a_this->property ++ && a_this->property->stryng ++ && a_this->property->stryng->str) { ++ str = g_strndup (a_this->property->stryng->str, ++ a_this->property->stryng->len); ++ if (str) { ++ cr_utils_dump_n_chars2 (' ', stringue, ++ a_indent); ++ g_string_append (stringue, str); ++ g_free (str); ++ str = NULL; ++ } else ++ goto error; ++ ++ if (a_this->value) { ++ guchar *value_str = NULL; ++ ++ value_str = cr_term_to_string (a_this->value); ++ if (value_str) { ++ g_string_append_printf (stringue, " : %s", ++ value_str); ++ g_free (value_str); ++ } else ++ goto error; ++ } ++ if (a_this->important == TRUE) { ++ g_string_append_printf (stringue, " %s", ++ "!important"); ++ } ++ } ++ if (stringue && stringue->str) { ++ result = stringue->str; ++ g_string_free (stringue, FALSE); ++ } ++ return result; ++ ++ error: ++ if (stringue) { ++ g_string_free (stringue, TRUE); ++ stringue = NULL; ++ } ++ if (str) { ++ g_free (str); ++ str = NULL; ++ } ++ ++ return result; ++} ++ ++/** ++ * cr_declaration_list_to_string: ++ *@a_this: the current instance of #CRDeclaration. ++ *@a_indent: the number of indentation white char ++ *to put before the actual serialisation. ++ * ++ *Serializes the declaration list into a string ++ */ ++guchar * ++cr_declaration_list_to_string (CRDeclaration const * a_this, gulong a_indent) ++{ ++ CRDeclaration const *cur = NULL; ++ GString *stringue = NULL; ++ guchar *str = NULL, ++ *result = NULL; ++ ++ g_return_val_if_fail (a_this, NULL); ++ ++ stringue = g_string_new (NULL); ++ ++ for (cur = a_this; cur; cur = cur->next) { ++ str = (guchar *) cr_declaration_to_string (cur, a_indent); ++ if (str) { ++ g_string_append_printf (stringue, "%s;", str); ++ g_free (str); ++ } else ++ break; ++ } ++ if (stringue && stringue->str) { ++ result = (guchar *) stringue->str; ++ g_string_free (stringue, FALSE); ++ } ++ ++ return result; ++} ++ ++/** ++ * cr_declaration_list_to_string2: ++ *@a_this: the current instance of #CRDeclaration. ++ *@a_indent: the number of indentation white char ++ *@a_one_decl_per_line: whether to output one doc per line or not. ++ *to put before the actual serialisation. ++ * ++ *Serializes the declaration list into a string ++ *Returns the serialized form the declararation. ++ */ ++guchar * ++cr_declaration_list_to_string2 (CRDeclaration const * a_this, ++ gulong a_indent, gboolean a_one_decl_per_line) ++{ ++ CRDeclaration const *cur = NULL; ++ GString *stringue = NULL; ++ guchar *str = NULL, ++ *result = NULL; ++ ++ g_return_val_if_fail (a_this, NULL); ++ ++ stringue = g_string_new (NULL); ++ ++ for (cur = a_this; cur; cur = cur->next) { ++ str = (guchar *) cr_declaration_to_string (cur, a_indent); ++ if (str) { ++ if (a_one_decl_per_line == TRUE) { ++ if (cur->next) ++ g_string_append_printf (stringue, ++ "%s;\n", str); ++ else ++ g_string_append (stringue, ++ (const gchar *) str); ++ } else { ++ if (cur->next) ++ g_string_append_printf (stringue, ++ "%s;", str); ++ else ++ g_string_append (stringue, ++ (const gchar *) str); ++ } ++ g_free (str); ++ } else ++ break; ++ } ++ if (stringue && stringue->str) { ++ result = (guchar *) stringue->str; ++ g_string_free (stringue, FALSE); ++ } ++ ++ return result; ++} ++ ++/** ++ * cr_declaration_nr_props: ++ *@a_this: the current instance of #CRDeclaration. ++ *Return the number of properties in the declaration ++ */ ++gint ++cr_declaration_nr_props (CRDeclaration const * a_this) ++{ ++ CRDeclaration 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_declaration_get_from_list: ++ *@a_this: the current instance of #CRDeclaration. ++ *@itemnr: the index into the declaration list. ++ * ++ *Use an index to get a CRDeclaration from the declaration list. ++ * ++ *Returns #CRDeclaration at position itemnr, ++ *if itemnr > number of declarations - 1, ++ *it will return NULL. ++ */ ++CRDeclaration * ++cr_declaration_get_from_list (CRDeclaration * a_this, int itemnr) ++{ ++ CRDeclaration *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_declaration_get_by_prop_name: ++ *@a_this: the current instance of #CRDeclaration. ++ *@a_prop: the property name to search for. ++ * ++ *Use property name to get a CRDeclaration from the declaration list. ++ *Returns #CRDeclaration with property name a_prop, or NULL if not found. ++ */ ++CRDeclaration * ++cr_declaration_get_by_prop_name (CRDeclaration * a_this, ++ const guchar * a_prop) ++{ ++ CRDeclaration *cur = NULL; ++ ++ g_return_val_if_fail (a_this, NULL); ++ g_return_val_if_fail (a_prop, NULL); ++ ++ for (cur = a_this; cur; cur = cur->next) { ++ if (cur->property ++ && cur->property->stryng ++ && cur->property->stryng->str) { ++ if (!strcmp (cur->property->stryng->str, ++ (const char *) a_prop)) { ++ return cur; ++ } ++ } ++ } ++ return NULL; ++} ++ ++/** ++ * cr_declaration_ref: ++ *@a_this: the current instance of #CRDeclaration. ++ * ++ *Increases the ref count of the current instance of #CRDeclaration. ++ */ ++void ++cr_declaration_ref (CRDeclaration * a_this) ++{ ++ g_return_if_fail (a_this); ++ ++ a_this->ref_count++; ++} ++ ++/** ++ * cr_declaration_unref: ++ *@a_this: the current instance of #CRDeclaration. ++ * ++ *Decrements the ref count of the current instance of #CRDeclaration. ++ *If the ref count reaches zero, the current instance of #CRDeclaration ++ *if destroyed. ++ *Returns TRUE if @a_this was destroyed (ref count reached zero), ++ *FALSE otherwise. ++ */ ++gboolean ++cr_declaration_unref (CRDeclaration * a_this) ++{ ++ g_return_val_if_fail (a_this, FALSE); ++ ++ if (a_this->ref_count) { ++ a_this->ref_count--; ++ } ++ ++ if (a_this->ref_count == 0) { ++ cr_declaration_destroy (a_this); ++ return TRUE; ++ } ++ return FALSE; ++} ++ ++/** ++ * cr_declaration_destroy: ++ *@a_this: the current instance of #CRDeclaration. ++ * ++ *Destructor of the declaration list. ++ */ ++void ++cr_declaration_destroy (CRDeclaration * a_this) ++{ ++ CRDeclaration *cur = NULL; ++ ++ g_return_if_fail (a_this); ++ ++ /* ++ * Go to the last element of the list. ++ */ ++ for (cur = a_this; cur->next; cur = cur->next) ++ g_assert (cur->next->prev == cur); ++ ++ /* ++ * Walk backward the list and free each "next" element. ++ * Meanwhile, free each property/value pair contained in the list. ++ */ ++ for (; cur; cur = cur->prev) { ++ g_free (cur->next); ++ cur->next = NULL; ++ ++ if (cur->property) { ++ cr_string_destroy (cur->property); ++ cur->property = NULL; ++ } ++ ++ if (cur->value) { ++ cr_term_destroy (cur->value); ++ cur->value = NULL; ++ } ++ } ++ ++ g_free (a_this); ++} +diff --git a/src/st/croco/cr-declaration.h b/src/st/croco/cr-declaration.h +new file mode 100644 +index 000000000..eee8be321 +--- /dev/null ++++ b/src/st/croco/cr-declaration.h +@@ -0,0 +1,136 @@ ++/* -*- Mode: C; indent-tabs-mode: nil; c-basic-offset: 8 -*- */ ++ ++/* ++ * This file is part of The Croco Library ++ * ++ * 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 ++ * ++ * See the COPYRIGHTS file for copyright information. ++ */ ++ ++#ifndef __CR_DECLARATION_H__ ++#define __CR_DECLARATION_H__ ++ ++#include ++#include "cr-utils.h" ++#include "cr-term.h" ++#include "cr-parsing-location.h" ++ ++G_BEGIN_DECLS ++ ++/** ++ *@file ++ *The declaration of the #CRDeclaration class. ++ */ ++ ++/*forward declaration of what is defined in cr-statement.h*/ ++typedef struct _CRStatement CRStatement ; ++ ++/** ++ *The abstraction of a css declaration defined by the ++ *css2 spec in chapter 4. ++ *It is actually a chained list of property/value pairs. ++ */ ++typedef struct _CRDeclaration CRDeclaration ; ++struct _CRDeclaration ++{ ++ /**The property.*/ ++ CRString *property ; ++ ++ /**The value of the property.*/ ++ CRTerm *value ; ++ ++ /*the ruleset that contains this declaration*/ ++ CRStatement *parent_statement ; ++ ++ /*the next declaration*/ ++ CRDeclaration *next ; ++ ++ /*the previous one declaration*/ ++ CRDeclaration *prev ; ++ ++ /*does the declaration have the important keyword ?*/ ++ gboolean important ; ++ ++ glong ref_count ; ++ ++ CRParsingLocation location ; ++ /*reserved for future usage*/ ++ gpointer rfu0 ; ++ gpointer rfu1 ; ++ gpointer rfu2 ; ++ gpointer rfu3 ; ++} ; ++ ++ ++CRDeclaration * cr_declaration_new (CRStatement *a_statement, ++ CRString *a_property, ++ CRTerm *a_value) ; ++ ++ ++CRDeclaration * cr_declaration_parse_from_buf (CRStatement *a_statement, ++ const guchar *a_str, ++ enum CREncoding a_enc) ; ++ ++CRDeclaration * cr_declaration_parse_list_from_buf (const guchar *a_str, ++ enum CREncoding a_enc) ; ++ ++CRDeclaration * cr_declaration_append (CRDeclaration *a_this, ++ CRDeclaration *a_new) ; ++ ++CRDeclaration * cr_declaration_append2 (CRDeclaration *a_this, ++ CRString *a_prop, ++ CRTerm *a_value) ; ++ ++CRDeclaration * cr_declaration_prepend (CRDeclaration *a_this, ++ CRDeclaration *a_new) ; ++ ++CRDeclaration * cr_declaration_unlink (CRDeclaration * a_decl) ; ++ ++void ++cr_declaration_dump (CRDeclaration const *a_this, ++ FILE *a_fp, glong a_indent, ++ gboolean a_one_per_line) ; ++ ++void cr_declaration_dump_one (CRDeclaration const *a_this, ++ FILE *a_fp, glong a_indent) ; ++ ++gint cr_declaration_nr_props (CRDeclaration const *a_this) ; ++ ++CRDeclaration * cr_declaration_get_from_list (CRDeclaration *a_this, ++ int itemnr) ; ++ ++CRDeclaration * cr_declaration_get_by_prop_name (CRDeclaration *a_this, ++ const guchar *a_str) ; ++ ++gchar * cr_declaration_to_string (CRDeclaration const *a_this, ++ gulong a_indent) ; ++ ++guchar * cr_declaration_list_to_string (CRDeclaration const *a_this, ++ gulong a_indent) ; ++ ++guchar * cr_declaration_list_to_string2 (CRDeclaration const *a_this, ++ gulong a_indent, ++ gboolean a_one_decl_per_line) ; ++ ++void cr_declaration_ref (CRDeclaration *a_this) ; ++ ++gboolean cr_declaration_unref (CRDeclaration *a_this) ; ++ ++void cr_declaration_destroy (CRDeclaration *a_this) ; ++ ++G_END_DECLS ++ ++#endif /*__CR_DECLARATION_H__*/ +diff --git a/src/st/croco/cr-doc-handler.c b/src/st/croco/cr-doc-handler.c +new file mode 100644 +index 000000000..bbb158298 +--- /dev/null ++++ b/src/st/croco/cr-doc-handler.c +@@ -0,0 +1,276 @@ ++/* -*- Mode: C; indent-tabs-mode: nil; c-basic-offset: 8 -*- */ ++ ++/* ++ * This file is part of The Croco Library ++ * ++ * 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 ++ * ++ * See COPRYRIGHTS file for copyright information. ++ */ ++ ++#include ++#include "cr-doc-handler.h" ++#include "cr-parser.h" ++ ++/** ++ *@CRDocHandler: ++ * ++ *The definition of the CRDocHandler class. ++ *Contains methods to instantiate, destroy, ++ *and initialyze instances of #CRDocHandler ++ *to custom values. ++ */ ++ ++#define PRIVATE(obj) (obj)->priv ++ ++struct _CRDocHandlerPriv { ++ /** ++ *This pointer is to hold an application parsing context. ++ *For example, it used by the Object Model parser to ++ *store it parsing context. #CRParser does not touch it, but ++ *#CROMParser does. #CROMParser allocates this pointer at ++ *the beginning of the css document, and frees it at the end ++ *of the document. ++ */ ++ gpointer context; ++ ++ /** ++ *The place where #CROMParser puts the result of its parsing, if ++ *any. ++ */ ++ gpointer result; ++ /** ++ *a pointer to the parser used to parse ++ *the current document. ++ */ ++ CRParser *parser ; ++}; ++ ++/** ++ * cr_doc_handler_new: ++ *Constructor of #CRDocHandler. ++ * ++ *Returns the newly built instance of ++ *#CRDocHandler ++ * ++ */ ++CRDocHandler * ++cr_doc_handler_new (void) ++{ ++ CRDocHandler *result = NULL; ++ ++ result = g_try_malloc (sizeof (CRDocHandler)); ++ ++ g_return_val_if_fail (result, NULL); ++ ++ memset (result, 0, sizeof (CRDocHandler)); ++ result->ref_count++; ++ ++ result->priv = g_try_malloc (sizeof (CRDocHandlerPriv)); ++ if (!result->priv) { ++ cr_utils_trace_info ("Out of memory exception"); ++ g_free (result); ++ return NULL; ++ } ++ ++ cr_doc_handler_set_default_sac_handler (result); ++ ++ return result; ++} ++ ++/** ++ * cr_doc_handler_get_ctxt: ++ *@a_this: the current instance of #CRDocHandler. ++ *@a_ctxt: out parameter. The new parsing context. ++ * ++ *Gets the private parsing context associated to the document handler ++ *The private parsing context is used by libcroco only. ++ * ++ *Returns CR_OK upon successfull completion, an error code otherwise. ++ */ ++enum CRStatus ++cr_doc_handler_get_ctxt (CRDocHandler const * a_this, gpointer * a_ctxt) ++{ ++ g_return_val_if_fail (a_this && a_this->priv, CR_BAD_PARAM_ERROR); ++ ++ *a_ctxt = a_this->priv->context; ++ ++ return CR_OK; ++} ++ ++/** ++ * cr_doc_handler_set_ctxt: ++ *@a_this: the current instance of #CRDocHandler ++ *@a_ctxt: a pointer to the parsing context. ++ * ++ *Sets the private parsing context. ++ *This is used by libcroco only. ++ *Returns CR_OK upon successfull completion, an error code otherwise. ++ */ ++enum CRStatus ++cr_doc_handler_set_ctxt (CRDocHandler * a_this, gpointer a_ctxt) ++{ ++ g_return_val_if_fail (a_this && a_this->priv, CR_BAD_PARAM_ERROR); ++ a_this->priv->context = a_ctxt; ++ return CR_OK; ++} ++ ++/** ++ * cr_doc_handler_get_result: ++ *@a_this: the current instance of #CRDocHandler ++ *@a_result: out parameter. The returned result. ++ * ++ *Gets the private parsing result. ++ *The private parsing result is used by libcroco only. ++ * ++ *Returns CR_OK upon successfull completion, an error code otherwise. ++ */ ++enum CRStatus ++cr_doc_handler_get_result (CRDocHandler const * a_this, gpointer * a_result) ++{ ++ g_return_val_if_fail (a_this && a_this->priv, CR_BAD_PARAM_ERROR); ++ ++ *a_result = a_this->priv->result; ++ ++ return CR_OK; ++} ++ ++/** ++ * cr_doc_handler_set_result: ++ *@a_this: the current instance of #CRDocHandler ++ *@a_result: the new result. ++ * ++ *Sets the private parsing context. ++ *This is used by libcroco only. ++ * ++ *Returns CR_OK upon successfull completion, an error code otherwise. ++ */ ++enum CRStatus ++cr_doc_handler_set_result (CRDocHandler * a_this, gpointer a_result) ++{ ++ g_return_val_if_fail (a_this && a_this->priv, CR_BAD_PARAM_ERROR); ++ a_this->priv->result = a_result; ++ return CR_OK; ++} ++ ++/** ++ *cr_doc_handler_set_default_sac_handler: ++ *@a_this: a pointer to the current instance of #CRDocHandler. ++ * ++ *Sets the sac handlers contained in the current ++ *instance of DocHandler to the default handlers. ++ *For the time being the default handlers are ++ *test handlers. This is expected to change in a ++ *near future, when the libcroco gets a bit debugged. ++ * ++ *Returns CR_OK upon successfull completion, an error code otherwise. ++ */ ++enum CRStatus ++cr_doc_handler_set_default_sac_handler (CRDocHandler * a_this) ++{ ++ g_return_val_if_fail (a_this, CR_BAD_PARAM_ERROR); ++ ++ a_this->start_document = NULL; ++ a_this->end_document = NULL; ++ a_this->import_style = NULL; ++ a_this->namespace_declaration = NULL; ++ a_this->comment = NULL; ++ a_this->start_selector = NULL; ++ a_this->end_selector = NULL; ++ a_this->property = NULL; ++ a_this->start_font_face = NULL; ++ a_this->end_font_face = NULL; ++ a_this->start_media = NULL; ++ a_this->end_media = NULL; ++ a_this->start_page = NULL; ++ a_this->end_page = NULL; ++ a_this->ignorable_at_rule = NULL; ++ a_this->error = NULL; ++ a_this->unrecoverable_error = NULL; ++ return CR_OK; ++} ++ ++/** ++ * cr_doc_handler_ref: ++ *@a_this: the current instance of #CRDocHandler. ++ */ ++void ++cr_doc_handler_ref (CRDocHandler * a_this) ++{ ++ g_return_if_fail (a_this); ++ ++ a_this->ref_count++; ++} ++ ++/** ++ * cr_doc_handler_unref: ++ *@a_this: the currrent instance of #CRDocHandler. ++ * ++ *Decreases the ref count of the current instance of #CRDocHandler. ++ *If the ref count reaches '0' then, destroys the instance. ++ * ++ *Returns TRUE if the instance as been destroyed, FALSE otherwise. ++ */ ++gboolean ++cr_doc_handler_unref (CRDocHandler * a_this) ++{ ++ g_return_val_if_fail (a_this, FALSE); ++ ++ if (a_this->ref_count > 0) { ++ a_this->ref_count--; ++ } ++ ++ if (a_this->ref_count == 0) { ++ cr_doc_handler_destroy (a_this); ++ return TRUE; ++ } ++ return FALSE ; ++} ++ ++/** ++ * cr_doc_handler_destroy: ++ *@a_this: the instance of #CRDocHandler to ++ *destroy. ++ * ++ *The destructor of the #CRDocHandler class. ++ */ ++void ++cr_doc_handler_destroy (CRDocHandler * a_this) ++{ ++ g_return_if_fail (a_this); ++ ++ if (a_this->priv) { ++ g_free (a_this->priv); ++ a_this->priv = NULL; ++ } ++ g_free (a_this); ++} ++ ++/** ++ * cr_doc_handler_associate_a_parser: ++ *Associates a parser to the current document handler ++ * ++ *@a_this: the current instance of document handler. ++ *@a_parser: the parser to associate. ++ */ ++void ++cr_doc_handler_associate_a_parser (CRDocHandler *a_this, ++ gpointer a_parser) ++{ ++ g_return_if_fail (a_this && PRIVATE (a_this) ++ && a_parser) ; ++ ++ PRIVATE (a_this)->parser = a_parser ; ++} +diff --git a/src/st/croco/cr-doc-handler.h b/src/st/croco/cr-doc-handler.h +new file mode 100644 +index 000000000..d12673f31 +--- /dev/null ++++ b/src/st/croco/cr-doc-handler.h +@@ -0,0 +1,298 @@ ++/* -*- Mode: C; indent-tabs-mode: nil; c-basic-offset: 8 -*- */ ++ ++/* ++ * This file is part of The Croco Library ++ * ++ * 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 ++ * ++ * See the COPYRIGHTS file for copyright information. ++ */ ++ ++#ifndef __CR_DOC_HANDLER_H__ ++#define __CR_DOC_HANDLER_H__ ++ ++/** ++ *@file ++ *The declaration of the #CRDocumentHandler class. ++ *This class is actually the parsing events handler. ++ */ ++ ++#include ++#include "cr-utils.h" ++#include "cr-input.h" ++#include "cr-stylesheet.h" ++ ++G_BEGIN_DECLS ++ ++ ++typedef struct _CRDocHandler CRDocHandler ; ++ ++struct _CRDocHandlerPriv ; ++typedef struct _CRDocHandlerPriv CRDocHandlerPriv ; ++ ++ ++/** ++ *The SAC document handler. ++ *An instance of this class is to ++ *be passed to a parser. Then, during the parsing ++ *the parser calls the convenient function pointer ++ *whenever a particular event (a css construction) occurs. ++ */ ++struct _CRDocHandler ++{ ++ CRDocHandlerPriv *priv ; ++ ++ /** ++ *This pointer is to be used by the application for ++ *it custom needs. It is there to extend the doc handler. ++ */ ++ gpointer app_data ; ++ ++ /** ++ *Is called at the beginning of the parsing of the document. ++ *@param a_this a pointer to the current instance of ++ *#CRDocHandler. ++ */ ++ void (*start_document) (CRDocHandler *a_this) ; ++ ++ /** ++ *Is called to notify the end of the parsing of the document. ++ *@param a_this a pointer to the current instance of ++ *#CRDocHandler. ++ */ ++ void (*end_document) (CRDocHandler *a_this) ; ++ ++ /** ++ *Is called to notify an at charset rule. ++ *@param a_this the document handler. ++ *@param a_charset the declared charset. ++ */ ++ void (*charset) (CRDocHandler *a_this, ++ CRString *a_charset, ++ CRParsingLocation *a_charset_sym_location) ; ++ ++ /** ++ *Is called to notify an import statement in ++ *the stylesheet. ++ *@param a_this the current instance of #CRDocHandler. ++ *@param a_media_list a doubly linked list of GString objects. ++ *Each GString object contains a string which is the ++ *destination media for style information. ++ *@param a_uri the uri of the imported style sheet. ++ *@param a_uri_default_ns the default namespace of URI ++ *@param a_location the parsing location of the '\@import' ++ *keyword. ++ *of the imported style sheet. ++ */ ++ void (*import_style) (CRDocHandler *a_this, ++ GList *a_media_list, ++ CRString *a_uri, ++ CRString *a_uri_default_ns, ++ CRParsingLocation *a_location) ; ++ ++ void (*import_style_result) (CRDocHandler *a_this, ++ GList *a_media_list, ++ CRString *a_uri, ++ CRString *a_uri_default_ns, ++ CRStyleSheet *a_sheet) ; ++ ++ /** ++ *Is called to notify a namespace declaration. ++ *Not used yet. ++ *@param a_this the current instance of #CRDocHandler. ++ *@param a_prefix the prefix of the namespace. ++ *@param a_uri the uri of the namespace. ++ *@param a_location the location of the "@namespace" keyword. ++ */ ++ void (*namespace_declaration) (CRDocHandler *a_this, ++ CRString *a_prefix, ++ CRString *a_uri, ++ CRParsingLocation *a_location) ; ++ ++ /** ++ *Is called to notify a comment. ++ *@param a_this a pointer to the current instance ++ *of #CRDocHandler. ++ *@param a_comment the comment. ++ */ ++ void (*comment) (CRDocHandler *a_this, ++ CRString *a_comment) ; ++ ++ /** ++ *Is called to notify the beginning of a rule ++ *statement. ++ *@param a_this the current instance of #CRDocHandler. ++ *@param a_selector_list the list of selectors that precedes ++ *the rule declarations. ++ */ ++ void (*start_selector) (CRDocHandler * a_this, ++ CRSelector *a_selector_list) ; ++ ++ /** ++ *Is called to notify the end of a rule statement. ++ *@param a_this the current instance of #CRDocHandler. ++ *@param a_selector_list the list of selectors that precedes ++ *the rule declarations. This pointer is the same as ++ *the one passed to start_selector() ; ++ */ ++ void (*end_selector) (CRDocHandler *a_this, ++ CRSelector *a_selector_list) ; ++ ++ ++ /** ++ *Is called to notify a declaration. ++ *@param a_this a pointer to the current instance ++ *of #CRDocHandler. ++ *@param a_name the name of the parsed property. ++ *@param a_expression a css expression that represents ++ *the value of the property. A css expression is ++ *actually a linked list of 'terms'. Each term can ++ *be linked to other using operators. ++ * ++ */ ++ void (*property) (CRDocHandler *a_this, ++ CRString *a_name, ++ CRTerm *a_expression, ++ gboolean a_is_important) ; ++ /** ++ *Is called to notify the start of a font face statement. ++ *The parser invokes this method at the beginning of every ++ *font face statement in the style sheet. There will ++ *be a corresponding end_font_face () event for every ++ *start_font_face () event. ++ * ++ *@param a_this a pointer to the current instance of ++ *#CRDocHandler. ++ *@param a_location the parsing location of the "\@font-face" ++ *keyword. ++ */ ++ void (*start_font_face) (CRDocHandler *a_this, ++ CRParsingLocation *a_location) ; ++ ++ /** ++ *Is called to notify the end of a font face statement. ++ *@param a_this a pointer to the current instance of ++ *#CRDocHandler. ++ */ ++ void (*end_font_face) (CRDocHandler *a_this) ; ++ ++ ++ /** ++ *Is called to notify the beginning of a media statement. ++ *The parser will invoke this method at the beginning of ++ *every media statement in the style sheet. There will be ++ *a corresponding end_media() event for every start_media() ++ *event. ++ *@param a_this a pointer to the current instance of ++ *#CRDocHandler. ++ *@param a_media_list a double linked list of ++ #CRString * objects. ++ *Each CRString objects is actually a destination media for ++ *the style information. ++ */ ++ void (*start_media) (CRDocHandler *a_this, ++ GList *a_media_list, ++ CRParsingLocation *a_location) ; ++ ++ /** ++ *Is called to notify the end of a media statement. ++ *@param a_this a pointer to the current instance ++ *of #CRDocHandler. ++ *@param a_media_list a double linked list of GString * objects. ++ *Each GString objects is actually a destination media for ++ *the style information. ++ */ ++ void (*end_media) (CRDocHandler *a_this, ++ GList *a_media_list) ; ++ ++ /** ++ *Is called to notify the beginning of a page statement. ++ *The parser invokes this function at the beginning of ++ *every page statement in the style sheet. There will be ++ *a corresponding end_page() event for every single ++ *start_page() event. ++ *@param a_this a pointer to the current instance of ++ *#CRDocHandler. ++ *@param a_name the name of the page (if any, null otherwise). ++ *@param a_pseudo_page the pseudo page (if any, null otherwise). ++ *@param a_location the parsing location of the "\@page" keyword. ++ */ ++ void (*start_page) (CRDocHandler *a_this, ++ CRString *a_name, ++ CRString *a_pseudo_page, ++ CRParsingLocation *a_location) ; ++ ++ /** ++ *Is called to notify the end of a page statement. ++ *@param a_this a pointer to the current instance of ++ *#CRDocHandler. ++ *@param a_name the name of the page (if any, null otherwise). ++ *@param a_pseudo_page the pseudo page (if any, null otherwise). ++ */ ++ void (*end_page) (CRDocHandler *a_this, ++ CRString *a_name, ++ CRString *pseudo_page) ; ++ ++ /** ++ *Is Called to notify an unknown at-rule not supported ++ *by this parser. ++ */ ++ void (*ignorable_at_rule) (CRDocHandler *a_this, ++ CRString *a_name) ; ++ ++ /** ++ *Is called to notify a parsing error. After this error ++ *the application must ignore the rule being parsed, if ++ *any. After completion of this callback, ++ *the parser will then try to resume the parsing, ++ *ignoring the current error. ++ */ ++ void (*error) (CRDocHandler *a_this) ; ++ ++ /** ++ *Is called to notify an unrecoverable parsing error. ++ *This is the place to put emergency routines that free allocated ++ *resources. ++ */ ++ void (*unrecoverable_error) (CRDocHandler *a_this) ; ++ ++ gboolean resolve_import ; ++ gulong ref_count ; ++} ; ++ ++CRDocHandler * cr_doc_handler_new (void) ; ++ ++enum CRStatus cr_doc_handler_set_result (CRDocHandler *a_this, gpointer a_result) ; ++ ++enum CRStatus cr_doc_handler_get_result (CRDocHandler const *a_this, gpointer * a_result) ; ++ ++enum CRStatus cr_doc_handler_set_ctxt (CRDocHandler *a_this, gpointer a_ctxt) ; ++ ++enum CRStatus cr_doc_handler_get_ctxt (CRDocHandler const *a_this, gpointer * a_ctxt) ; ++ ++enum CRStatus cr_doc_handler_set_default_sac_handler (CRDocHandler *a_this) ; ++ ++void cr_doc_handler_associate_a_parser (CRDocHandler *a_this, ++ gpointer a_parser) ; ++ ++void cr_doc_handler_ref (CRDocHandler *a_this) ; ++ ++gboolean cr_doc_handler_unref (CRDocHandler *a_this) ; ++ ++void cr_doc_handler_destroy (CRDocHandler *a_this) ; ++ ++G_END_DECLS ++ ++#endif /*__CR_DOC_HANDLER_H__*/ +diff --git a/src/st/croco/cr-enc-handler.c b/src/st/croco/cr-enc-handler.c +new file mode 100644 +index 000000000..a7c4269ad +--- /dev/null ++++ b/src/st/croco/cr-enc-handler.c +@@ -0,0 +1,184 @@ ++/* -*- Mode: C; indent-tabs-mode: nil; c-basic-offset: 8 -*- */ ++ ++/* ++ * This file is part of The Croco Library ++ * ++ * Copyright (C) 2002-2003 Dodji Seketeli ++ * ++ * 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 ++ */ ++ ++/* ++ *$Id$ ++ */ ++ ++/** ++ *@file ++ *The definition of the #CREncHandler class. ++ */ ++ ++#include "cr-enc-handler.h" ++#include "cr-utils.h" ++ ++#include ++ ++struct CREncAlias { ++ const gchar *name; ++ enum CREncoding encoding; ++}; ++ ++static struct CREncAlias gv_default_aliases[] = { ++ {"UTF-8", CR_UTF_8}, ++ {"UTF_8", CR_UTF_8}, ++ {"UTF8", CR_UTF_8}, ++ {"UTF-16", CR_UTF_16}, ++ {"UTF_16", CR_UTF_16}, ++ {"UTF16", CR_UTF_16}, ++ {"UCS1", CR_UCS_1}, ++ {"UCS-1", CR_UCS_1}, ++ {"UCS_1", CR_UCS_1}, ++ {"ISO-8859-1", CR_UCS_1}, ++ {"ISO_8859-1", CR_UCS_1}, ++ {"UCS-1", CR_UCS_1}, ++ {"UCS_1", CR_UCS_1}, ++ {"UCS4", CR_UCS_4}, ++ {"UCS-4", CR_UCS_4}, ++ {"UCS_4", CR_UCS_4}, ++ {"ASCII", CR_ASCII}, ++ {0, 0} ++}; ++ ++static CREncHandler gv_default_enc_handlers[] = { ++ {CR_UCS_1, cr_utils_ucs1_to_utf8, cr_utils_utf8_to_ucs1, ++ cr_utils_ucs1_str_len_as_utf8, cr_utils_utf8_str_len_as_ucs1}, ++ ++ {CR_ISO_8859_1, cr_utils_ucs1_to_utf8, cr_utils_utf8_to_ucs1, ++ cr_utils_ucs1_str_len_as_utf8, cr_utils_utf8_str_len_as_ucs1}, ++ ++ {CR_ASCII, cr_utils_ucs1_to_utf8, cr_utils_utf8_to_ucs1, ++ cr_utils_ucs1_str_len_as_utf8, cr_utils_utf8_str_len_as_ucs1}, ++ ++ {0, NULL, NULL, NULL, NULL} ++}; ++ ++/** ++ * cr_enc_handler_get_instance: ++ *@a_enc: the encoding of the Handler. ++ * ++ *Gets the instance of encoding handler. ++ *This function implements a singleton pattern. ++ * ++ *Returns the instance of #CREncHandler. ++ */ ++CREncHandler * ++cr_enc_handler_get_instance (enum CREncoding a_enc) ++{ ++ gulong i = 0; ++ ++ for (i = 0; gv_default_enc_handlers[i].encoding; i++) { ++ if (gv_default_enc_handlers[i].encoding == a_enc) { ++ return (CREncHandler *) & gv_default_enc_handlers[i]; ++ } ++ } ++ ++ return NULL; ++} ++ ++/** ++ * cr_enc_handler_resolve_enc_alias: ++ *@a_alias_name: the encoding name. ++ *@a_enc: output param. The returned encoding type ++ *or 0 if the alias is not supported. ++ * ++ *Given an encoding name (called an alias name) ++ *the function returns the matching encoding type. ++ * ++ *Returns CR_OK upon successfull completion, an error code otherwise. ++ */ ++enum CRStatus ++cr_enc_handler_resolve_enc_alias (const guchar * a_alias_name, ++ enum CREncoding *a_enc) ++{ ++ gulong i = 0; ++ guchar *alias_name_up = NULL; ++ enum CRStatus status = CR_ENCODING_NOT_FOUND_ERROR; ++ ++ g_return_val_if_fail (a_alias_name != NULL, CR_BAD_PARAM_ERROR); ++ ++ alias_name_up = (guchar *) g_ascii_strup ((const gchar *) a_alias_name, -1); ++ ++ for (i = 0; gv_default_aliases[i].name; i++) { ++ if (!strcmp (gv_default_aliases[i].name, (const gchar *) alias_name_up)) { ++ *a_enc = gv_default_aliases[i].encoding; ++ status = CR_OK; ++ break; ++ } ++ } ++ ++ return status; ++} ++ ++/** ++ * cr_enc_handler_convert_input: ++ *@a_this: the current instance of #CREncHandler. ++ *@a_in: the input buffer to convert. ++ *@a_in_len: in/out parameter. The len of the input ++ *buffer to convert. After return, contains the number of ++ *bytes actually consumed. ++ *@a_out: output parameter. The converted output buffer. ++ *Must be freed by the buffer. ++ *@a_out_len: output parameter. The length of the output buffer. ++ * ++ *Converts a raw input buffer into an utf8 buffer. ++ * ++ *Returns CR_OK upon successfull completion, an error code otherwise. ++ */ ++enum CRStatus ++cr_enc_handler_convert_input (CREncHandler * a_this, ++ const guchar * a_in, ++ gulong * a_in_len, ++ guchar ** a_out, gulong * a_out_len) ++{ ++ enum CRStatus status = CR_OK; ++ ++ g_return_val_if_fail (a_this && a_in && a_in_len && a_out, ++ CR_BAD_PARAM_ERROR); ++ ++ if (a_this->decode_input == NULL) ++ return CR_OK; ++ ++ if (a_this->enc_str_len_as_utf8) { ++ status = a_this->enc_str_len_as_utf8 (a_in, ++ &a_in[*a_in_len - 1], ++ a_out_len); ++ ++ g_return_val_if_fail (status == CR_OK, status); ++ } else { ++ *a_out_len = *a_in_len; ++ } ++ ++ *a_out = g_malloc0 (*a_out_len); ++ ++ status = a_this->decode_input (a_in, a_in_len, *a_out, a_out_len); ++ ++ if (status != CR_OK) { ++ g_free (*a_out); ++ *a_out = NULL; ++ } ++ ++ g_return_val_if_fail (status == CR_OK, status); ++ ++ return CR_OK; ++} +diff --git a/src/st/croco/cr-enc-handler.h b/src/st/croco/cr-enc-handler.h +new file mode 100644 +index 000000000..0727764c0 +--- /dev/null ++++ b/src/st/croco/cr-enc-handler.h +@@ -0,0 +1,94 @@ ++/* -*- Mode: C; indent-tabs-mode: nil; c-basic-offset: 8 -*- */ ++ ++/* ++ * This file is part of The Croco Library ++ * ++ * Copyright (C) 2002-2003 Dodji Seketeli ++ * ++ * 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 ++ */ ++ ++/* ++ *$Id$ ++ */ ++ ++/** ++ *@file: ++ *The declaration of the #CREncHandler class. ++ * ++ */ ++ ++#ifndef __CR_ENC_HANDLER_H__ ++#define __CR_ENC_HANDLER_H__ ++ ++#include "cr-utils.h" ++ ++G_BEGIN_DECLS ++ ++ ++typedef struct _CREncHandler CREncHandler ; ++ ++typedef enum CRStatus (*CREncInputFunc) (const guchar * a_in, ++ gulong *a_in_len, ++ guchar *a_out, ++ gulong *a_out_len) ; ++ ++typedef enum CRStatus (*CREncOutputFunc) (const guchar * a_in, ++ gulong *a_in_len, ++ guchar *a_out, ++ gulong *a_out_len) ; ++ ++typedef enum CRStatus (*CREncInputStrLenAsUtf8Func) ++(const guchar *a_in_start, ++ const guchar *a_in_end, ++ gulong *a_in_size); ++ ++typedef enum CRStatus (*CREncUtf8StrLenAsOutputFunc) ++(const guchar *a_in_start, ++ const guchar *a_in_end, ++ gulong *a_in_size) ; ++ ++/** ++ *This class is responsible of the ++ *the encoding conversions stuffs in ++ *libcroco. ++ */ ++ ++struct _CREncHandler ++{ ++ enum CREncoding encoding ; ++ CREncInputFunc decode_input ; ++ CREncInputFunc encode_output ; ++ CREncInputStrLenAsUtf8Func enc_str_len_as_utf8 ; ++ CREncUtf8StrLenAsOutputFunc utf8_str_len_as_enc ; ++} ; ++ ++CREncHandler * ++cr_enc_handler_get_instance (enum CREncoding a_enc) ; ++ ++enum CRStatus ++cr_enc_handler_resolve_enc_alias (const guchar *a_alias_name, ++ enum CREncoding *a_enc) ; ++ ++enum CRStatus ++cr_enc_handler_convert_input (CREncHandler *a_this, ++ const guchar *a_in, ++ gulong *a_in_len, ++ guchar **a_out, ++ gulong *a_out_len) ; ++ ++G_END_DECLS ++ ++#endif /*__CR_ENC_HANDLER_H__*/ +diff --git a/src/st/croco/cr-fonts.c b/src/st/croco/cr-fonts.c +new file mode 100644 +index 000000000..3a5788cea +--- /dev/null ++++ b/src/st/croco/cr-fonts.c +@@ -0,0 +1,949 @@ ++/* -*- Mode: C; indent-tabs-mode:nil; c-basic-offset: 8-*- */ ++ ++/* ++ * This file is part of The Croco Library ++ * ++ * ++ * 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 ++ * ++ *See COPYRIGHTS file for copyright information ++ */ ++ ++#include "cr-fonts.h" ++#include ++ ++static enum CRStatus ++cr_font_family_to_string_real (CRFontFamily const * a_this, ++ gboolean a_walk_list, GString ** a_string) ++{ ++ guchar const *name = NULL; ++ enum CRStatus result = CR_OK; ++ ++ if (!*a_string) { ++ *a_string = g_string_new (NULL); ++ g_return_val_if_fail (*a_string, ++ CR_INSTANCIATION_FAILED_ERROR); ++ } ++ ++ if (!a_this) { ++ g_string_append (*a_string, "NULL"); ++ return CR_OK; ++ } ++ ++ switch (a_this->type) { ++ case FONT_FAMILY_SANS_SERIF: ++ name = (guchar const *) "sans-serif"; ++ break; ++ ++ case FONT_FAMILY_SERIF: ++ name = (guchar const *) "sans-serif"; ++ break; ++ ++ case FONT_FAMILY_CURSIVE: ++ name = (guchar const *) "cursive"; ++ break; ++ ++ case FONT_FAMILY_FANTASY: ++ name = (guchar const *) "fantasy"; ++ break; ++ ++ case FONT_FAMILY_MONOSPACE: ++ name = (guchar const *) "monospace"; ++ break; ++ ++ case FONT_FAMILY_NON_GENERIC: ++ name = (guchar const *) a_this->name; ++ break; ++ ++ default: ++ name = NULL; ++ break; ++ } ++ ++ if (name) { ++ if (a_this->prev) { ++ g_string_append_printf (*a_string, ", %s", name); ++ } else { ++ g_string_append (*a_string, (const gchar *) name); ++ } ++ } ++ if (a_walk_list == TRUE && a_this->next) { ++ result = cr_font_family_to_string_real (a_this->next, ++ TRUE, a_string); ++ } ++ return result; ++} ++ ++static const gchar * ++cr_predefined_absolute_font_size_to_string (enum CRPredefinedAbsoluteFontSize ++ a_code) ++{ ++ gchar const *str = NULL; ++ ++ switch (a_code) { ++ case FONT_SIZE_XX_SMALL: ++ str = "xx-small"; ++ break; ++ case FONT_SIZE_X_SMALL: ++ str = "x-small"; ++ break; ++ case FONT_SIZE_SMALL: ++ str = "small"; ++ break; ++ case FONT_SIZE_MEDIUM: ++ str = "medium"; ++ break; ++ case FONT_SIZE_LARGE: ++ str = "large"; ++ break; ++ case FONT_SIZE_X_LARGE: ++ str = "x-large"; ++ break; ++ case FONT_SIZE_XX_LARGE: ++ str = "xx-large"; ++ break; ++ default: ++ str = "unknown absolute font size value"; ++ } ++ return str; ++} ++ ++static const gchar * ++cr_relative_font_size_to_string (enum CRRelativeFontSize a_code) ++{ ++ gchar const *str = NULL; ++ ++ switch (a_code) { ++ case FONT_SIZE_LARGER: ++ str = "larger"; ++ break; ++ case FONT_SIZE_SMALLER: ++ str = "smaller"; ++ break; ++ default: ++ str = "unknown relative font size value"; ++ break; ++ } ++ return str; ++} ++ ++/** ++ * cr_font_family_new: ++ * @a_type: the type of font family to create. ++ * @a_name: the name of the font family. ++ * ++ * create a font family. ++ * ++ * Returns the newly built font family. ++ */ ++CRFontFamily * ++cr_font_family_new (enum CRFontFamilyType a_type, guchar * a_name) ++{ ++ CRFontFamily *result = NULL; ++ ++ result = g_try_malloc (sizeof (CRFontFamily)); ++ ++ if (!result) { ++ cr_utils_trace_info ("Out of memory"); ++ return NULL; ++ } ++ ++ memset (result, 0, sizeof (CRFontFamily)); ++ result->type = a_type; ++ ++ cr_font_family_set_name (result, a_name); ++ ++ return result; ++} ++ ++/** ++ * cr_font_family_to_string: ++ * @a_this: the current instance of #CRFontFamily. ++ * @a_walk_font_family_list: wether the serialize the entire list. ++ * ++ * Returns the seriliazed font family. The caller has to free it using ++ * g_free(). ++ */ ++guchar * ++cr_font_family_to_string (CRFontFamily const * a_this, ++ gboolean a_walk_font_family_list) ++{ ++ enum CRStatus status = CR_OK; ++ guchar *result = NULL; ++ GString *stringue = NULL; ++ ++ if (!a_this) { ++ result = (guchar *) g_strdup ("NULL"); ++ g_return_val_if_fail (result, NULL); ++ return result; ++ } ++ status = cr_font_family_to_string_real (a_this, ++ a_walk_font_family_list, ++ &stringue); ++ ++ if (status == CR_OK && stringue) { ++ result = (guchar *) stringue->str; ++ g_string_free (stringue, FALSE); ++ stringue = NULL; ++ ++ } else { ++ if (stringue) { ++ g_string_free (stringue, TRUE); ++ stringue = NULL; ++ } ++ } ++ ++ return result; ++} ++ ++/** ++ * cr_font_family_set_name: ++ * @a_this: the current instance of #CRFontFamily. ++ * @a_name: the new name ++ * ++ * Returns CR_OK upon sucessful completion, an error code otherwise. ++ */ ++enum CRStatus ++cr_font_family_set_name (CRFontFamily * a_this, guchar * a_name) ++{ ++ g_return_val_if_fail (a_this, CR_BAD_PARAM_ERROR); ++ ++ /* ++ *only non generic font families can have a name ++ */ ++ ++ if (a_this->type != FONT_FAMILY_NON_GENERIC) { ++ return CR_BAD_PARAM_ERROR; ++ } ++ ++ if (a_this->name) { ++ g_free (a_this->name); ++ a_this->name = NULL; ++ } ++ ++ a_this->name = a_name; ++ return CR_OK; ++} ++ ++/** ++ * cr_font_family_append: ++ * @a_this: the current instance of #CRFontFamily. ++ * @a_family_to_append: the font family to append to the list ++ * ++ * Returns the new font family list. ++ */ ++CRFontFamily * ++cr_font_family_append (CRFontFamily * a_this, ++ CRFontFamily * a_family_to_append) ++{ ++ CRFontFamily *cur_ff = NULL; ++ ++ g_return_val_if_fail (a_family_to_append, NULL); ++ ++ if (!a_this) ++ return a_family_to_append; ++ ++ for (cur_ff = a_this; cur_ff && cur_ff->next; cur_ff = cur_ff->next) ; ++ ++ cur_ff->next = a_family_to_append; ++ a_family_to_append->prev = cur_ff; ++ ++ return a_this; ++ ++} ++ ++/** ++ * cr_font_family_prepend: ++ * @a_this: the current instance #CRFontFamily. ++ * @a_family_to_prepend: the font family to prepend to the list. ++ * ++ * Returns the font family list. ++ */ ++CRFontFamily * ++cr_font_family_prepend (CRFontFamily * a_this, ++ CRFontFamily * a_family_to_prepend) ++{ ++ g_return_val_if_fail (a_this && a_family_to_prepend, NULL); ++ ++ if (!a_this) ++ return a_family_to_prepend; ++ ++ a_family_to_prepend->next = a_this; ++ a_this->prev = a_family_to_prepend; ++ ++ return a_family_to_prepend; ++} ++ ++/** ++ * cr_font_family_destroy: ++ * @a_this: the current instance of #CRFontFamily. ++ * ++ * Returns CR_OK upon sucessful completion, an error code otherwise. ++ */ ++enum CRStatus ++cr_font_family_destroy (CRFontFamily * a_this) ++{ ++ CRFontFamily *cur_ff = NULL; ++ ++ g_return_val_if_fail (a_this, CR_BAD_PARAM_ERROR); ++ ++ for (cur_ff = a_this; cur_ff && cur_ff->next; cur_ff = cur_ff->next) ; ++ ++ for (; cur_ff; cur_ff = cur_ff->prev) { ++ if (a_this->name) { ++ g_free (a_this->name); ++ a_this->name = NULL; ++ } ++ ++ if (cur_ff->next) { ++ g_free (cur_ff->next); ++ ++ } ++ ++ if (cur_ff->prev == NULL) { ++ g_free (a_this); ++ } ++ } ++ ++ return CR_OK; ++} ++ ++/*************************************************** ++ *'font-size' manipulation functions definitions ++ ***************************************************/ ++ ++/** ++ * cr_font_size_new: ++ * ++ * Returns the newly created font size. ++ */ ++CRFontSize * ++cr_font_size_new (void) ++{ ++ CRFontSize *result = NULL; ++ ++ result = g_try_malloc (sizeof (CRFontSize)); ++ if (!result) { ++ cr_utils_trace_info ("Out of memory"); ++ return NULL; ++ } ++ memset (result, 0, sizeof (CRFontSize)); ++ ++ return result; ++} ++ ++/** ++ * cr_font_size_clear: ++ * @a_this: the current instance of #CRFontSize ++ * ++ * Returns CR_OK upon successful completion, an error code otherwise. ++ */ ++enum CRStatus ++cr_font_size_clear (CRFontSize * a_this) ++{ ++ g_return_val_if_fail (a_this, CR_BAD_PARAM_ERROR); ++ ++ switch (a_this->type) { ++ case PREDEFINED_ABSOLUTE_FONT_SIZE: ++ case RELATIVE_FONT_SIZE: ++ case INHERITED_FONT_SIZE: ++ memset (a_this, 0, sizeof (CRFontSize)); ++ break; ++ ++ case ABSOLUTE_FONT_SIZE: ++ memset (a_this, 0, sizeof (CRFontSize)); ++ break; ++ ++ default: ++ return CR_UNKNOWN_TYPE_ERROR; ++ } ++ ++ return CR_OK; ++} ++ ++/** ++ * cr_font_size_copy: ++ * @a_dst: the destination #CRFontSize (where to copy to). ++ * @a_src: the source #CRFontSize (where to copy from). ++ * ++ * Returns CR_OK upon successful completion, an error code otherwise. ++ */ ++enum CRStatus ++cr_font_size_copy (CRFontSize * a_dst, CRFontSize const * a_src) ++{ ++ g_return_val_if_fail (a_dst && a_src, CR_BAD_PARAM_ERROR); ++ ++ switch (a_src->type) { ++ case PREDEFINED_ABSOLUTE_FONT_SIZE: ++ case RELATIVE_FONT_SIZE: ++ case INHERITED_FONT_SIZE: ++ cr_font_size_clear (a_dst); ++ memcpy (a_dst, a_src, sizeof (CRFontSize)); ++ break; ++ ++ case ABSOLUTE_FONT_SIZE: ++ cr_font_size_clear (a_dst); ++ cr_num_copy (&a_dst->value.absolute, ++ &a_src->value.absolute); ++ a_dst->type = a_src->type; ++ break; ++ ++ default: ++ return CR_UNKNOWN_TYPE_ERROR; ++ } ++ return CR_OK; ++} ++ ++/** ++ * cr_font_size_set_predefined_absolute_font_size: ++ * @a_this: the current instance of #CRFontSize. ++ * @a_predefined: what to set. ++ * ++ * Returns CR_OK upon sucessful completion, an error code otherwise. ++ */ ++enum CRStatus ++cr_font_size_set_predefined_absolute_font_size (CRFontSize *a_this, ++ enum CRPredefinedAbsoluteFontSize a_predefined) ++{ ++ g_return_val_if_fail (a_this, CR_BAD_PARAM_ERROR) ; ++ g_return_val_if_fail (a_predefined >= FONT_SIZE_XX_SMALL ++ && a_predefined < NB_PREDEFINED_ABSOLUTE_FONT_SIZES, ++ CR_BAD_PARAM_ERROR) ; ++ ++ a_this->type = PREDEFINED_ABSOLUTE_FONT_SIZE ; ++ a_this->value.predefined = a_predefined ; ++ ++ return CR_OK ; ++} ++ ++/** ++ * cr_font_size_set_relative_font_size: ++ * @a_this: the current instance of #CRFontSize ++ * @a_relative: the new relative font size ++ * ++ * Returns CR_OK upon successful completion, an error code otherwise. ++ */ ++enum CRStatus ++cr_font_size_set_relative_font_size (CRFontSize *a_this, ++ enum CRRelativeFontSize a_relative) ++{ ++ g_return_val_if_fail (a_this, CR_BAD_PARAM_ERROR) ; ++ g_return_val_if_fail (a_relative >= FONT_SIZE_LARGER ++ && a_relative < NB_RELATIVE_FONT_SIZE, ++ CR_BAD_PARAM_ERROR) ; ++ ++ a_this->type = RELATIVE_FONT_SIZE ; ++ a_this->value.relative = a_relative ; ++ return CR_OK ; ++} ++ ++/** ++ * cr_font_size_set_absolute_font_size: ++ * @a_this: the current instance of #CRFontSize ++ * @a_num_type: the type of number to set. ++ * @a_value: the actual value to set. ++ * ++ * Returns CR_OK upon succesful completion, an error code otherwise. ++ */ ++enum CRStatus ++cr_font_size_set_absolute_font_size (CRFontSize *a_this, ++ enum CRNumType a_num_type, ++ gdouble a_value) ++{ ++ g_return_val_if_fail (a_this, CR_BAD_PARAM_ERROR) ; ++ g_return_val_if_fail (a_num_type >= NUM_AUTO ++ && a_num_type < NB_NUM_TYPE, ++ CR_BAD_PARAM_ERROR) ; ++ ++ a_this->type = ABSOLUTE_FONT_SIZE ; ++ cr_num_set (&a_this->value.absolute, ++ a_value, a_num_type) ; ++ return CR_OK ; ++} ++ ++/** ++ * cr_font_size_set_to_inherit: ++ * @a_this: the current instance of #CRFontSize ++ * ++ * Returns CR_OK upon succesful completion, an error code otherwise. ++ */ ++enum CRStatus ++cr_font_size_set_to_inherit (CRFontSize *a_this) ++{ ++ g_return_val_if_fail (a_this, CR_BAD_PARAM_ERROR) ; ++ ++ cr_font_size_clear (a_this) ; ++ a_this->type = INHERITED_FONT_SIZE ; ++ ++ return CR_OK ; ++} ++ ++/** ++ * cr_font_size_is_set_to_inherit: ++ * @a_this: the current instance of #CRFontSize. ++ * ++ * Returns TRUE if the current instance is set to 'inherit'. ++ */ ++gboolean ++cr_font_size_is_set_to_inherit (CRFontSize const *a_this) ++{ ++ g_return_val_if_fail (a_this, FALSE) ; ++ ++ return a_this->type == INHERITED_FONT_SIZE ; ++} ++ ++/** ++ * cr_font_size_to_string: ++ * @a_this: the current instance of #CRFontSize ++ * ++ * Returns the serialized form of #CRFontSize. The returned string ++ * has to bee freed using g_free(). ++ */ ++gchar * ++cr_font_size_to_string (CRFontSize const * a_this) ++{ ++ gchar *str = NULL; ++ ++ if (!a_this) { ++ str = g_strdup ("NULL"); ++ g_return_val_if_fail (str, NULL); ++ return str; ++ } ++ switch (a_this->type) { ++ case PREDEFINED_ABSOLUTE_FONT_SIZE: ++ str = g_strdup (cr_predefined_absolute_font_size_to_string ++ (a_this->value.predefined)); ++ break; ++ case ABSOLUTE_FONT_SIZE: ++ str = (gchar *) cr_num_to_string (&a_this->value.absolute); ++ break; ++ case RELATIVE_FONT_SIZE: ++ str = g_strdup (cr_relative_font_size_to_string ++ (a_this->value.relative)); ++ break; ++ case INHERITED_FONT_SIZE: ++ str = g_strdup ("inherit"); ++ break; ++ default: ++ break; ++ } ++ return str; ++} ++ ++/** ++ * cr_font_size_get_smaller_predefined: ++ * @a_font_size: the font size to consider. ++ * @a_smaller_size: out parameter. The a smaller value than @a_font_size. ++ */ ++void ++cr_font_size_get_smaller_predefined_font_size ++ (enum CRPredefinedAbsoluteFontSize a_font_size, ++ enum CRPredefinedAbsoluteFontSize *a_smaller_size) ++{ ++ enum CRPredefinedAbsoluteFontSize result = FONT_SIZE_MEDIUM ; ++ ++ g_return_if_fail (a_smaller_size) ; ++ g_return_if_fail (a_font_size < NB_PREDEFINED_ABSOLUTE_FONT_SIZES ++ && a_font_size >= FONT_SIZE_XX_SMALL) ; ++ ++ switch (a_font_size) { ++ case FONT_SIZE_XX_SMALL: ++ result = FONT_SIZE_XX_SMALL ; ++ break ; ++ case FONT_SIZE_X_SMALL: ++ result = FONT_SIZE_XX_SMALL ; ++ break ; ++ case FONT_SIZE_SMALL: ++ result = FONT_SIZE_X_SMALL; ++ break ; ++ case FONT_SIZE_MEDIUM: ++ result = FONT_SIZE_SMALL; ++ break ; ++ case FONT_SIZE_LARGE: ++ result = FONT_SIZE_MEDIUM; ++ break ; ++ case FONT_SIZE_X_LARGE: ++ result = FONT_SIZE_LARGE; ++ break ; ++ case FONT_SIZE_XX_LARGE: ++ result = FONT_SIZE_XX_LARGE; ++ break ; ++ case FONT_SIZE_INHERIT: ++ cr_utils_trace_info ("can't return a smaller size for FONT_SIZE_INHERIT") ; ++ result = FONT_SIZE_MEDIUM ; ++ break ; ++ default: ++ cr_utils_trace_info ("Unknown FONT_SIZE") ; ++ result = FONT_SIZE_MEDIUM ; ++ break ; ++ } ++ *a_smaller_size = result ; ++} ++ ++ ++/** ++ * cr_font_size_get_larger_predefined_font_size: ++ * @a_font_size: the font size to consider. ++ * @a_larger_size: out parameter. the font size considered larger than ++ * @a_font_size. ++ * ++ */ ++void ++cr_font_size_get_larger_predefined_font_size ++ (enum CRPredefinedAbsoluteFontSize a_font_size, ++ enum CRPredefinedAbsoluteFontSize *a_larger_size) ++{ ++ enum CRPredefinedAbsoluteFontSize result = FONT_SIZE_MEDIUM ; ++ ++ g_return_if_fail (a_larger_size) ; ++ g_return_if_fail (a_font_size >= FONT_SIZE_XX_SMALL ++ && a_font_size < NB_PREDEFINED_ABSOLUTE_FONT_SIZES) ; ++ ++ switch (a_font_size) { ++ case FONT_SIZE_XX_SMALL: ++ result = FONT_SIZE_X_SMALL ; ++ break ; ++ case FONT_SIZE_X_SMALL: ++ result = FONT_SIZE_SMALL ; ++ break ; ++ case FONT_SIZE_SMALL: ++ result = FONT_SIZE_MEDIUM; ++ break ; ++ case FONT_SIZE_MEDIUM: ++ result = FONT_SIZE_LARGE; ++ break ; ++ case FONT_SIZE_LARGE: ++ result = FONT_SIZE_X_LARGE; ++ break ; ++ case FONT_SIZE_X_LARGE: ++ result = FONT_SIZE_XX_LARGE ; ++ break ; ++ case FONT_SIZE_XX_LARGE: ++ result = FONT_SIZE_XX_LARGE; ++ break ; ++ case FONT_SIZE_INHERIT: ++ cr_utils_trace_info ("can't return a bigger size for FONT_SIZE_INHERIT") ; ++ result = FONT_SIZE_MEDIUM ; ++ break ; ++ default: ++ cr_utils_trace_info ("Unknown FONT_SIZE") ; ++ result = FONT_SIZE_MEDIUM ; ++ break ; ++ } ++ *a_larger_size = result ; ++} ++ ++/** ++ * cr_font_size_is_predefined_absolute_font_size: ++ * @a_font_size: the font size to consider. ++ * ++ * Returns TRUE if the instance is an predefined absolute font size, FALSE ++ * otherwise. ++ */ ++gboolean ++cr_font_size_is_predefined_absolute_font_size ++ (enum CRPredefinedAbsoluteFontSize a_font_size) ++{ ++ if (a_font_size >= FONT_SIZE_XX_SMALL ++ && a_font_size < NB_PREDEFINED_ABSOLUTE_FONT_SIZES) { ++ return TRUE ; ++ } else { ++ return FALSE ; ++ } ++} ++ ++/** ++ * cr_font_size_adjust_to_string: ++ * @a_this: the instance of #CRFontSizeAdjust. ++ * ++ * Returns the serialized form of #CRFontSizeAdjust ++ */ ++gchar * ++cr_font_size_adjust_to_string (CRFontSizeAdjust const * a_this) ++{ ++ gchar *str = NULL; ++ ++ if (!a_this) { ++ str = g_strdup ("NULL"); ++ g_return_val_if_fail (str, NULL); ++ return str; ++ } ++ ++ switch (a_this->type) { ++ case FONT_SIZE_ADJUST_NONE: ++ str = g_strdup ("none"); ++ break; ++ case FONT_SIZE_ADJUST_NUMBER: ++ if (a_this->num) ++ str = (gchar *) cr_num_to_string (a_this->num); ++ else ++ str = g_strdup ("unknown font-size-adjust property value"); /* Should raise an error no?*/ ++ break; ++ case FONT_SIZE_ADJUST_INHERIT: ++ str = g_strdup ("inherit"); ++ } ++ return str; ++} ++ ++/** ++ * cr_font_style_to_string: ++ * @a_code: the current instance of #CRFontStyle . ++ * ++ * Returns the serialized #CRFontStyle. The caller must free the returned ++ * string using g_free(). ++ */ ++const gchar * ++cr_font_style_to_string (enum CRFontStyle a_code) ++{ ++ gchar *str = NULL; ++ ++ switch (a_code) { ++ case FONT_STYLE_NORMAL: ++ str = (gchar *) "normal"; ++ break; ++ case FONT_STYLE_ITALIC: ++ str = (gchar *) "italic"; ++ break; ++ case FONT_STYLE_OBLIQUE: ++ str = (gchar *) "oblique"; ++ break; ++ case FONT_STYLE_INHERIT: ++ str = (gchar *) "inherit"; ++ break; ++ default: ++ str = (gchar *) "unknown font style value"; ++ break; ++ } ++ return str; ++} ++ ++/** ++ * cr_font_variant_to_string: ++ * @a_code: the current instance of #CRFontVariant. ++ * ++ * Returns the serialized form of #CRFontVariant. The caller has ++ * to free the returned string using g_free(). ++ */ ++const gchar * ++cr_font_variant_to_string (enum CRFontVariant a_code) ++{ ++ gchar *str = NULL; ++ ++ switch (a_code) { ++ case FONT_VARIANT_NORMAL: ++ str = (gchar *) "normal"; ++ break; ++ case FONT_VARIANT_SMALL_CAPS: ++ str = (gchar *) "small-caps"; ++ break; ++ case FONT_VARIANT_INHERIT: ++ str = (gchar *) "inherit"; ++ break; ++ } ++ return str; ++} ++ ++/** ++ * cr_font_weight_get_bolder: ++ * @a_weight: the #CRFontWeight to consider. ++ * ++ * Returns a font weight bolder than @a_weight ++ */ ++enum CRFontWeight ++cr_font_weight_get_bolder (enum CRFontWeight a_weight) ++{ ++ if (a_weight == FONT_WEIGHT_INHERIT) { ++ cr_utils_trace_info ("can't return a bolder weight for FONT_WEIGHT_INHERIT") ; ++ return a_weight; ++ } else if (a_weight >= FONT_WEIGHT_900) { ++ return FONT_WEIGHT_900 ; ++ } else if (a_weight < FONT_WEIGHT_NORMAL) { ++ return FONT_WEIGHT_NORMAL ; ++ } else if (a_weight == FONT_WEIGHT_BOLDER ++ || a_weight == FONT_WEIGHT_LIGHTER) { ++ cr_utils_trace_info ("FONT_WEIGHT_BOLDER or FONT_WEIGHT_LIGHTER should not appear here") ; ++ return FONT_WEIGHT_NORMAL ; ++ } else { ++ return a_weight << 1 ; ++ } ++} ++ ++/** ++ * cr_font_weight_to_string: ++ * @a_code: the font weight to consider. ++ * ++ * Returns the serialized form of #CRFontWeight. ++ */ ++const gchar * ++cr_font_weight_to_string (enum CRFontWeight a_code) ++{ ++ gchar *str = NULL; ++ ++ switch (a_code) { ++ case FONT_WEIGHT_NORMAL: ++ str = (gchar *) "normal"; ++ break; ++ case FONT_WEIGHT_BOLD: ++ str = (gchar *) "bold"; ++ break; ++ case FONT_WEIGHT_BOLDER: ++ str = (gchar *) "bolder"; ++ break; ++ case FONT_WEIGHT_LIGHTER: ++ str = (gchar *) "lighter"; ++ break; ++ case FONT_WEIGHT_100: ++ str = (gchar *) "100"; ++ break; ++ case FONT_WEIGHT_200: ++ str = (gchar *) "200"; ++ break; ++ case FONT_WEIGHT_300: ++ str = (gchar *) "300"; ++ break; ++ case FONT_WEIGHT_400: ++ str = (gchar *) "400"; ++ break; ++ case FONT_WEIGHT_500: ++ str = (gchar *) "500"; ++ break; ++ case FONT_WEIGHT_600: ++ str = (gchar *) "600"; ++ break; ++ case FONT_WEIGHT_700: ++ str = (gchar *) "700"; ++ break; ++ case FONT_WEIGHT_800: ++ str = (gchar *) "800"; ++ break; ++ case FONT_WEIGHT_900: ++ str = (gchar *) "900"; ++ break; ++ case FONT_WEIGHT_INHERIT: ++ str = (gchar *) "inherit"; ++ break; ++ default: ++ str = (gchar *) "unknown font-weight property value"; ++ break; ++ } ++ return str; ++} ++ ++/** ++ * cr_font_stretch_to_string: ++ * @a_code: the instance of #CRFontStretch to consider. ++ * ++ * Returns the serialized form of #CRFontStretch. ++ */ ++const gchar * ++cr_font_stretch_to_string (enum CRFontStretch a_code) ++{ ++ gchar *str = NULL; ++ ++ switch (a_code) { ++ case FONT_STRETCH_NORMAL: ++ str = (gchar *) "normal"; ++ break; ++ case FONT_STRETCH_WIDER: ++ str = (gchar *) "wider"; ++ break; ++ case FONT_STRETCH_NARROWER: ++ str = (gchar *) "narrower"; ++ break; ++ case FONT_STRETCH_ULTRA_CONDENSED: ++ str = (gchar *) "ultra-condensed"; ++ break; ++ case FONT_STRETCH_EXTRA_CONDENSED: ++ str = (gchar *) "extra-condensed"; ++ break; ++ case FONT_STRETCH_CONDENSED: ++ str = (gchar *) "condensed"; ++ break; ++ case FONT_STRETCH_SEMI_CONDENSED: ++ str = (gchar *) "semi-condensed"; ++ break; ++ case FONT_STRETCH_SEMI_EXPANDED: ++ str = (gchar *) "semi-expanded"; ++ break; ++ case FONT_STRETCH_EXPANDED: ++ str = (gchar *) "expanded"; ++ break; ++ case FONT_STRETCH_EXTRA_EXPANDED: ++ str = (gchar *) "extra-expaned"; ++ break; ++ case FONT_STRETCH_ULTRA_EXPANDED: ++ str = (gchar *) "ultra-expanded"; ++ break; ++ case FONT_STRETCH_INHERIT: ++ str = (gchar *) "inherit"; ++ break; ++ } ++ return str; ++} ++ ++/** ++ * cr_font_size_destroy: ++ * @a_font_size: the font size to destroy ++ * ++ */ ++void ++cr_font_size_destroy (CRFontSize * a_font_size) ++{ ++ g_return_if_fail (a_font_size); ++ ++ g_free (a_font_size) ; ++} ++ ++/******************************************************* ++ *'font-size-adjust' manipulation function definition ++ *******************************************************/ ++ ++/** ++ * cr_font_size_adjust_new: ++ * ++ * Returns a newly built instance of #CRFontSizeAdjust ++ */ ++CRFontSizeAdjust * ++cr_font_size_adjust_new (void) ++{ ++ CRFontSizeAdjust *result = NULL; ++ ++ result = g_try_malloc (sizeof (CRFontSizeAdjust)); ++ if (!result) { ++ cr_utils_trace_info ("Out of memory"); ++ return NULL; ++ } ++ memset (result, 0, sizeof (CRFontSizeAdjust)); ++ ++ return result; ++} ++ ++/** ++ * cr_font_size_adjust_destroy: ++ * @a_this: the current instance of #CRFontSizeAdjust. ++ * ++ */ ++void ++cr_font_size_adjust_destroy (CRFontSizeAdjust * a_this) ++{ ++ g_return_if_fail (a_this); ++ ++ if (a_this->type == FONT_SIZE_ADJUST_NUMBER && a_this->num) { ++ cr_num_destroy (a_this->num); ++ a_this->num = NULL; ++ } ++} +diff --git a/src/st/croco/cr-fonts.h b/src/st/croco/cr-fonts.h +new file mode 100644 +index 000000000..9eaeeeb98 +--- /dev/null ++++ b/src/st/croco/cr-fonts.h +@@ -0,0 +1,315 @@ ++/* -*- Mode: C; indent-tabs-mode:nil; c-basic-offset: 8-*- */ ++ ++/* ++ * This file is part of The Croco Library ++ * ++ * 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 ++ * See COPYRIGHTS file for copyright information. ++ */ ++ ++#ifndef __CR_FONTS_H__ ++#define __CR_FONTS_H__ ++ ++#include "cr-utils.h" ++#include "cr-num.h" ++ ++/** ++ *@file ++ *Various type declarations about font selection related ++ *properties. ++ */ ++G_BEGIN_DECLS ++ ++ ++enum CRFontFamilyType ++{ ++ FONT_FAMILY_SANS_SERIF, ++ FONT_FAMILY_SERIF, ++ FONT_FAMILY_CURSIVE, ++ FONT_FAMILY_FANTASY, ++ FONT_FAMILY_MONOSPACE, ++ FONT_FAMILY_NON_GENERIC, ++ FONT_FAMILY_INHERIT, ++ /**/ ++ NB_FONT_FAMILIE_TYPES ++} ; ++ ++typedef struct _CRFontFamily CRFontFamily ; ++ ++struct _CRFontFamily ++{ ++ enum CRFontFamilyType type ; ++ ++ /* ++ *The name of the font family, in case ++ *it is non generic. ++ *Is set only if the type is FONT_FAMILY_NON_GENERIC. ++ */ ++ guchar *name ; ++ ++ CRFontFamily *next ; ++ CRFontFamily *prev ; ++} ; ++ ++ ++/** ++ *The different types ++ *of absolute font size. ++ *This is used by the 'font-size' ++ *property defined in css2 spec ++ *in chapter 15.2.4 . ++ *These values a indexes of ++ *table of size so please, do not ++ *change their definition order unless ++ *you know what you are doing. ++ */ ++enum CRPredefinedAbsoluteFontSize ++{ ++ FONT_SIZE_XX_SMALL=0, ++ FONT_SIZE_X_SMALL, ++ FONT_SIZE_SMALL, ++ FONT_SIZE_MEDIUM, ++ FONT_SIZE_LARGE, ++ FONT_SIZE_X_LARGE, ++ FONT_SIZE_XX_LARGE, ++ FONT_SIZE_INHERIT, ++ NB_PREDEFINED_ABSOLUTE_FONT_SIZES ++} ; ++ ++/** ++ *The different types ++ *of relative font size. ++ *This is used by the 'font-size' ++ *property defined in css2 spec ++ *in chapter 15.2.4 . ++ *These values a indexes of ++ *table of size so please, do not ++ *change their definition order unless ++ *you know what you are doing. ++ */ ++enum CRRelativeFontSize ++{ ++ FONT_SIZE_LARGER, ++ FONT_SIZE_SMALLER, ++ NB_RELATIVE_FONT_SIZE ++} ; ++ ++/** ++ *The type of font-size property. ++ *Used to define the type of #CRFontSize . ++ *See css2 spec chapter 15.2.4 to understand. ++ */ ++enum CRFontSizeType { ++ /** ++ *If the type of #CRFontSize is ++ *PREDEFINED_ABSOLUTE_FONT_SIZE, ++ *the CRFontSize::value.predefined_absolute ++ *field will be defined. ++ */ ++ PREDEFINED_ABSOLUTE_FONT_SIZE, ++ ++ /** ++ *If the type of #CRFontSize is ++ *ABSOLUTE_FONT_SIZE, ++ *the CRFontSize::value.absolute ++ *field will be defined. ++ */ ++ ABSOLUTE_FONT_SIZE, ++ ++ /** ++ *If the type of #CRFontSize is ++ *RELATIVE_FONT_SIZE, ++ *the CRFontSize::value.relative ++ *field will be defined. ++ */ ++ RELATIVE_FONT_SIZE, ++ ++ /** ++ *If the type of #CRFontSize is ++ *INHERITED_FONT_SIZE, ++ *the None of the field of the CRFontSize::value enum ++ *will be defined. ++ */ ++ INHERITED_FONT_SIZE, ++ ++ NB_FONT_SIZE_TYPE ++} ; ++ ++typedef struct _CRFontSize CRFontSize ; ++struct _CRFontSize { ++ enum CRFontSizeType type ; ++ union { ++ enum CRPredefinedAbsoluteFontSize predefined ; ++ enum CRRelativeFontSize relative ; ++ CRNum absolute ; ++ } value; ++} ; ++ ++enum CRFontSizeAdjustType ++{ ++ FONT_SIZE_ADJUST_NONE = 0, ++ FONT_SIZE_ADJUST_NUMBER, ++ FONT_SIZE_ADJUST_INHERIT ++} ; ++typedef struct _CRFontSizeAdjust CRFontSizeAdjust ; ++struct _CRFontSizeAdjust ++{ ++ enum CRFontSizeAdjustType type ; ++ CRNum *num ; ++} ; ++ ++enum CRFontStyle ++{ ++ FONT_STYLE_NORMAL=0, ++ FONT_STYLE_ITALIC, ++ FONT_STYLE_OBLIQUE, ++ FONT_STYLE_INHERIT ++} ; ++ ++enum CRFontVariant ++{ ++ FONT_VARIANT_NORMAL=0, ++ FONT_VARIANT_SMALL_CAPS, ++ FONT_VARIANT_INHERIT ++} ; ++ ++enum CRFontWeight ++{ ++ FONT_WEIGHT_NORMAL = 1, ++ FONT_WEIGHT_BOLD = 1<<1, ++ FONT_WEIGHT_BOLDER = 1<<2, ++ FONT_WEIGHT_LIGHTER = 1<<3, ++ FONT_WEIGHT_100 = 1<<4, ++ FONT_WEIGHT_200 = 1<<5, ++ FONT_WEIGHT_300 = 1<<6, ++ FONT_WEIGHT_400 = 1<<7, ++ FONT_WEIGHT_500 = 1<<8, ++ FONT_WEIGHT_600 = 1<<9, ++ FONT_WEIGHT_700 = 1<<10, ++ FONT_WEIGHT_800 = 1<<11, ++ FONT_WEIGHT_900 = 1<<12, ++ FONT_WEIGHT_INHERIT = 1<<13, ++ NB_FONT_WEIGHTS ++} ; ++ ++enum CRFontStretch ++{ ++ FONT_STRETCH_NORMAL=0, ++ FONT_STRETCH_WIDER, ++ FONT_STRETCH_NARROWER, ++ FONT_STRETCH_ULTRA_CONDENSED, ++ FONT_STRETCH_EXTRA_CONDENSED, ++ FONT_STRETCH_CONDENSED, ++ FONT_STRETCH_SEMI_CONDENSED, ++ FONT_STRETCH_SEMI_EXPANDED, ++ FONT_STRETCH_EXPANDED, ++ FONT_STRETCH_EXTRA_EXPANDED, ++ FONT_STRETCH_ULTRA_EXPANDED, ++ FONT_STRETCH_INHERIT ++} ; ++ ++/************************************** ++ *'font-family' manipulation functions ++ ***************************************/ ++CRFontFamily * ++cr_font_family_new (enum CRFontFamilyType a_type, guchar *a_name) ; ++ ++CRFontFamily * ++cr_font_family_append (CRFontFamily *a_this, ++ CRFontFamily *a_family_to_append) ; ++ ++guchar * ++cr_font_family_to_string (CRFontFamily const *a_this, ++ gboolean a_walk_font_family_list) ; ++ ++CRFontFamily * ++cr_font_family_prepend (CRFontFamily *a_this, ++ CRFontFamily *a_family_to_prepend); ++ ++enum CRStatus ++cr_font_family_destroy (CRFontFamily *a_this) ; ++ ++enum CRStatus ++cr_font_family_set_name (CRFontFamily *a_this, guchar *a_name) ; ++ ++ ++/************************************ ++ *'font-size' manipulation functions ++ ***********************************/ ++ ++CRFontSize * cr_font_size_new (void) ; ++ ++enum CRStatus cr_font_size_clear (CRFontSize *a_this) ; ++ ++enum CRStatus cr_font_size_copy (CRFontSize *a_dst, ++ CRFontSize const *a_src) ; ++enum CRStatus cr_font_size_set_predefined_absolute_font_size (CRFontSize *a_this, ++ enum CRPredefinedAbsoluteFontSize a_predefined) ; ++enum CRStatus cr_font_size_set_relative_font_size (CRFontSize *a_this, ++ enum CRRelativeFontSize a_relative) ; ++ ++enum CRStatus cr_font_size_set_absolute_font_size (CRFontSize *a_this, ++ enum CRNumType a_num_type, ++ gdouble a_value) ; ++ ++enum CRStatus cr_font_size_set_to_inherit (CRFontSize *a_this) ; ++ ++gboolean cr_font_size_is_set_to_inherit (CRFontSize const *a_this) ; ++ ++gchar* cr_font_size_to_string (CRFontSize const *a_this) ; ++ ++void cr_font_size_destroy (CRFontSize *a_font_size) ; ++ ++/******************************************************* ++ *'font-size-adjust' manipulation function declarations ++ *******************************************************/ ++ ++CRFontSizeAdjust * cr_font_size_adjust_new (void) ; ++ ++gchar * cr_font_size_adjust_to_string (CRFontSizeAdjust const *a_this) ; ++ ++void cr_font_size_adjust_destroy (CRFontSizeAdjust *a_this) ; ++ ++void ++cr_font_size_get_smaller_predefined_font_size (enum CRPredefinedAbsoluteFontSize a_font_size, ++ enum CRPredefinedAbsoluteFontSize *a_smaller_size) ; ++void ++cr_font_size_get_larger_predefined_font_size (enum CRPredefinedAbsoluteFontSize a_font_size, ++ enum CRPredefinedAbsoluteFontSize *a_larger_size) ; ++ ++gboolean ++cr_font_size_is_predefined_absolute_font_size (enum CRPredefinedAbsoluteFontSize a_font_size) ; ++ ++/*********************************** ++ *various other font related functions ++ ***********************************/ ++const gchar * cr_font_style_to_string (enum CRFontStyle a_code) ; ++ ++const gchar * cr_font_weight_to_string (enum CRFontWeight a_code) ; ++ ++enum CRFontWeight ++cr_font_weight_get_bolder (enum CRFontWeight a_weight) ; ++ ++const gchar * cr_font_variant_to_string (enum CRFontVariant a_code) ; ++ ++const gchar * cr_font_stretch_to_string (enum CRFontStretch a_code) ; ++ ++G_END_DECLS ++ ++#endif +diff --git a/src/st/croco/cr-input.c b/src/st/croco/cr-input.c +new file mode 100644 +index 000000000..3b63a88ee +--- /dev/null ++++ b/src/st/croco/cr-input.c +@@ -0,0 +1,1191 @@ ++/* -*- Mode: C; indent-tabs-mode: nil; c-basic-offset: 8-*- */ ++ ++/* ++ * This file is part of The Croco Library ++ * ++ * 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 ++ * See COPYRIGHTS file for copyright information. ++ */ ++ ++#include "stdio.h" ++#include ++#include "cr-input.h" ++#include "cr-enc-handler.h" ++ ++/** ++ *@CRInput: ++ * ++ *The definition of the #CRInput class. ++ */ ++ ++/******************* ++ *Private type defs ++ *******************/ ++ ++/** ++ *The private attributes of ++ *the #CRInputPriv class. ++ */ ++struct _CRInputPriv { ++ /* ++ *The input buffer ++ */ ++ guchar *in_buf; ++ gulong in_buf_size; ++ ++ gulong nb_bytes; ++ ++ /* ++ *The index of the next byte ++ *to be read. ++ */ ++ gulong next_byte_index; ++ ++ /* ++ *The current line number ++ */ ++ gulong line; ++ ++ /* ++ *The current col number ++ */ ++ gulong col; ++ ++ gboolean end_of_line; ++ gboolean end_of_input; ++ ++ /* ++ *the reference count of this ++ *instance. ++ */ ++ guint ref_count; ++ gboolean free_in_buf; ++}; ++ ++#define PRIVATE(object) (object)->priv ++ ++/*************************** ++ *private constants ++ **************************/ ++#define CR_INPUT_MEM_CHUNK_SIZE 1024 * 4 ++ ++static CRInput *cr_input_new_real (void); ++ ++static CRInput * ++cr_input_new_real (void) ++{ ++ CRInput *result = NULL; ++ ++ result = g_try_malloc (sizeof (CRInput)); ++ if (!result) { ++ cr_utils_trace_info ("Out of memory"); ++ return NULL; ++ } ++ memset (result, 0, sizeof (CRInput)); ++ ++ PRIVATE (result) = g_try_malloc (sizeof (CRInputPriv)); ++ if (!PRIVATE (result)) { ++ cr_utils_trace_info ("Out of memory"); ++ g_free (result); ++ return NULL; ++ } ++ memset (PRIVATE (result), 0, sizeof (CRInputPriv)); ++ PRIVATE (result)->free_in_buf = TRUE; ++ return result; ++} ++ ++/**************** ++ *Public methods ++ ***************/ ++ ++/** ++ * cr_input_new_from_buf: ++ *@a_buf: the memory buffer to create the input stream from. ++ *The #CRInput keeps this pointer so user should not free it !. ++ *@a_len: the size of the input buffer. ++ *@a_enc: the buffer's encoding. ++ *@a_free_buf: if set to TRUE, this a_buf will be freed ++ *at the destruction of this instance. If set to false, it is up ++ *to the caller to free it. ++ * ++ *Creates a new input stream from a memory buffer. ++ *Returns the newly built instance of #CRInput. ++ */ ++CRInput * ++cr_input_new_from_buf (guchar * a_buf, ++ gulong a_len, ++ enum CREncoding a_enc, ++ gboolean a_free_buf) ++{ ++ CRInput *result = NULL; ++ enum CRStatus status = CR_OK; ++ CREncHandler *enc_handler = NULL; ++ gulong len = a_len; ++ ++ g_return_val_if_fail (a_buf, NULL); ++ ++ result = cr_input_new_real (); ++ g_return_val_if_fail (result, NULL); ++ ++ /*transform the encoding in utf8 */ ++ if (a_enc != CR_UTF_8) { ++ enc_handler = cr_enc_handler_get_instance (a_enc); ++ if (!enc_handler) { ++ goto error; ++ } ++ ++ status = cr_enc_handler_convert_input ++ (enc_handler, a_buf, &len, ++ &PRIVATE (result)->in_buf, ++ &PRIVATE (result)->in_buf_size); ++ if (status != CR_OK) ++ goto error; ++ PRIVATE (result)->free_in_buf = TRUE; ++ if (a_free_buf == TRUE && a_buf) { ++ g_free (a_buf) ; ++ a_buf = NULL ; ++ } ++ PRIVATE (result)->nb_bytes = PRIVATE (result)->in_buf_size; ++ } else { ++ PRIVATE (result)->in_buf = (guchar *) a_buf; ++ PRIVATE (result)->in_buf_size = a_len; ++ PRIVATE (result)->nb_bytes = a_len; ++ PRIVATE (result)->free_in_buf = a_free_buf; ++ } ++ PRIVATE (result)->line = 1; ++ PRIVATE (result)->col = 0; ++ return result; ++ ++ error: ++ if (result) { ++ cr_input_destroy (result); ++ result = NULL; ++ } ++ ++ return NULL; ++} ++ ++/** ++ * cr_input_new_from_uri: ++ *@a_file_uri: the file to create *the input stream from. ++ *@a_enc: the encoding of the file *to create the input from. ++ * ++ *Creates a new input stream from ++ *a file. ++ * ++ *Returns the newly created input stream if ++ *this method could read the file and create it, ++ *NULL otherwise. ++ */ ++ ++CRInput * ++cr_input_new_from_uri (const gchar * a_file_uri, enum CREncoding a_enc) ++{ ++ CRInput *result = NULL; ++ enum CRStatus status = CR_OK; ++ FILE *file_ptr = NULL; ++ guchar tmp_buf[CR_INPUT_MEM_CHUNK_SIZE] = { 0 }; ++ gulong nb_read = 0, ++ len = 0, ++ buf_size = 0; ++ gboolean loop = TRUE; ++ guchar *buf = NULL; ++ ++ g_return_val_if_fail (a_file_uri, NULL); ++ ++ file_ptr = fopen (a_file_uri, "r"); ++ ++ if (file_ptr == NULL) { ++ ++#ifdef CR_DEBUG ++ cr_utils_trace_debug ("could not open file"); ++#endif ++ g_warning ("Could not open file %s\n", a_file_uri); ++ ++ return NULL; ++ } ++ ++ /*load the file */ ++ while (loop) { ++ nb_read = fread (tmp_buf, 1 /*read bytes */ , ++ CR_INPUT_MEM_CHUNK_SIZE /*nb of bytes */ , ++ file_ptr); ++ ++ if (nb_read != CR_INPUT_MEM_CHUNK_SIZE) { ++ /*we read less chars than we wanted */ ++ if (feof (file_ptr)) { ++ /*we reached eof */ ++ loop = FALSE; ++ } else { ++ /*a pb occurred !! */ ++ cr_utils_trace_debug ("an io error occurred"); ++ status = CR_ERROR; ++ goto cleanup; ++ } ++ } ++ ++ if (status == CR_OK) { ++ /*read went well */ ++ buf = g_realloc (buf, len + CR_INPUT_MEM_CHUNK_SIZE); ++ memcpy (buf + len, tmp_buf, nb_read); ++ len += nb_read; ++ buf_size += CR_INPUT_MEM_CHUNK_SIZE; ++ } ++ } ++ ++ if (status == CR_OK) { ++ result = cr_input_new_from_buf (buf, len, a_enc, TRUE); ++ if (!result) { ++ goto cleanup; ++ } ++ /* ++ *we should free buf here because it's own by CRInput. ++ *(see the last parameter of cr_input_new_from_buf(). ++ */ ++ buf = NULL; ++ } ++ ++ cleanup: ++ if (file_ptr) { ++ fclose (file_ptr); ++ file_ptr = NULL; ++ } ++ ++ if (buf) { ++ g_free (buf); ++ buf = NULL; ++ } ++ ++ return result; ++} ++ ++/** ++ * cr_input_destroy: ++ *@a_this: the current instance of #CRInput. ++ * ++ *The destructor of the #CRInput class. ++ */ ++void ++cr_input_destroy (CRInput * a_this) ++{ ++ if (a_this == NULL) ++ return; ++ ++ if (PRIVATE (a_this)) { ++ if (PRIVATE (a_this)->in_buf && PRIVATE (a_this)->free_in_buf) { ++ g_free (PRIVATE (a_this)->in_buf); ++ PRIVATE (a_this)->in_buf = NULL; ++ } ++ ++ g_free (PRIVATE (a_this)); ++ PRIVATE (a_this) = NULL; ++ } ++ ++ g_free (a_this); ++} ++ ++/** ++ * cr_input_ref: ++ *@a_this: the current instance of #CRInput. ++ * ++ *Increments the reference count of the current ++ *instance of #CRInput. ++ */ ++void ++cr_input_ref (CRInput * a_this) ++{ ++ g_return_if_fail (a_this && PRIVATE (a_this)); ++ ++ PRIVATE (a_this)->ref_count++; ++} ++ ++/** ++ * cr_input_unref: ++ *@a_this: the current instance of #CRInput. ++ * ++ *Decrements the reference count of this instance ++ *of #CRInput. If the reference count goes down to ++ *zero, this instance is destroyed. ++ * ++ * Returns TRUE if the instance of #CRInput got destroyed, false otherwise. ++ */ ++gboolean ++cr_input_unref (CRInput * a_this) ++{ ++ g_return_val_if_fail (a_this && PRIVATE (a_this), FALSE); ++ ++ if (PRIVATE (a_this)->ref_count) { ++ PRIVATE (a_this)->ref_count--; ++ } ++ ++ if (PRIVATE (a_this)->ref_count == 0) { ++ cr_input_destroy (a_this); ++ return TRUE; ++ } ++ return FALSE; ++} ++ ++/** ++ * cr_input_end_of_input: ++ *@a_this: the current instance of #CRInput. ++ *@a_end_of_input: out parameter. Is set to TRUE if ++ *the current instance has reached the end of its input buffer, ++ *FALSE otherwise. ++ * ++ *Tests wether the current instance of ++ *#CRInput has reached its input buffer. ++ * ++ * Returns CR_OK upon successful completion, an error code otherwise. ++ * Note that all the out parameters of this method are valid if ++ * and only if this method returns CR_OK. ++ */ ++enum CRStatus ++cr_input_end_of_input (CRInput const * a_this, gboolean * a_end_of_input) ++{ ++ g_return_val_if_fail (a_this && PRIVATE (a_this) ++ && a_end_of_input, CR_BAD_PARAM_ERROR); ++ ++ *a_end_of_input = (PRIVATE (a_this)->next_byte_index ++ >= PRIVATE (a_this)->in_buf_size) ? TRUE : FALSE; ++ ++ return CR_OK; ++} ++ ++/** ++ * cr_input_get_nb_bytes_left: ++ *@a_this: the current instance of #CRInput. ++ * ++ *Returns the number of bytes left in the input stream ++ *before the end, -1 in case of error. ++ */ ++glong ++cr_input_get_nb_bytes_left (CRInput const * a_this) ++{ ++ g_return_val_if_fail (a_this && PRIVATE (a_this), -1); ++ g_return_val_if_fail (PRIVATE (a_this)->nb_bytes ++ <= PRIVATE (a_this)->in_buf_size, -1); ++ g_return_val_if_fail (PRIVATE (a_this)->next_byte_index ++ <= PRIVATE (a_this)->nb_bytes, -1); ++ ++ if (PRIVATE (a_this)->end_of_input) ++ return 0; ++ ++ return PRIVATE (a_this)->nb_bytes - PRIVATE (a_this)->next_byte_index; ++} ++ ++/** ++ * cr_input_read_byte: ++ *@a_this: the current instance of #CRInput. ++ *@a_byte: out parameter the returned byte. ++ * ++ *Gets the next byte of the input. ++ *Updates the state of the input so that ++ *the next invocation of this method returns ++ *the next coming byte. ++ * ++ *Returns CR_OK upon successful completion, an error code ++ *otherwise. All the out parameters of this method are valid if ++ *and only if this method returns CR_OK. ++ */ ++enum CRStatus ++cr_input_read_byte (CRInput * a_this, guchar * a_byte) ++{ ++ gulong nb_bytes_left = 0; ++ ++ g_return_val_if_fail (a_this && PRIVATE (a_this) ++ && a_byte, CR_BAD_PARAM_ERROR); ++ ++ g_return_val_if_fail (PRIVATE (a_this)->next_byte_index <= ++ PRIVATE (a_this)->nb_bytes, CR_BAD_PARAM_ERROR); ++ ++ if (PRIVATE (a_this)->end_of_input == TRUE) ++ return CR_END_OF_INPUT_ERROR; ++ ++ nb_bytes_left = cr_input_get_nb_bytes_left (a_this); ++ ++ if (nb_bytes_left < 1) { ++ return CR_END_OF_INPUT_ERROR; ++ } ++ ++ *a_byte = PRIVATE (a_this)->in_buf[PRIVATE (a_this)->next_byte_index]; ++ ++ if (PRIVATE (a_this)->nb_bytes - ++ PRIVATE (a_this)->next_byte_index < 2) { ++ PRIVATE (a_this)->end_of_input = TRUE; ++ } else { ++ PRIVATE (a_this)->next_byte_index++; ++ } ++ ++ return CR_OK; ++} ++ ++/** ++ * cr_input_read_char: ++ *@a_this: the current instance of CRInput. ++ *@a_char: out parameter. The read character. ++ * ++ *Reads an unicode character from the current instance of ++ *#CRInput. ++ * ++ *Returns CR_OK upon successful completion, an error code ++ *otherwise. ++ */ ++enum CRStatus ++cr_input_read_char (CRInput * a_this, guint32 * a_char) ++{ ++ enum CRStatus status = CR_OK; ++ gulong consumed = 0, ++ nb_bytes_left = 0; ++ ++ g_return_val_if_fail (a_this && PRIVATE (a_this) && a_char, ++ CR_BAD_PARAM_ERROR); ++ ++ if (PRIVATE (a_this)->end_of_input == TRUE) ++ return CR_END_OF_INPUT_ERROR; ++ ++ nb_bytes_left = cr_input_get_nb_bytes_left (a_this); ++ ++ if (nb_bytes_left < 1) { ++ return CR_END_OF_INPUT_ERROR; ++ } ++ ++ status = cr_utils_read_char_from_utf8_buf ++ (PRIVATE (a_this)->in_buf ++ + ++ PRIVATE (a_this)->next_byte_index, ++ nb_bytes_left, a_char, &consumed); ++ ++ if (status == CR_OK) { ++ /*update next byte index */ ++ PRIVATE (a_this)->next_byte_index += consumed; ++ ++ /*update line and column number */ ++ if (PRIVATE (a_this)->end_of_line == TRUE) { ++ PRIVATE (a_this)->col = 1; ++ PRIVATE (a_this)->line++; ++ PRIVATE (a_this)->end_of_line = FALSE; ++ } else if (*a_char != '\n') { ++ PRIVATE (a_this)->col++; ++ } ++ ++ if (*a_char == '\n') { ++ PRIVATE (a_this)->end_of_line = TRUE; ++ } ++ } ++ ++ return status; ++} ++ ++/** ++ * cr_input_set_line_num: ++ *@a_this: the "this pointer" of the current instance of #CRInput. ++ *@a_line_num: the new line number. ++ * ++ *Setter of the current line number. ++ * ++ *Return CR_OK upon successful completion, an error code otherwise. ++ */ ++enum CRStatus ++cr_input_set_line_num (CRInput * a_this, glong a_line_num) ++{ ++ g_return_val_if_fail (a_this && PRIVATE (a_this), CR_BAD_PARAM_ERROR); ++ ++ PRIVATE (a_this)->line = a_line_num; ++ ++ return CR_OK; ++} ++ ++/** ++ * cr_input_get_line_num: ++ *@a_this: the "this pointer" of the current instance of #CRInput. ++ *@a_line_num: the returned line number. ++ * ++ *Getter of the current line number. ++ * ++ *Returns CR_OK upon successful completion, an error code otherwise. ++ */ ++enum CRStatus ++cr_input_get_line_num (CRInput const * a_this, glong * a_line_num) ++{ ++ g_return_val_if_fail (a_this && PRIVATE (a_this) ++ && a_line_num, CR_BAD_PARAM_ERROR); ++ ++ *a_line_num = PRIVATE (a_this)->line; ++ ++ return CR_OK; ++} ++ ++/** ++ * cr_input_set_column_num: ++ *@a_this: the "this pointer" of the current instance of #CRInput. ++ *@a_col: the new column number. ++ * ++ *Setter of the current column number. ++ * ++ *Returns CR_OK upon successful completion, an error code otherwise. ++ */ ++enum CRStatus ++cr_input_set_column_num (CRInput * a_this, glong a_col) ++{ ++ g_return_val_if_fail (a_this && PRIVATE (a_this), CR_BAD_PARAM_ERROR); ++ ++ PRIVATE (a_this)->col = a_col; ++ ++ return CR_OK; ++} ++ ++/** ++ * cr_input_get_column_num: ++ *@a_this: the "this pointer" of the current instance of #CRInput. ++ *@a_col: out parameter ++ * ++ *Getter of the current column number. ++ * ++ *Returns CR_OK upon successful completion, an error code otherwise. ++ */ ++enum CRStatus ++cr_input_get_column_num (CRInput const * a_this, glong * a_col) ++{ ++ g_return_val_if_fail (a_this && PRIVATE (a_this) && a_col, ++ CR_BAD_PARAM_ERROR); ++ ++ *a_col = PRIVATE (a_this)->col; ++ ++ return CR_OK; ++} ++ ++/** ++ * cr_input_increment_line_num: ++ *@a_this: the "this pointer" of the current instance of #CRInput. ++ *@a_increment: the increment to add to the line number. ++ * ++ *Increments the current line number. ++ * ++ *Returns CR_OK upon successful completion, an error code otherwise. ++ */ ++enum CRStatus ++cr_input_increment_line_num (CRInput * a_this, glong a_increment) ++{ ++ g_return_val_if_fail (a_this && PRIVATE (a_this), CR_BAD_PARAM_ERROR); ++ ++ PRIVATE (a_this)->line += a_increment; ++ ++ return CR_OK; ++} ++ ++/** ++ * cr_input_increment_col_num: ++ *@a_this: the "this pointer" of the current instance of #CRInput. ++ *@a_increment: the increment to add to the column number. ++ * ++ *Increments the current column number. ++ * ++ *Returns CR_OK upon successful completion, an error code otherwise. ++ */ ++enum CRStatus ++cr_input_increment_col_num (CRInput * a_this, glong a_increment) ++{ ++ g_return_val_if_fail (a_this && PRIVATE (a_this), CR_BAD_PARAM_ERROR); ++ ++ PRIVATE (a_this)->col += a_increment; ++ ++ return CR_OK; ++} ++ ++/** ++ * cr_input_consume_char: ++ *@a_this: the this pointer. ++ *@a_char: the character to consume. If set to zero, ++ *consumes any character. ++ * ++ *Consumes the next character of the input stream if ++ *and only if that character equals a_char. ++ * ++ *Returns CR_OK upon successful completion, CR_PARSING_ERROR if ++ *next char is different from a_char, an other error code otherwise ++ */ ++enum CRStatus ++cr_input_consume_char (CRInput * a_this, guint32 a_char) ++{ ++ guint32 c; ++ enum CRStatus status; ++ ++ g_return_val_if_fail (a_this && PRIVATE (a_this), CR_BAD_PARAM_ERROR); ++ ++ if ((status = cr_input_peek_char (a_this, &c)) != CR_OK) { ++ return status; ++ } ++ ++ if (c == a_char || a_char == 0) { ++ status = cr_input_read_char (a_this, &c); ++ } else { ++ return CR_PARSING_ERROR; ++ } ++ ++ return status; ++} ++ ++/** ++ * cr_input_consume_chars: ++ *@a_this: the this pointer of the current instance of #CRInput. ++ *@a_char: the character to consume. ++ *@a_nb_char: in/out parameter. The number of characters to consume. ++ *If set to a negative value, the function will consume all the occurences ++ *of a_char found. ++ *After return, if the return value equals CR_OK, this variable contains ++ *the number of characters actually consumed. ++ * ++ *Consumes up to a_nb_char occurences of the next contiguous characters ++ *which equal a_char. Note that the next character of the input stream ++ **MUST* equal a_char to trigger the consumption, or else, the error ++ *code CR_PARSING_ERROR is returned. ++ *If the number of contiguous characters that equals a_char is less than ++ *a_nb_char, then this function consumes all the characters it can consume. ++ * ++ *Returns CR_OK if at least one character has been consumed, an error code ++ *otherwise. ++ */ ++enum CRStatus ++cr_input_consume_chars (CRInput * a_this, guint32 a_char, gulong * a_nb_char) ++{ ++ enum CRStatus status = CR_OK; ++ gulong nb_consumed = 0; ++ ++ g_return_val_if_fail (a_this && PRIVATE (a_this) && a_nb_char, ++ CR_BAD_PARAM_ERROR); ++ ++ g_return_val_if_fail (a_char != 0 || a_nb_char != NULL, ++ CR_BAD_PARAM_ERROR); ++ ++ for (nb_consumed = 0; ((status == CR_OK) ++ && (*a_nb_char > 0 ++ && nb_consumed < *a_nb_char)); ++ nb_consumed++) { ++ status = cr_input_consume_char (a_this, a_char); ++ } ++ ++ *a_nb_char = nb_consumed; ++ ++ if ((nb_consumed > 0) ++ && ((status == CR_PARSING_ERROR) ++ || (status == CR_END_OF_INPUT_ERROR))) { ++ status = CR_OK; ++ } ++ ++ return status; ++} ++ ++/** ++ * cr_input_consume_white_spaces: ++ *@a_this: the "this pointer" of the current instance of #CRInput. ++ *@a_nb_chars: in/out parameter. The number of white spaces to ++ *consume. After return, holds the number of white spaces actually consumed. ++ * ++ *Same as cr_input_consume_chars() but this one consumes white ++ *spaces. ++ * ++ *Returns CR_OK upon successful completion, an error code otherwise. ++ */ ++enum CRStatus ++cr_input_consume_white_spaces (CRInput * a_this, gulong * a_nb_chars) ++{ ++ enum CRStatus status = CR_OK; ++ guint32 cur_char = 0, ++ nb_consumed = 0; ++ ++ g_return_val_if_fail (a_this && PRIVATE (a_this) && a_nb_chars, ++ CR_BAD_PARAM_ERROR); ++ ++ for (nb_consumed = 0; ++ ((*a_nb_chars > 0) && (nb_consumed < *a_nb_chars)); ++ nb_consumed++) { ++ status = cr_input_peek_char (a_this, &cur_char); ++ if (status != CR_OK) ++ break; ++ ++ /*if the next char is a white space, consume it ! */ ++ if (cr_utils_is_white_space (cur_char) == TRUE) { ++ status = cr_input_read_char (a_this, &cur_char); ++ if (status != CR_OK) ++ break; ++ continue; ++ } ++ ++ break; ++ ++ } ++ ++ *a_nb_chars = (gulong) nb_consumed; ++ ++ if (nb_consumed && status == CR_END_OF_INPUT_ERROR) { ++ status = CR_OK; ++ } ++ ++ return status; ++} ++ ++/** ++ * cr_input_peek_char: ++ *@a_this: the current instance of #CRInput. ++ *@a_char: out parameter. The returned character. ++ * ++ *Same as cr_input_read_char() but does not update the ++ *internal state of the input stream. The next call ++ *to cr_input_peek_char() or cr_input_read_char() will thus ++ *return the same character as the current one. ++ * ++ *Returns CR_OK upon successful completion, an error code ++ *otherwise. ++ */ ++enum CRStatus ++cr_input_peek_char (CRInput const * a_this, guint32 * a_char) ++{ ++ enum CRStatus status = CR_OK; ++ gulong consumed = 0, ++ nb_bytes_left = 0; ++ ++ g_return_val_if_fail (a_this && PRIVATE (a_this) ++ && a_char, CR_BAD_PARAM_ERROR); ++ ++ if (PRIVATE (a_this)->next_byte_index >= ++ PRIVATE (a_this)->in_buf_size) { ++ return CR_END_OF_INPUT_ERROR; ++ } ++ ++ nb_bytes_left = cr_input_get_nb_bytes_left (a_this); ++ ++ if (nb_bytes_left < 1) { ++ return CR_END_OF_INPUT_ERROR; ++ } ++ ++ status = cr_utils_read_char_from_utf8_buf ++ (PRIVATE (a_this)->in_buf + ++ PRIVATE (a_this)->next_byte_index, ++ nb_bytes_left, a_char, &consumed); ++ ++ return status; ++} ++ ++/** ++ * cr_input_peek_byte: ++ *@a_this: the current instance of #CRInput. ++ *@a_origin: the origin to consider in the calculation ++ *of the position of the byte to peek. ++ *@a_offset: the offset of the byte to peek, starting from ++ *the origin specified by a_origin. ++ *@a_byte: out parameter the peeked byte. ++ * ++ *Gets a byte from the input stream, ++ *starting from the current position in the input stream. ++ *Unlike cr_input_peek_next_byte() this method ++ *does not update the state of the current input stream. ++ *Subsequent calls to cr_input_peek_byte with the same arguments ++ *will return the same byte. ++ * ++ *Returns CR_OK upon successful completion or, ++ *CR_BAD_PARAM_ERROR if at least one of the parameters is invalid; ++ *CR_OUT_OF_BOUNDS_ERROR if the indexed byte is out of bounds. ++ */ ++enum CRStatus ++cr_input_peek_byte (CRInput const * a_this, enum CRSeekPos a_origin, ++ gulong a_offset, guchar * a_byte) ++{ ++ gulong abs_offset = 0; ++ ++ g_return_val_if_fail (a_this && PRIVATE (a_this) ++ && a_byte, CR_BAD_PARAM_ERROR); ++ ++ switch (a_origin) { ++ ++ case CR_SEEK_CUR: ++ abs_offset = PRIVATE (a_this)->next_byte_index - 1 + a_offset; ++ break; ++ ++ case CR_SEEK_BEGIN: ++ abs_offset = a_offset; ++ break; ++ ++ case CR_SEEK_END: ++ abs_offset = PRIVATE (a_this)->in_buf_size - 1 - a_offset; ++ break; ++ ++ default: ++ return CR_BAD_PARAM_ERROR; ++ } ++ ++ if (abs_offset < PRIVATE (a_this)->in_buf_size) { ++ ++ *a_byte = PRIVATE (a_this)->in_buf[abs_offset]; ++ ++ return CR_OK; ++ ++ } else { ++ return CR_END_OF_INPUT_ERROR; ++ } ++} ++ ++/** ++ * cr_input_peek_byte2: ++ *@a_this: the current byte input stream. ++ *@a_offset: the offset of the byte to peek, starting ++ *from the current input position pointer. ++ *@a_eof: out parameter. Is set to true is we reach end of ++ *stream. If set to NULL by the caller, this parameter is not taken ++ *in account. ++ * ++ *Same as cr_input_peek_byte() but with a simplified ++ *interface. ++ * ++ *Returns the read byte or 0 if something bad happened. ++ */ ++guchar ++cr_input_peek_byte2 (CRInput const * a_this, gulong a_offset, gboolean * a_eof) ++{ ++ guchar result = 0; ++ enum CRStatus status = CR_ERROR; ++ ++ g_return_val_if_fail (a_this && PRIVATE (a_this), 0); ++ ++ if (a_eof) ++ *a_eof = FALSE; ++ ++ status = cr_input_peek_byte (a_this, CR_SEEK_CUR, a_offset, &result); ++ ++ if ((status == CR_END_OF_INPUT_ERROR) ++ && a_eof) ++ *a_eof = TRUE; ++ ++ return result; ++} ++ ++/** ++ * cr_input_get_byte_addr: ++ *@a_this: the current instance of #CRInput. ++ *@a_offset: the offset of the byte in the input stream starting ++ *from the beginning of the stream. ++ * ++ *Gets the memory address of the byte located at a given offset ++ *in the input stream. ++ * ++ *Returns the address, otherwise NULL if an error occurred. ++ */ ++guchar * ++cr_input_get_byte_addr (CRInput * a_this, gulong a_offset) ++{ ++ g_return_val_if_fail (a_this && PRIVATE (a_this), NULL); ++ ++ if (a_offset >= PRIVATE (a_this)->nb_bytes) { ++ return NULL; ++ } ++ ++ return &PRIVATE (a_this)->in_buf[a_offset]; ++} ++ ++/** ++ * cr_input_get_cur_byte_addr: ++ *@a_this: the current input stream ++ *@a_offset: out parameter. The returned address. ++ * ++ *Gets the address of the current character pointer. ++ * ++ *Returns CR_OK upon successful completion, an error code otherwise. ++ */ ++enum CRStatus ++cr_input_get_cur_byte_addr (CRInput * a_this, guchar ** a_offset) ++{ ++ g_return_val_if_fail (a_this && PRIVATE (a_this) && a_offset, ++ CR_BAD_PARAM_ERROR); ++ ++ if (!PRIVATE (a_this)->next_byte_index) { ++ return CR_START_OF_INPUT_ERROR; ++ } ++ ++ *a_offset = cr_input_get_byte_addr ++ (a_this, PRIVATE (a_this)->next_byte_index - 1); ++ ++ return CR_OK; ++} ++ ++/** ++ * cr_input_seek_index: ++ *@a_this: the current instance of #CRInput. ++ *@a_origin: the origin to consider during the calculation ++ *of the absolute position of the new "current byte index". ++ *@a_pos: the relative offset of the new "current byte index." ++ *This offset is relative to the origin a_origin. ++ * ++ *Sets the "current byte index" of the current instance ++ *of #CRInput. Next call to cr_input_get_byte() will return ++ *the byte next after the new "current byte index". ++ * ++ *Returns CR_OK upon successful completion otherwise returns ++ *CR_BAD_PARAM_ERROR if at least one of the parameters is not valid ++ *or CR_OUT_BOUNDS_ERROR in case of error. ++ */ ++enum CRStatus ++cr_input_seek_index (CRInput * a_this, enum CRSeekPos a_origin, gint a_pos) ++{ ++ ++ glong abs_offset = 0; ++ ++ g_return_val_if_fail (a_this && PRIVATE (a_this), CR_BAD_PARAM_ERROR); ++ ++ switch (a_origin) { ++ ++ case CR_SEEK_CUR: ++ abs_offset = PRIVATE (a_this)->next_byte_index - 1 + a_pos; ++ break; ++ ++ case CR_SEEK_BEGIN: ++ abs_offset = a_pos; ++ break; ++ ++ case CR_SEEK_END: ++ abs_offset = PRIVATE (a_this)->in_buf_size - 1 - a_pos; ++ break; ++ ++ default: ++ return CR_BAD_PARAM_ERROR; ++ } ++ ++ if ((abs_offset > 0) ++ && (gulong) abs_offset < PRIVATE (a_this)->nb_bytes) { ++ ++ /*update the input stream's internal state */ ++ PRIVATE (a_this)->next_byte_index = abs_offset + 1; ++ ++ return CR_OK; ++ } ++ ++ return CR_OUT_OF_BOUNDS_ERROR; ++} ++ ++/** ++ * cr_input_get_cur_pos: ++ *@a_this: the current instance of #CRInput. ++ *@a_pos: out parameter. The returned position. ++ * ++ *Gets the position of the "current byte index" which ++ *is basically the position of the last returned byte in the ++ *input stream. ++ * ++ *Returns CR_OK upon successful completion. Otherwise, ++ *CR_BAD_PARAMETER_ERROR if at least one of the arguments is invalid. ++ *CR_START_OF_INPUT if no call to either cr_input_read_byte() ++ *or cr_input_seek_index() have been issued before calling ++ *cr_input_get_cur_pos() ++ *Note that the out parameters of this function are valid if and only if this ++ *function returns CR_OK. ++ */ ++enum CRStatus ++cr_input_get_cur_pos (CRInput const * a_this, CRInputPos * a_pos) ++{ ++ g_return_val_if_fail (a_this && PRIVATE (a_this) && a_pos, ++ CR_BAD_PARAM_ERROR); ++ ++ a_pos->next_byte_index = PRIVATE (a_this)->next_byte_index; ++ a_pos->line = PRIVATE (a_this)->line; ++ a_pos->col = PRIVATE (a_this)->col; ++ a_pos->end_of_line = PRIVATE (a_this)->end_of_line; ++ a_pos->end_of_file = PRIVATE (a_this)->end_of_input; ++ ++ return CR_OK; ++} ++ ++/** ++ * cr_input_get_parsing_location: ++ *@a_this: the current instance of #CRInput ++ *@a_loc: the set parsing location. ++ * ++ *Gets the current parsing location. ++ *The Parsing location is a public datastructure that ++ *represents the current line/column/byte offset/ in the input ++ *stream. ++ * ++ *Returns CR_OK upon successful completion, an error ++ *code otherwise. ++ */ ++enum CRStatus ++cr_input_get_parsing_location (CRInput const *a_this, ++ CRParsingLocation *a_loc) ++{ ++ g_return_val_if_fail (a_this ++ && PRIVATE (a_this) ++ && a_loc, ++ CR_BAD_PARAM_ERROR) ; ++ ++ a_loc->line = PRIVATE (a_this)->line ; ++ a_loc->column = PRIVATE (a_this)->col ; ++ if (PRIVATE (a_this)->next_byte_index) { ++ a_loc->byte_offset = PRIVATE (a_this)->next_byte_index - 1 ; ++ } else { ++ a_loc->byte_offset = PRIVATE (a_this)->next_byte_index ; ++ } ++ return CR_OK ; ++} ++ ++/** ++ * cr_input_get_cur_index: ++ *@a_this: the "this pointer" of the current instance of ++ *#CRInput ++ *@a_index: out parameter. The returned index. ++ * ++ *Getter of the next byte index. ++ *It actually returns the index of the ++ *next byte to be read. ++ * ++ *Returns CR_OK upon successful completion, an error code ++ *otherwise. ++ */ ++enum CRStatus ++cr_input_get_cur_index (CRInput const * a_this, glong * a_index) ++{ ++ g_return_val_if_fail (a_this && PRIVATE (a_this) ++ && a_index, CR_BAD_PARAM_ERROR); ++ ++ *a_index = PRIVATE (a_this)->next_byte_index; ++ ++ return CR_OK; ++} ++ ++/** ++ * cr_input_set_cur_index: ++ *@a_this: the "this pointer" of the current instance ++ *of #CRInput . ++ *@a_index: the new index to set. ++ * ++ *Setter of the next byte index. ++ *It sets the index of the next byte to be read. ++ * ++ *Returns CR_OK upon successful completion, an error code otherwise. ++ */ ++enum CRStatus ++cr_input_set_cur_index (CRInput * a_this, glong a_index) ++{ ++ g_return_val_if_fail (a_this && PRIVATE (a_this), CR_BAD_PARAM_ERROR); ++ ++ PRIVATE (a_this)->next_byte_index = a_index; ++ ++ return CR_OK; ++} ++ ++/** ++ * cr_input_set_end_of_file: ++ *@a_this: the current instance of #CRInput. ++ *@a_eof: the new end of file flag. ++ * ++ *Sets the end of file flag. ++ * ++ *Returns CR_OK upon successful completion, an error code otherwise. ++ */ ++enum CRStatus ++cr_input_set_end_of_file (CRInput * a_this, gboolean a_eof) ++{ ++ g_return_val_if_fail (a_this && PRIVATE (a_this), CR_BAD_PARAM_ERROR); ++ ++ PRIVATE (a_this)->end_of_input = a_eof; ++ ++ return CR_OK; ++} ++ ++/** ++ * cr_input_get_end_of_file: ++ *@a_this: the current instance of #CRInput. ++ *@a_eof: out parameter the place to put the end of ++ *file flag. ++ * ++ *Gets the end of file flag. ++ * ++ *Returns CR_OK upon successful completion, an error code otherwise. ++ */ ++enum CRStatus ++cr_input_get_end_of_file (CRInput const * a_this, gboolean * a_eof) ++{ ++ g_return_val_if_fail (a_this && PRIVATE (a_this) ++ && a_eof, CR_BAD_PARAM_ERROR); ++ ++ *a_eof = PRIVATE (a_this)->end_of_input; ++ ++ return CR_OK; ++} ++ ++/** ++ * cr_input_set_end_of_line: ++ *@a_this: the current instance of #CRInput. ++ *@a_eol: the new end of line flag. ++ * ++ *Sets the end of line flag. ++ * ++ *Returns CR_OK upon successful completion, an error code ++ *otherwise. ++ */ ++enum CRStatus ++cr_input_set_end_of_line (CRInput * a_this, gboolean a_eol) ++{ ++ g_return_val_if_fail (a_this && PRIVATE (a_this), CR_BAD_PARAM_ERROR); ++ ++ PRIVATE (a_this)->end_of_line = a_eol; ++ ++ return CR_OK; ++} ++ ++/** ++ * cr_input_get_end_of_line: ++ *@a_this: the current instance of #CRInput ++ *@a_eol: out parameter. The place to put ++ *the returned flag ++ * ++ *Gets the end of line flag of the current input. ++ * ++ *Returns CR_OK upon successful completion, an error code ++ *otherwise. ++ */ ++enum CRStatus ++cr_input_get_end_of_line (CRInput const * a_this, gboolean * a_eol) ++{ ++ g_return_val_if_fail (a_this && PRIVATE (a_this) ++ && a_eol, CR_BAD_PARAM_ERROR); ++ ++ *a_eol = PRIVATE (a_this)->end_of_line; ++ ++ return CR_OK; ++} ++ ++/** ++ * cr_input_set_cur_pos: ++ *@a_this: the "this pointer" of the current instance of ++ *#CRInput. ++ *@a_pos: the new position. ++ * ++ *Sets the current position in the input stream. ++ * ++ * Returns CR_OK upon successful completion, an error code otherwise. ++ */ ++enum CRStatus ++cr_input_set_cur_pos (CRInput * a_this, CRInputPos const * a_pos) ++{ ++ g_return_val_if_fail (a_this && PRIVATE (a_this) && a_pos, ++ CR_BAD_PARAM_ERROR); ++ ++ cr_input_set_column_num (a_this, a_pos->col); ++ cr_input_set_line_num (a_this, a_pos->line); ++ cr_input_set_cur_index (a_this, a_pos->next_byte_index); ++ cr_input_set_end_of_line (a_this, a_pos->end_of_line); ++ cr_input_set_end_of_file (a_this, a_pos->end_of_file); ++ ++ return CR_OK; ++} +diff --git a/src/st/croco/cr-input.h b/src/st/croco/cr-input.h +new file mode 100644 +index 000000000..9eb402a87 +--- /dev/null ++++ b/src/st/croco/cr-input.h +@@ -0,0 +1,174 @@ ++/* -*- Mode: C; indent-tabs-mode:nil; c-basic-offset:8 -*- */ ++ ++/* ++ * This file is part of The Croco Library ++ * ++ * 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 ++ * See the COPYRIGHTS file for copyrights information. ++ */ ++ ++#ifndef __CR_INPUT_SRC_H__ ++#define __CR_INPUT_SRC_H__ ++ ++ ++#include ++#include "cr-utils.h" ++#include "cr-parsing-location.h" ++ ++G_BEGIN_DECLS ++ ++/** ++ *@file ++ *The libcroco basic input stream class ++ *declaration file. ++ */ ++ ++typedef struct _CRInput CRInput ; ++typedef struct _CRInputPriv CRInputPriv ; ++ ++/** ++ *The #CRInput class provides the abstraction of ++ *an utf8-encoded character stream. ++ */ ++struct _CRInput ++{ ++ CRInputPriv *priv ; ++} ; ++ ++typedef struct _CRInputPos CRInputPos ; ++ ++struct _CRInputPos ++{ ++ glong line ; ++ glong col ; ++ gboolean end_of_file ; ++ gboolean end_of_line ; ++ glong next_byte_index ; ++} ; ++ ++CRInput * ++cr_input_new_from_buf (guchar *a_buf, gulong a_len, ++ enum CREncoding a_enc, gboolean a_free_buf) ; ++CRInput * ++cr_input_new_from_uri (const gchar *a_file_uri, ++ enum CREncoding a_enc) ; ++ ++void ++cr_input_destroy (CRInput *a_this) ; ++ ++void ++cr_input_ref (CRInput *a_this) ; ++ ++gboolean ++cr_input_unref (CRInput *a_this) ; ++ ++enum CRStatus ++cr_input_read_byte (CRInput *a_this, guchar *a_byte) ; ++ ++enum CRStatus ++cr_input_read_char (CRInput *a_this, guint32 *a_char) ; ++ ++enum CRStatus ++cr_input_consume_chars (CRInput *a_this, guint32 a_char, ++ gulong *a_nb_char) ; ++ ++enum CRStatus ++cr_input_consume_char (CRInput *a_this, guint32 a_char) ; ++ ++enum CRStatus ++cr_input_consume_white_spaces (CRInput *a_this, gulong *a_nb_chars) ; ++ ++enum CRStatus ++cr_input_peek_byte (CRInput const *a_this, enum CRSeekPos a_origin, ++ gulong a_offset, guchar *a_byte) ; ++ ++guchar ++cr_input_peek_byte2 (CRInput const *a_this, gulong a_offset, ++ gboolean *a_eof) ; ++ ++enum CRStatus ++cr_input_peek_char (CRInput const *a_this, guint32 *a_char) ; ++ ++guchar * ++cr_input_get_byte_addr (CRInput *a_this, ++ gulong a_offset) ; ++ ++enum CRStatus ++cr_input_get_cur_byte_addr (CRInput *a_this, guchar ** a_offset) ; ++ ++enum CRStatus ++cr_input_seek_index (CRInput *a_this, ++ enum CRSeekPos a_origin, gint a_pos) ; ++ ++enum CRStatus ++cr_input_get_cur_index (CRInput const *a_this, glong *a_index) ; ++ ++enum CRStatus ++cr_input_set_cur_index (CRInput *a_this, glong a_index) ; ++ ++enum CRStatus ++cr_input_get_cur_pos (CRInput const *a_this, CRInputPos * a_pos) ; ++ ++enum CRStatus ++cr_input_set_cur_pos (CRInput *a_this, CRInputPos const *a_pos) ; ++ ++enum CRStatus ++cr_input_get_parsing_location (CRInput const *a_this, ++ CRParsingLocation *a_loc) ; ++ ++enum CRStatus ++cr_input_get_end_of_line (CRInput const *a_this, gboolean *a_eol) ; ++ ++enum CRStatus ++cr_input_set_end_of_line (CRInput *a_this, gboolean a_eol) ; ++ ++enum CRStatus ++cr_input_get_end_of_file (CRInput const *a_this, gboolean *a_eof) ; ++ ++enum CRStatus ++cr_input_set_end_of_file (CRInput *a_this, gboolean a_eof) ; ++ ++enum CRStatus ++cr_input_set_line_num (CRInput *a_this, glong a_line_num) ; ++ ++enum CRStatus ++cr_input_get_line_num (CRInput const *a_this, glong *a_line_num) ; ++ ++enum CRStatus ++cr_input_set_column_num (CRInput *a_this, glong a_col) ; ++ ++enum CRStatus ++cr_input_get_column_num (CRInput const *a_this, glong *a_col) ; ++ ++enum CRStatus ++cr_input_increment_line_num (CRInput *a_this, ++ glong a_increment) ; ++ ++enum CRStatus ++cr_input_increment_col_num (CRInput *a_this, ++ glong a_increment) ; ++ ++glong ++cr_input_get_nb_bytes_left (CRInput const *a_this) ; ++ ++enum CRStatus ++cr_input_end_of_input (CRInput const *a_this, gboolean *a_end_of_input) ; ++ ++G_END_DECLS ++ ++#endif /*__CR_INPUT_SRC_H__*/ ++ +diff --git a/src/st/croco/cr-num.c b/src/st/croco/cr-num.c +new file mode 100644 +index 000000000..d5dbd5fb0 +--- /dev/null ++++ b/src/st/croco/cr-num.c +@@ -0,0 +1,313 @@ ++/* -*- Mode: C; indent-tabs-mode:nil; c-basic-offset: 8-*- */ ++ ++/* ++ * This file is part of The Croco Library ++ * ++ * ++ * 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 ++ * See COPYRIGHTS file for copyrights information. ++ */ ++ ++/** ++ *@CRNum: ++ * ++ *The definition ++ *of the #CRNum class. ++ */ ++ ++#include "cr-num.h" ++#include "string.h" ++ ++/** ++ * cr_num_new: ++ * ++ *#CRNum. ++ * ++ *Returns the newly built instance of ++ *#CRNum. ++ */ ++CRNum * ++cr_num_new (void) ++{ ++ CRNum *result = NULL; ++ ++ result = g_try_malloc (sizeof (CRNum)); ++ ++ if (result == NULL) { ++ cr_utils_trace_info ("Out of memory"); ++ return NULL; ++ } ++ ++ memset (result, 0, sizeof (CRNum)); ++ ++ return result; ++} ++ ++/** ++ * cr_num_new_with_val: ++ * @a_val: the numerical value of the number. ++ * @a_type: the type of number. ++ * ++ * A constructor of #CRNum. ++ * ++ * Returns the newly built instance of #CRNum or ++ * NULL if an error arises. ++ */ ++CRNum * ++cr_num_new_with_val (gdouble a_val, enum CRNumType a_type) ++{ ++ CRNum *result = NULL; ++ ++ result = cr_num_new (); ++ ++ g_return_val_if_fail (result, NULL); ++ ++ result->val = a_val; ++ result->type = a_type; ++ ++ return result; ++} ++ ++/** ++ * cr_num_to_string: ++ *@a_this: the current instance of #CRNum. ++ * ++ *Returns the newly built string representation ++ *of the current instance of #CRNum. The returned ++ *string is NULL terminated. The caller *must* ++ *free the returned string. ++ */ ++guchar * ++cr_num_to_string (CRNum const * a_this) ++{ ++ gdouble test_val = 0.0; ++ ++ guchar *tmp_char1 = NULL, ++ *tmp_char2 = NULL, ++ *result = NULL; ++ ++ g_return_val_if_fail (a_this, NULL); ++ ++ test_val = a_this->val - (glong) a_this->val; ++ ++ if (!test_val) { ++ tmp_char1 = (guchar *) g_strdup_printf ("%ld", (glong) a_this->val); ++ } else { ++ tmp_char1 = (guchar *) g_new0 (char, G_ASCII_DTOSTR_BUF_SIZE + 1); ++ if (tmp_char1 != NULL) ++ g_ascii_dtostr ((gchar *) tmp_char1, G_ASCII_DTOSTR_BUF_SIZE, a_this->val); ++ } ++ ++ g_return_val_if_fail (tmp_char1, NULL); ++ ++ switch (a_this->type) { ++ case NUM_LENGTH_EM: ++ tmp_char2 = (guchar *) "em"; ++ break; ++ ++ case NUM_LENGTH_EX: ++ tmp_char2 = (guchar *) "ex"; ++ break; ++ ++ case NUM_LENGTH_PX: ++ tmp_char2 = (guchar *) "px"; ++ break; ++ ++ case NUM_LENGTH_IN: ++ tmp_char2 = (guchar *) "in"; ++ break; ++ ++ case NUM_LENGTH_CM: ++ tmp_char2 = (guchar *) "cm"; ++ break; ++ ++ case NUM_LENGTH_MM: ++ tmp_char2 = (guchar *) "mm"; ++ break; ++ ++ case NUM_LENGTH_PT: ++ tmp_char2 = (guchar *) "pt"; ++ break; ++ ++ case NUM_LENGTH_PC: ++ tmp_char2 = (guchar *) "pc"; ++ break; ++ ++ case NUM_ANGLE_DEG: ++ tmp_char2 = (guchar *) "deg"; ++ break; ++ ++ case NUM_ANGLE_RAD: ++ tmp_char2 = (guchar *) "rad"; ++ break; ++ ++ case NUM_ANGLE_GRAD: ++ tmp_char2 = (guchar *) "grad"; ++ break; ++ ++ case NUM_TIME_MS: ++ tmp_char2 = (guchar *) "ms"; ++ break; ++ ++ case NUM_TIME_S: ++ tmp_char2 = (guchar *) "s"; ++ break; ++ ++ case NUM_FREQ_HZ: ++ tmp_char2 = (guchar *) "Hz"; ++ break; ++ ++ case NUM_FREQ_KHZ: ++ tmp_char2 = (guchar *) "KHz"; ++ break; ++ ++ case NUM_PERCENTAGE: ++ tmp_char2 = (guchar *) "%"; ++ break; ++ case NUM_INHERIT: ++ tmp_char2 = (guchar *) "inherit"; ++ break ; ++ case NUM_AUTO: ++ tmp_char2 = (guchar *) "auto"; ++ break ; ++ case NUM_GENERIC: ++ tmp_char2 = NULL ; ++ break ; ++ default: ++ tmp_char2 = (guchar *) "unknown"; ++ break; ++ } ++ ++ if (tmp_char2) { ++ result = (guchar *) g_strconcat ((gchar *) tmp_char1, tmp_char2, NULL); ++ g_free (tmp_char1); ++ } else { ++ result = tmp_char1; ++ } ++ ++ return result; ++} ++ ++/** ++ * cr_num_copy: ++ *@a_src: the instance of #CRNum to copy. ++ *Must be non NULL. ++ *@a_dest: the destination of the copy. ++ *Must be non NULL ++ * ++ *Copies an instance of #CRNum. ++ * ++ *Returns CR_OK upon successful completion, an ++ *error code otherwise. ++ */ ++enum CRStatus ++cr_num_copy (CRNum * a_dest, CRNum const * a_src) ++{ ++ g_return_val_if_fail (a_dest && a_src, CR_BAD_PARAM_ERROR); ++ ++ memcpy (a_dest, a_src, sizeof (CRNum)); ++ ++ return CR_OK; ++} ++ ++/** ++ * cr_num_dup: ++ *@a_this: the instance of #CRNum to duplicate. ++ * ++ *Duplicates an instance of #CRNum ++ * ++ *Returns the newly created (duplicated) instance of #CRNum. ++ *Must be freed by cr_num_destroy(). ++ */ ++CRNum * ++cr_num_dup (CRNum const * a_this) ++{ ++ CRNum *result = NULL; ++ enum CRStatus status = CR_OK; ++ ++ g_return_val_if_fail (a_this, NULL); ++ ++ result = cr_num_new (); ++ g_return_val_if_fail (result, NULL); ++ ++ status = cr_num_copy (result, a_this); ++ g_return_val_if_fail (status == CR_OK, NULL); ++ ++ return result; ++} ++ ++/** ++ * cr_num_set: ++ *Sets an instance of #CRNum. ++ *@a_this: the current instance of #CRNum to be set. ++ *@a_val: the new numerical value to be hold by the current ++ *instance of #CRNum ++ *@a_type: the new type of #CRNum. ++ * ++ * Returns CR_OK upon succesful completion, an error code otherwise. ++ */ ++enum CRStatus ++cr_num_set (CRNum * a_this, gdouble a_val, enum CRNumType a_type) ++{ ++ g_return_val_if_fail (a_this, CR_BAD_PARAM_ERROR); ++ ++ a_this->val = a_val; ++ a_this->type = a_type; ++ ++ return CR_OK; ++} ++ ++/** ++ * cr_num_is_fixed_length: ++ * @a_this: the current instance of #CRNum . ++ * ++ *Tests if the current instance of #CRNum is a fixed ++ *length value or not. Typically a fixed length value ++ *is anything from NUM_LENGTH_EM to NUM_LENGTH_PC. ++ *See the definition of #CRNumType to see what we mean. ++ * ++ *Returns TRUE if the instance of #CRNum is a fixed length number, ++ *FALSE otherwise. ++ */ ++gboolean ++cr_num_is_fixed_length (CRNum const * a_this) ++{ ++ gboolean result = FALSE; ++ ++ g_return_val_if_fail (a_this, FALSE); ++ ++ if (a_this->type >= NUM_LENGTH_EM ++ && a_this->type <= NUM_LENGTH_PC) { ++ result = TRUE ; ++ } ++ return result ; ++} ++ ++/** ++ * cr_num_destroy: ++ *@a_this: the this pointer of ++ *the current instance of #CRNum. ++ * ++ *The destructor of #CRNum. ++ */ ++void ++cr_num_destroy (CRNum * a_this) ++{ ++ g_return_if_fail (a_this); ++ ++ g_free (a_this); ++} +diff --git a/src/st/croco/cr-num.h b/src/st/croco/cr-num.h +new file mode 100644 +index 000000000..2b73aaf79 +--- /dev/null ++++ b/src/st/croco/cr-num.h +@@ -0,0 +1,127 @@ ++/* -*- Mode: C; indent-tabs-mode:nil; c-basic-offset: 8-*- */ ++ ++/* ++ * This file is part of The Croco Library ++ * ++ * 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 ++ * See COPYRIGHTS file for copyright information ++ */ ++ ++ ++/** ++ *@file ++ *The declaration ++ *of the #CRNum class. ++ */ ++ ++#ifndef __CR_NUM_H__ ++#define __CR_NUM_H__ ++ ++#include ++#include "cr-utils.h" ++#include "cr-parsing-location.h" ++ ++G_BEGIN_DECLS ++ ++/** ++ *@file ++ *The declaration of the #CRNum class. ++ * ++ */ ++ ++/** ++ *The different types ++ *of numbers. ++ *Please, do not modify ++ *the declaration order of the enum ++ *members, unless you know ++ *what you are doing. ++ */ ++enum CRNumType ++{ ++ NUM_AUTO = 0, ++ NUM_GENERIC, ++ NUM_LENGTH_EM, ++ NUM_LENGTH_EX, ++ NUM_LENGTH_PX, ++ NUM_LENGTH_IN, ++ NUM_LENGTH_CM, ++ NUM_LENGTH_MM, ++ NUM_LENGTH_PT, ++ NUM_LENGTH_PC, ++ NUM_ANGLE_DEG, ++ NUM_ANGLE_RAD, ++ NUM_ANGLE_GRAD, ++ NUM_TIME_MS, ++ NUM_TIME_S, ++ NUM_FREQ_HZ, ++ NUM_FREQ_KHZ, ++ NUM_PERCENTAGE, ++ NUM_INHERIT, ++ NUM_UNKNOWN_TYPE, ++ NB_NUM_TYPE ++} ; ++ ++ ++/** ++ *An abstraction of a number (num) ++ *as defined in the css2 spec. ++ */ ++typedef struct _CRNum CRNum ; ++ ++/** ++ *An abstraction of a number (num) ++ *as defined in the css2 spec. ++ */ ++struct _CRNum ++{ ++ enum CRNumType type ; ++ gdouble val ; ++ CRParsingLocation location ; ++} ; ++ ++CRNum * ++cr_num_new (void) ; ++ ++CRNum * ++cr_num_new_with_val (gdouble a_val, ++ enum CRNumType a_type) ; ++ ++CRNum * ++cr_num_dup (CRNum const *a_this) ; ++ ++guchar * ++cr_num_to_string (CRNum const *a_this) ; ++ ++enum CRStatus ++cr_num_copy (CRNum *a_dest, CRNum const *a_src) ; ++ ++enum CRStatus ++cr_num_set (CRNum *a_this, gdouble a_val, ++ enum CRNumType a_type) ; ++ ++gboolean ++cr_num_is_fixed_length (CRNum const *a_this) ; ++ ++void ++cr_num_destroy (CRNum *a_this) ; ++ ++ ++G_END_DECLS ++ ++ ++#endif /*__CR_NUM_H__*/ +diff --git a/src/st/croco/cr-om-parser.c b/src/st/croco/cr-om-parser.c +new file mode 100644 +index 000000000..ccc45b3e9 +--- /dev/null ++++ b/src/st/croco/cr-om-parser.c +@@ -0,0 +1,1142 @@ ++/* -*- Mode: C; indent-tabs-mode:nil; c-basic-offset: 8-*- */ ++ ++/* ++ * This file is part of The Croco Library ++ * ++ * 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 ++ * See COPYRIGHTS file for copyright information. ++ */ ++ ++#include ++#include "cr-utils.h" ++#include "cr-om-parser.h" ++ ++/** ++ *@CROMParser: ++ * ++ *The definition of the CSS Object Model Parser. ++ *This parser uses (and sits) the SAC api of libcroco defined ++ *in cr-parser.h and cr-doc-handler.h ++ */ ++ ++struct _CROMParserPriv { ++ CRParser *parser; ++}; ++ ++#define PRIVATE(a_this) ((a_this)->priv) ++ ++/* ++ *Forward declaration of a type defined later ++ *in this file. ++ */ ++struct _ParsingContext; ++typedef struct _ParsingContext ParsingContext; ++ ++static ParsingContext *new_parsing_context (void); ++ ++static void destroy_context (ParsingContext * a_ctxt); ++ ++static void unrecoverable_error (CRDocHandler * a_this); ++ ++static void error (CRDocHandler * a_this); ++ ++static void property (CRDocHandler * a_this, ++ CRString * a_name, ++ CRTerm * a_expression, ++ gboolean a_important); ++ ++static void end_selector (CRDocHandler * a_this, ++ CRSelector * a_selector_list); ++ ++static void start_selector (CRDocHandler * a_this, ++ CRSelector * a_selector_list); ++ ++static void start_font_face (CRDocHandler * a_this, ++ CRParsingLocation *a_location); ++ ++static void end_font_face (CRDocHandler * a_this); ++ ++static void end_document (CRDocHandler * a_this); ++ ++static void start_document (CRDocHandler * a_this); ++ ++static void charset (CRDocHandler * a_this, ++ CRString * a_charset, ++ CRParsingLocation *a_location); ++ ++static void start_page (CRDocHandler * a_this, CRString * a_page, ++ CRString * a_pseudo_page, ++ CRParsingLocation *a_location); ++ ++static void end_page (CRDocHandler * a_this, CRString * a_page, ++ CRString * a_pseudo_page); ++ ++static void start_media (CRDocHandler * a_this, ++ GList * a_media_list, ++ CRParsingLocation *a_location); ++ ++static void end_media (CRDocHandler * a_this, ++ GList * a_media_list); ++ ++static void import_style (CRDocHandler * a_this, ++ GList * a_media_list, ++ CRString * a_uri, ++ CRString * a_uri_default_ns, ++ CRParsingLocation *a_location); ++ ++struct _ParsingContext { ++ CRStyleSheet *stylesheet; ++ CRStatement *cur_stmt; ++ CRStatement *cur_media_stmt; ++}; ++ ++/******************************************** ++ *Private methods ++ ********************************************/ ++ ++static ParsingContext * ++new_parsing_context (void) ++{ ++ ParsingContext *result = NULL; ++ ++ result = g_try_malloc (sizeof (ParsingContext)); ++ if (!result) { ++ cr_utils_trace_info ("Out of Memory"); ++ return NULL; ++ } ++ memset (result, 0, sizeof (ParsingContext)); ++ return result; ++} ++ ++static void ++destroy_context (ParsingContext * a_ctxt) ++{ ++ g_return_if_fail (a_ctxt); ++ ++ if (a_ctxt->stylesheet) { ++ cr_stylesheet_destroy (a_ctxt->stylesheet); ++ a_ctxt->stylesheet = NULL; ++ } ++ if (a_ctxt->cur_stmt) { ++ cr_statement_destroy (a_ctxt->cur_stmt); ++ a_ctxt->cur_stmt = NULL; ++ } ++ g_free (a_ctxt); ++} ++ ++static enum CRStatus ++cr_om_parser_init_default_sac_handler (CROMParser * a_this) ++{ ++ CRDocHandler *sac_handler = NULL; ++ gboolean created_handler = FALSE; ++ enum CRStatus status = CR_OK; ++ ++ g_return_val_if_fail (a_this && PRIVATE (a_this) ++ && PRIVATE (a_this)->parser, ++ CR_BAD_PARAM_ERROR); ++ ++ status = cr_parser_get_sac_handler (PRIVATE (a_this)->parser, ++ &sac_handler); ++ g_return_val_if_fail (status == CR_OK, status); ++ ++ if (!sac_handler) { ++ sac_handler = cr_doc_handler_new (); ++ created_handler = TRUE; ++ } ++ ++ /* ++ *initialyze here the sac handler. ++ */ ++ sac_handler->start_document = start_document; ++ sac_handler->end_document = end_document; ++ sac_handler->start_selector = start_selector; ++ sac_handler->end_selector = end_selector; ++ sac_handler->property = property; ++ sac_handler->start_font_face = start_font_face; ++ sac_handler->end_font_face = end_font_face; ++ sac_handler->error = error; ++ sac_handler->unrecoverable_error = unrecoverable_error; ++ sac_handler->charset = charset; ++ sac_handler->start_page = start_page; ++ sac_handler->end_page = end_page; ++ sac_handler->start_media = start_media; ++ sac_handler->end_media = end_media; ++ sac_handler->import_style = import_style; ++ ++ if (created_handler) { ++ status = cr_parser_set_sac_handler (PRIVATE (a_this)->parser, ++ sac_handler); ++ cr_doc_handler_unref (sac_handler); ++ } ++ ++ return status; ++ ++} ++ ++static void ++start_document (CRDocHandler * a_this) ++{ ++ ParsingContext *ctxt = NULL; ++ CRStyleSheet *stylesheet = NULL; ++ ++ g_return_if_fail (a_this); ++ ++ ctxt = new_parsing_context (); ++ g_return_if_fail (ctxt); ++ ++ stylesheet = cr_stylesheet_new (NULL); ++ ctxt->stylesheet = stylesheet; ++ cr_doc_handler_set_ctxt (a_this, ctxt); ++} ++ ++static void ++start_font_face (CRDocHandler * a_this, ++ CRParsingLocation *a_location) ++{ ++ enum CRStatus status = CR_OK; ++ ParsingContext *ctxt = NULL; ++ ParsingContext **ctxtptr = NULL; ++ ++ g_return_if_fail (a_this); ++ ++ g_return_if_fail (a_this); ++ ctxtptr = &ctxt; ++ status = cr_doc_handler_get_ctxt (a_this, (gpointer *) ctxtptr); ++ g_return_if_fail (status == CR_OK && ctxt); ++ g_return_if_fail (ctxt->cur_stmt == NULL); ++ ++ ctxt->cur_stmt = ++ cr_statement_new_at_font_face_rule (ctxt->stylesheet, NULL); ++ ++ g_return_if_fail (ctxt->cur_stmt); ++} ++ ++static void ++end_font_face (CRDocHandler * a_this) ++{ ++ enum CRStatus status = CR_OK; ++ ParsingContext *ctxt = NULL; ++ ParsingContext **ctxtptr = NULL; ++ CRStatement *stmts = NULL; ++ ++ g_return_if_fail (a_this); ++ ++ g_return_if_fail (a_this); ++ ctxtptr = &ctxt; ++ status = cr_doc_handler_get_ctxt (a_this, (gpointer *) ctxtptr); ++ g_return_if_fail (status == CR_OK && ctxt); ++ g_return_if_fail ++ (ctxt->cur_stmt ++ && ctxt->cur_stmt->type == AT_FONT_FACE_RULE_STMT ++ && ctxt->stylesheet); ++ ++ stmts = cr_statement_append (ctxt->stylesheet->statements, ++ ctxt->cur_stmt); ++ if (!stmts) ++ goto error; ++ ++ ctxt->stylesheet->statements = stmts; ++ stmts = NULL; ++ ctxt->cur_stmt = NULL; ++ ++ return; ++ ++ error: ++ ++ if (ctxt->cur_stmt) { ++ cr_statement_destroy (ctxt->cur_stmt); ++ ctxt->cur_stmt = NULL; ++ } ++ ++ if (!stmts) { ++ cr_statement_destroy (stmts); ++ stmts = NULL; ++ } ++} ++ ++static void ++end_document (CRDocHandler * a_this) ++{ ++ enum CRStatus status = CR_OK; ++ ParsingContext *ctxt = NULL; ++ ParsingContext **ctxtptr = NULL; ++ ++ g_return_if_fail (a_this); ++ ctxtptr = &ctxt; ++ status = cr_doc_handler_get_ctxt (a_this, (gpointer *) ctxtptr); ++ g_return_if_fail (status == CR_OK && ctxt); ++ ++ if (!ctxt->stylesheet || ctxt->cur_stmt) ++ goto error; ++ ++ status = cr_doc_handler_set_result (a_this, ctxt->stylesheet); ++ g_return_if_fail (status == CR_OK); ++ ++ ctxt->stylesheet = NULL; ++ destroy_context (ctxt); ++ cr_doc_handler_set_ctxt (a_this, NULL); ++ ++ return; ++ ++ error: ++ if (ctxt) { ++ destroy_context (ctxt); ++ } ++} ++ ++static void ++charset (CRDocHandler * a_this, CRString * a_charset, ++ CRParsingLocation *a_location) ++{ ++ enum CRStatus status = CR_OK; ++ CRStatement *stmt = NULL, ++ *stmt2 = NULL; ++ CRString *charset = NULL; ++ ++ ParsingContext *ctxt = NULL; ++ ParsingContext **ctxtptr = NULL; ++ ++ g_return_if_fail (a_this); ++ ctxtptr = &ctxt; ++ status = cr_doc_handler_get_ctxt (a_this, (gpointer *) ctxtptr); ++ g_return_if_fail (status == CR_OK && ctxt); ++ g_return_if_fail (ctxt->stylesheet); ++ ++ charset = cr_string_dup (a_charset) ; ++ stmt = cr_statement_new_at_charset_rule (ctxt->stylesheet, charset); ++ g_return_if_fail (stmt); ++ stmt2 = cr_statement_append (ctxt->stylesheet->statements, stmt); ++ if (!stmt2) { ++ if (stmt) { ++ cr_statement_destroy (stmt); ++ stmt = NULL; ++ } ++ if (charset) { ++ cr_string_destroy (charset); ++ } ++ return; ++ } ++ ctxt->stylesheet->statements = stmt2; ++ stmt2 = NULL; ++} ++ ++static void ++start_page (CRDocHandler * a_this, ++ CRString * a_page, ++ CRString * a_pseudo, ++ CRParsingLocation *a_location) ++{ ++ enum CRStatus status = CR_OK; ++ ParsingContext *ctxt = NULL; ++ ParsingContext **ctxtptr = NULL; ++ ++ g_return_if_fail (a_this); ++ ctxtptr = &ctxt; ++ status = cr_doc_handler_get_ctxt (a_this, (gpointer *) ctxtptr); ++ g_return_if_fail (status == CR_OK && ctxt); ++ g_return_if_fail (ctxt->cur_stmt == NULL); ++ ++ ctxt->cur_stmt = cr_statement_new_at_page_rule ++ (ctxt->stylesheet, NULL, NULL, NULL); ++ if (a_page) { ++ ctxt->cur_stmt->kind.page_rule->name = ++ cr_string_dup (a_page) ; ++ ++ if (!ctxt->cur_stmt->kind.page_rule->name) { ++ goto error; ++ } ++ } ++ if (a_pseudo) { ++ ctxt->cur_stmt->kind.page_rule->pseudo = ++ cr_string_dup (a_pseudo) ; ++ if (!ctxt->cur_stmt->kind.page_rule->pseudo) { ++ goto error; ++ } ++ } ++ return; ++ ++ error: ++ if (ctxt->cur_stmt) { ++ cr_statement_destroy (ctxt->cur_stmt); ++ ctxt->cur_stmt = NULL; ++ } ++} ++ ++static void ++end_page (CRDocHandler * a_this, ++ CRString * a_page, ++ CRString * a_pseudo_page) ++{ ++ enum CRStatus status = CR_OK; ++ ParsingContext *ctxt = NULL; ++ ParsingContext **ctxtptr = NULL; ++ CRStatement *stmt = NULL; ++ ++ (void) a_page; ++ (void) a_pseudo_page; ++ ++ g_return_if_fail (a_this); ++ ++ ctxtptr = &ctxt; ++ status = cr_doc_handler_get_ctxt (a_this, (gpointer *) ctxtptr); ++ ++ g_return_if_fail (status == CR_OK && ctxt); ++ ++ g_return_if_fail (ctxt->cur_stmt ++ && ctxt->cur_stmt->type == AT_PAGE_RULE_STMT ++ && ctxt->stylesheet); ++ ++ stmt = cr_statement_append (ctxt->stylesheet->statements, ++ ctxt->cur_stmt); ++ ++ if (stmt) { ++ ctxt->stylesheet->statements = stmt; ++ stmt = NULL; ++ ctxt->cur_stmt = NULL; ++ } ++ ++ if (ctxt->cur_stmt) { ++ cr_statement_destroy (ctxt->cur_stmt); ++ ctxt->cur_stmt = NULL; ++ } ++ a_page = NULL; /*keep compiler happy */ ++ a_pseudo_page = NULL; /*keep compiler happy */ ++} ++ ++static void ++start_media (CRDocHandler * a_this, ++ GList * a_media_list, ++ CRParsingLocation *a_location) ++{ ++ enum CRStatus status = CR_OK; ++ ParsingContext *ctxt = NULL; ++ ParsingContext **ctxtptr = NULL; ++ GList *media_list = NULL; ++ ++ g_return_if_fail (a_this); ++ ctxtptr = &ctxt; ++ status = cr_doc_handler_get_ctxt (a_this, (gpointer *) ctxtptr); ++ g_return_if_fail (status == CR_OK && ctxt); ++ ++ g_return_if_fail (ctxt ++ && ctxt->cur_stmt == NULL ++ && ctxt->cur_media_stmt == NULL ++ && ctxt->stylesheet); ++ if (a_media_list) { ++ /*duplicate the media_list */ ++ media_list = cr_utils_dup_glist_of_cr_string ++ (a_media_list); ++ } ++ ctxt->cur_media_stmt = ++ cr_statement_new_at_media_rule ++ (ctxt->stylesheet, NULL, media_list); ++ ++} ++ ++static void ++end_media (CRDocHandler * a_this, GList * a_media_list) ++{ ++ enum CRStatus status = CR_OK; ++ ParsingContext *ctxt = NULL; ++ ParsingContext **ctxtptr = NULL; ++ CRStatement *stmts = NULL; ++ ++ (void) a_media_list; ++ ++ g_return_if_fail (a_this); ++ ++ ctxtptr = &ctxt; ++ status = cr_doc_handler_get_ctxt (a_this, (gpointer *) ctxtptr); ++ ++ g_return_if_fail (status == CR_OK && ctxt); ++ ++ g_return_if_fail (ctxt ++ && ctxt->cur_media_stmt ++ && ctxt->cur_media_stmt->type == AT_MEDIA_RULE_STMT ++ && ctxt->stylesheet); ++ ++ stmts = cr_statement_append (ctxt->stylesheet->statements, ++ ctxt->cur_media_stmt); ++ ++ if (!stmts) { ++ cr_statement_destroy (ctxt->cur_media_stmt); ++ ctxt->cur_media_stmt = NULL; ++ } ++ ++ ctxt->stylesheet->statements = stmts; ++ stmts = NULL; ++ ++ ctxt->cur_stmt = NULL ; ++ ctxt->cur_media_stmt = NULL ; ++ a_media_list = NULL; ++} ++ ++static void ++import_style (CRDocHandler * a_this, ++ GList * a_media_list, ++ CRString * a_uri, ++ CRString * a_uri_default_ns, ++ CRParsingLocation *a_location) ++{ ++ enum CRStatus status = CR_OK; ++ CRString *uri = NULL; ++ CRStatement *stmt = NULL, ++ *stmt2 = NULL; ++ ParsingContext *ctxt = NULL; ++ ParsingContext **ctxtptr = NULL; ++ GList *media_list = NULL ; ++ ++ (void) a_uri_default_ns; ++ ++ g_return_if_fail (a_this); ++ ++ ctxtptr = &ctxt; ++ status = cr_doc_handler_get_ctxt (a_this, (gpointer *) ctxtptr); ++ ++ g_return_if_fail (status == CR_OK && ctxt); ++ ++ g_return_if_fail (ctxt->stylesheet); ++ ++ uri = cr_string_dup (a_uri) ; ++ ++ if (a_media_list) ++ media_list = cr_utils_dup_glist_of_cr_string (a_media_list) ; ++ ++ stmt = cr_statement_new_at_import_rule ++ (ctxt->stylesheet, uri, media_list, NULL); ++ ++ if (!stmt) ++ goto error; ++ ++ if (ctxt->cur_stmt) { ++ stmt2 = cr_statement_append (ctxt->cur_stmt, stmt); ++ if (!stmt2) ++ goto error; ++ ctxt->cur_stmt = stmt2; ++ stmt2 = NULL; ++ stmt = NULL; ++ } else { ++ stmt2 = cr_statement_append (ctxt->stylesheet->statements, ++ stmt); ++ if (!stmt2) ++ goto error; ++ ctxt->stylesheet->statements = stmt2; ++ stmt2 = NULL; ++ stmt = NULL; ++ } ++ ++ return; ++ ++ error: ++ if (uri) { ++ cr_string_destroy (uri); ++ } ++ ++ if (stmt) { ++ cr_statement_destroy (stmt); ++ stmt = NULL; ++ } ++ a_uri_default_ns = NULL; /*keep compiler happy */ ++} ++ ++static void ++start_selector (CRDocHandler * a_this, CRSelector * a_selector_list) ++{ ++ enum CRStatus status = CR_OK ; ++ ParsingContext *ctxt = NULL; ++ ParsingContext **ctxtptr = NULL; ++ ++ g_return_if_fail (a_this); ++ ctxtptr = &ctxt; ++ status = cr_doc_handler_get_ctxt (a_this, (gpointer *) ctxtptr); ++ g_return_if_fail (status == CR_OK && ctxt); ++ if (ctxt->cur_stmt) { ++ /*hmm, this should be NULL so free it */ ++ cr_statement_destroy (ctxt->cur_stmt); ++ ctxt->cur_stmt = NULL; ++ } ++ ++ ctxt->cur_stmt = cr_statement_new_ruleset ++ (ctxt->stylesheet, a_selector_list, NULL, NULL); ++} ++ ++static void ++end_selector (CRDocHandler * a_this, CRSelector * a_selector_list) ++{ ++ enum CRStatus status = CR_OK; ++ ParsingContext *ctxt = NULL; ++ ParsingContext **ctxtptr = NULL; ++ ++ (void) a_selector_list; ++ ++ g_return_if_fail (a_this); ++ ++ ctxtptr = &ctxt; ++ status = cr_doc_handler_get_ctxt (a_this, (gpointer *) ctxtptr); ++ ++ g_return_if_fail (status == CR_OK && ctxt); ++ ++ g_return_if_fail (ctxt->cur_stmt && ctxt->stylesheet); ++ ++ if (ctxt->cur_stmt) { ++ CRStatement *stmts = NULL; ++ ++ if (ctxt->cur_media_stmt) { ++ CRAtMediaRule *media_rule = NULL; ++ ++ media_rule = ctxt->cur_media_stmt->kind.media_rule; ++ ++ stmts = cr_statement_append ++ (media_rule->rulesets, ctxt->cur_stmt); ++ ++ if (!stmts) { ++ cr_utils_trace_info ++ ("Could not append a new statement"); ++ cr_statement_destroy (media_rule->rulesets); ++ ctxt->cur_media_stmt-> ++ kind.media_rule->rulesets = NULL; ++ return; ++ } ++ media_rule->rulesets = stmts; ++ ctxt->cur_stmt = NULL; ++ } else { ++ stmts = cr_statement_append ++ (ctxt->stylesheet->statements, ++ ctxt->cur_stmt); ++ if (!stmts) { ++ cr_utils_trace_info ++ ("Could not append a new statement"); ++ cr_statement_destroy (ctxt->cur_stmt); ++ ctxt->cur_stmt = NULL; ++ return; ++ } ++ ctxt->stylesheet->statements = stmts; ++ ctxt->cur_stmt = NULL; ++ } ++ ++ } ++ ++ a_selector_list = NULL; /*keep compiler happy */ ++} ++ ++static void ++property (CRDocHandler * a_this, ++ CRString * a_name, ++ CRTerm * a_expression, ++ gboolean a_important) ++{ ++ enum CRStatus status = CR_OK; ++ ParsingContext *ctxt = NULL; ++ ParsingContext **ctxtptr = NULL; ++ CRDeclaration *decl = NULL, ++ *decl2 = NULL; ++ CRString *str = NULL; ++ ++ g_return_if_fail (a_this); ++ ctxtptr = &ctxt; ++ status = cr_doc_handler_get_ctxt (a_this, (gpointer *) ctxtptr); ++ g_return_if_fail (status == CR_OK && ctxt); ++ ++ /* ++ *make sure a current ruleset statement has been allocated ++ *already. ++ */ ++ g_return_if_fail ++ (ctxt->cur_stmt ++ && ++ (ctxt->cur_stmt->type == RULESET_STMT ++ || ctxt->cur_stmt->type == AT_FONT_FACE_RULE_STMT ++ || ctxt->cur_stmt->type == AT_PAGE_RULE_STMT)); ++ ++ if (a_name) { ++ str = cr_string_dup (a_name); ++ g_return_if_fail (str); ++ } ++ ++ /*instanciates a new declaration */ ++ decl = cr_declaration_new (ctxt->cur_stmt, str, a_expression); ++ g_return_if_fail (decl); ++ str = NULL; ++ decl->important = a_important; ++ /* ++ *add the new declaration to the current statement ++ *being build. ++ */ ++ switch (ctxt->cur_stmt->type) { ++ case RULESET_STMT: ++ decl2 = cr_declaration_append ++ (ctxt->cur_stmt->kind.ruleset->decl_list, decl); ++ if (!decl2) { ++ cr_declaration_destroy (decl); ++ cr_utils_trace_info ++ ("Could not append decl to ruleset"); ++ goto error; ++ } ++ ctxt->cur_stmt->kind.ruleset->decl_list = decl2; ++ decl = NULL; ++ decl2 = NULL; ++ break; ++ ++ case AT_FONT_FACE_RULE_STMT: ++ decl2 = cr_declaration_append ++ (ctxt->cur_stmt->kind.font_face_rule->decl_list, ++ decl); ++ if (!decl2) { ++ cr_declaration_destroy (decl); ++ cr_utils_trace_info ++ ("Could not append decl to ruleset"); ++ goto error; ++ } ++ ctxt->cur_stmt->kind.font_face_rule->decl_list = decl2; ++ decl = NULL; ++ decl2 = NULL; ++ break; ++ case AT_PAGE_RULE_STMT: ++ decl2 = cr_declaration_append ++ (ctxt->cur_stmt->kind.page_rule->decl_list, decl); ++ if (!decl2) { ++ cr_declaration_destroy (decl); ++ cr_utils_trace_info ++ ("Could not append decl to ruleset"); ++ goto error; ++ } ++ ctxt->cur_stmt->kind.page_rule->decl_list = decl2; ++ decl = NULL; ++ decl2 = NULL; ++ break; ++ ++ default: ++ goto error; ++ break; ++ } ++ ++ return; ++ ++ error: ++ if (str) { ++ g_free (str); ++ str = NULL; ++ } ++ ++ if (decl) { ++ cr_declaration_destroy (decl); ++ decl = NULL; ++ } ++} ++ ++static void ++error (CRDocHandler * a_this) ++{ ++ enum CRStatus status = CR_OK; ++ ParsingContext *ctxt = NULL; ++ ParsingContext **ctxtptr = NULL; ++ ++ g_return_if_fail (a_this); ++ ctxtptr = &ctxt; ++ status = cr_doc_handler_get_ctxt (a_this, (gpointer *) ctxtptr); ++ g_return_if_fail (status == CR_OK && ctxt); ++ ++ if (ctxt->cur_stmt) { ++ cr_statement_destroy (ctxt->cur_stmt); ++ ctxt->cur_stmt = NULL; ++ } ++} ++ ++static void ++unrecoverable_error (CRDocHandler * a_this) ++{ ++ enum CRStatus status = CR_OK; ++ ParsingContext *ctxt = NULL; ++ ParsingContext **ctxtptr = NULL; ++ ++ ctxtptr = &ctxt; ++ status = cr_doc_handler_get_ctxt (a_this, (gpointer *) ctxtptr); ++ g_return_if_fail (status == CR_OK); ++ ++ if (ctxt) { ++ if (ctxt->stylesheet) { ++ status = cr_doc_handler_set_result ++ (a_this, ctxt->stylesheet); ++ g_return_if_fail (status == CR_OK); ++ } ++ g_free (ctxt); ++ cr_doc_handler_set_ctxt (a_this, NULL); ++ } ++} ++ ++/******************************************** ++ *Public methods ++ ********************************************/ ++ ++/** ++ * cr_om_parser_new: ++ *@a_input: the input stream. ++ * ++ *Constructor of the CROMParser. ++ *Returns the newly built instance of #CROMParser. ++ */ ++CROMParser * ++cr_om_parser_new (CRInput * a_input) ++{ ++ CROMParser *result = NULL; ++ enum CRStatus status = CR_OK; ++ ++ result = g_try_malloc (sizeof (CROMParser)); ++ ++ if (!result) { ++ cr_utils_trace_info ("Out of memory"); ++ return NULL; ++ } ++ ++ memset (result, 0, sizeof (CROMParser)); ++ PRIVATE (result) = g_try_malloc (sizeof (CROMParserPriv)); ++ ++ if (!PRIVATE (result)) { ++ cr_utils_trace_info ("Out of memory"); ++ goto error; ++ } ++ ++ memset (PRIVATE (result), 0, sizeof (CROMParserPriv)); ++ ++ PRIVATE (result)->parser = cr_parser_new_from_input (a_input); ++ ++ if (!PRIVATE (result)->parser) { ++ cr_utils_trace_info ("parsing instantiation failed"); ++ goto error; ++ } ++ ++ status = cr_om_parser_init_default_sac_handler (result); ++ ++ if (status != CR_OK) { ++ goto error; ++ } ++ ++ return result; ++ ++ error: ++ ++ if (result) { ++ cr_om_parser_destroy (result); ++ } ++ ++ return NULL; ++} ++ ++/** ++ * cr_om_parser_parse_buf: ++ *@a_this: the current instance of #CROMParser. ++ *@a_buf: the in memory buffer to parse. ++ *@a_len: the length of the in memory buffer in number of bytes. ++ *@a_enc: the encoding of the in memory buffer. ++ *@a_result: out parameter the resulting style sheet ++ * ++ *Parses the content of an in memory buffer. ++ * ++ *Returns CR_OK upon successfull completion, an error code otherwise. ++ */ ++enum CRStatus ++cr_om_parser_parse_buf (CROMParser * a_this, ++ const guchar * a_buf, ++ gulong a_len, ++ enum CREncoding a_enc, CRStyleSheet ** a_result) ++{ ++ ++ enum CRStatus status = CR_OK; ++ ++ g_return_val_if_fail (a_this && a_result, CR_BAD_PARAM_ERROR); ++ ++ if (!PRIVATE (a_this)->parser) { ++ PRIVATE (a_this)->parser = cr_parser_new (NULL); ++ } ++ ++ status = cr_parser_parse_buf (PRIVATE (a_this)->parser, ++ a_buf, a_len, a_enc); ++ ++ if (status == CR_OK) { ++ CRStyleSheet *result = NULL; ++ CRStyleSheet **resultptr = NULL; ++ CRDocHandler *sac_handler = NULL; ++ ++ cr_parser_get_sac_handler (PRIVATE (a_this)->parser, ++ &sac_handler); ++ g_return_val_if_fail (sac_handler, CR_ERROR); ++ resultptr = &result; ++ status = cr_doc_handler_get_result (sac_handler, ++ (gpointer *) resultptr); ++ g_return_val_if_fail (status == CR_OK, status); ++ ++ if (result) ++ *a_result = result; ++ } ++ ++ return status; ++} ++ ++/** ++ * cr_om_parser_simply_parse_buf: ++ *@a_buf: the css2 in memory buffer. ++ *@a_len: the length of the in memory buffer. ++ *@a_enc: the encoding of the in memory buffer. ++ *@a_result: out parameter. The resulting css2 style sheet. ++ * ++ *The simpler way to parse an in memory css2 buffer. ++ * ++ *Returns CR_OK upon successfull completion, an error code otherwise. ++ */ ++enum CRStatus ++cr_om_parser_simply_parse_buf (const guchar * a_buf, ++ gulong a_len, ++ enum CREncoding a_enc, ++ CRStyleSheet ** a_result) ++{ ++ CROMParser *parser = NULL; ++ enum CRStatus status = CR_OK; ++ ++ parser = cr_om_parser_new (NULL); ++ if (!parser) { ++ cr_utils_trace_info ("Could not create om parser"); ++ cr_utils_trace_info ("System possibly out of memory"); ++ return CR_ERROR; ++ } ++ ++ status = cr_om_parser_parse_buf (parser, a_buf, a_len, ++ a_enc, a_result); ++ ++ if (parser) { ++ cr_om_parser_destroy (parser); ++ parser = NULL; ++ } ++ ++ return status; ++} ++ ++/** ++ * cr_om_parser_parse_file: ++ *@a_this: the current instance of the cssom parser. ++ *@a_file_uri: the uri of the file. ++ *(only local file paths are suppported so far) ++ *@a_enc: the encoding of the file. ++ *@a_result: out parameter. A pointer ++ *the build css object model. ++ * ++ *Parses a css2 stylesheet contained ++ *in a file. ++ * ++ * Returns CR_OK upon succesful completion, an error code otherwise. ++ */ ++enum CRStatus ++cr_om_parser_parse_file (CROMParser * a_this, ++ const guchar * a_file_uri, ++ enum CREncoding a_enc, CRStyleSheet ** a_result) ++{ ++ enum CRStatus status = CR_OK; ++ ++ g_return_val_if_fail (a_this && a_file_uri && a_result, ++ CR_BAD_PARAM_ERROR); ++ ++ if (!PRIVATE (a_this)->parser) { ++ PRIVATE (a_this)->parser = cr_parser_new_from_file ++ (a_file_uri, a_enc); ++ } ++ ++ status = cr_parser_parse_file (PRIVATE (a_this)->parser, ++ a_file_uri, a_enc); ++ ++ if (status == CR_OK) { ++ CRStyleSheet *result = NULL; ++ CRStyleSheet **resultptr = NULL; ++ CRDocHandler *sac_handler = NULL; ++ ++ cr_parser_get_sac_handler (PRIVATE (a_this)->parser, ++ &sac_handler); ++ g_return_val_if_fail (sac_handler, CR_ERROR); ++ resultptr = &result; ++ status = cr_doc_handler_get_result ++ (sac_handler, (gpointer *) resultptr); ++ g_return_val_if_fail (status == CR_OK, status); ++ if (result) ++ *a_result = result; ++ } ++ ++ return status; ++} ++ ++/** ++ * cr_om_parser_simply_parse_file: ++ *@a_file_path: the css2 local file path. ++ *@a_enc: the file encoding. ++ *@a_result: out parameter. The returned css stylesheet. ++ *Must be freed by the caller using cr_stylesheet_destroy. ++ * ++ *The simpler method to parse a css2 file. ++ * ++ *Returns CR_OK upon successfull completion, an error code otherwise. ++ *Note that this method uses cr_om_parser_parse_file() so both methods ++ *have the same return values. ++ */ ++enum CRStatus ++cr_om_parser_simply_parse_file (const guchar * a_file_path, ++ enum CREncoding a_enc, ++ CRStyleSheet ** a_result) ++{ ++ CROMParser *parser = NULL; ++ enum CRStatus status = CR_OK; ++ ++ parser = cr_om_parser_new (NULL); ++ if (!parser) { ++ cr_utils_trace_info ("Could not allocate om parser"); ++ cr_utils_trace_info ("System may be out of memory"); ++ return CR_ERROR; ++ } ++ ++ status = cr_om_parser_parse_file (parser, a_file_path, ++ a_enc, a_result); ++ if (parser) { ++ cr_om_parser_destroy (parser); ++ parser = NULL; ++ } ++ ++ return status; ++} ++ ++/** ++ * cr_om_parser_parse_paths_to_cascade: ++ *@a_this: the current instance of #CROMParser ++ *@a_author_path: the path to the author stylesheet ++ *@a_user_path: the path to the user stylesheet ++ *@a_ua_path: the path to the User Agent stylesheet ++ *@a_encoding: the encoding of the sheets. ++ *@a_result: out parameter. The resulting cascade if the parsing ++ *was okay ++ * ++ *Parses three sheets located by their paths and build a cascade ++ * ++ *Returns CR_OK upon successful completion, an error code otherwise ++ */ ++enum CRStatus ++cr_om_parser_parse_paths_to_cascade (CROMParser * a_this, ++ const guchar * a_author_path, ++ const guchar * a_user_path, ++ const guchar * a_ua_path, ++ enum CREncoding a_encoding, ++ CRCascade ** a_result) ++{ ++ enum CRStatus status = CR_OK; ++ ++ /*0->author sheet, 1->user sheet, 2->UA sheet */ ++ CRStyleSheet *sheets[3]; ++ guchar *paths[3]; ++ CRCascade *result = NULL; ++ gint i = 0; ++ ++ g_return_val_if_fail (a_this, CR_BAD_PARAM_ERROR); ++ ++ memset (sheets, 0, sizeof (CRStyleSheet*) * 3); ++ paths[0] = (guchar *) a_author_path; ++ paths[1] = (guchar *) a_user_path; ++ paths[2] = (guchar *) a_ua_path; ++ ++ for (i = 0; i < 3; i++) { ++ status = cr_om_parser_parse_file (a_this, paths[i], ++ a_encoding, &sheets[i]); ++ if (status != CR_OK) { ++ if (sheets[i]) { ++ cr_stylesheet_unref (sheets[i]); ++ sheets[i] = NULL; ++ } ++ continue; ++ } ++ } ++ result = cr_cascade_new (sheets[0], sheets[1], sheets[2]); ++ if (!result) { ++ for (i = 0; i < 3; i++) { ++ cr_stylesheet_unref (sheets[i]); ++ sheets[i] = 0; ++ } ++ return CR_ERROR; ++ } ++ *a_result = result; ++ return CR_OK; ++} ++ ++/** ++ * cr_om_parser_simply_parse_paths_to_cascade: ++ *@a_author_path: the path to the author stylesheet ++ *@a_user_path: the path to the user stylesheet ++ *@a_ua_path: the path to the User Agent stylesheet ++ *@a_encoding: the encoding of the sheets. ++ *@a_result: out parameter. The resulting cascade if the parsing ++ *was okay ++ * ++ *Parses three sheets located by their paths and build a cascade ++ * ++ *Returns CR_OK upon successful completion, an error code otherwise ++ */ ++enum CRStatus ++cr_om_parser_simply_parse_paths_to_cascade (const guchar * a_author_path, ++ const guchar * a_user_path, ++ const guchar * a_ua_path, ++ enum CREncoding a_encoding, ++ CRCascade ** a_result) ++{ ++ enum CRStatus status = CR_OK; ++ CROMParser *parser = NULL; ++ ++ parser = cr_om_parser_new (NULL); ++ if (!parser) { ++ cr_utils_trace_info ("could not allocated om parser"); ++ cr_utils_trace_info ("System may be out of memory"); ++ return CR_ERROR; ++ } ++ status = cr_om_parser_parse_paths_to_cascade (parser, ++ a_author_path, ++ a_user_path, ++ a_ua_path, ++ a_encoding, a_result); ++ if (parser) { ++ cr_om_parser_destroy (parser); ++ parser = NULL; ++ } ++ return status; ++} ++ ++/** ++ * cr_om_parser_destroy: ++ *@a_this: the current instance of #CROMParser. ++ * ++ *Destructor of the #CROMParser. ++ */ ++void ++cr_om_parser_destroy (CROMParser * a_this) ++{ ++ g_return_if_fail (a_this && PRIVATE (a_this)); ++ ++ if (PRIVATE (a_this)->parser) { ++ cr_parser_destroy (PRIVATE (a_this)->parser); ++ PRIVATE (a_this)->parser = NULL; ++ } ++ ++ if (PRIVATE (a_this)) { ++ g_free (PRIVATE (a_this)); ++ PRIVATE (a_this) = NULL; ++ } ++ ++ if (a_this) { ++ g_free (a_this); ++ a_this = NULL; ++ } ++} +diff --git a/src/st/croco/cr-om-parser.h b/src/st/croco/cr-om-parser.h +new file mode 100644 +index 000000000..13d35b1cd +--- /dev/null ++++ b/src/st/croco/cr-om-parser.h +@@ -0,0 +1,98 @@ ++/* -*- Mode: C; indent-tabs-mode:nil; c-basic-offset: 8-*- */ ++ ++/* ++ * This file is part of The Croco Library ++ * ++ * Copyright (C) 2002-2003 Dodji Seketeli ++ * ++ * 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 ++ */ ++ ++/* ++ *$Id$ ++ */ ++ ++#ifndef __CR_OM_PARSER_H__ ++#define __CR_OM_PARSER_H__ ++ ++#include "cr-parser.h" ++#include "cr-cascade.h" ++ ++ ++/** ++ *@file ++ *The definition of the CSS Object Model Parser. ++ *This parser uses (and sits) the SAC api of libcroco defined ++ *in cr-parser.h and cr-doc-handler.h ++ */ ++ ++G_BEGIN_DECLS ++ ++typedef struct _CROMParser CROMParser ; ++typedef struct _CROMParserPriv CROMParserPriv ; ++ ++/** ++ *The Object model parser. ++ *Can parse a css file and build a css object model. ++ *This parser uses an instance of #CRParser and defines ++ *a set of SAC callbacks to build the Object Model. ++ */ ++struct _CROMParser ++{ ++ CROMParserPriv *priv ; ++} ; ++ ++CROMParser * cr_om_parser_new (CRInput *a_input) ; ++ ++ ++enum CRStatus cr_om_parser_simply_parse_file (const guchar *a_file_path, ++ enum CREncoding a_enc, ++ CRStyleSheet **a_result) ; ++ ++enum CRStatus cr_om_parser_parse_file (CROMParser *a_this, ++ const guchar *a_file_uri, ++ enum CREncoding a_enc, ++ CRStyleSheet **a_result) ; ++ ++enum CRStatus cr_om_parser_simply_parse_buf (const guchar *a_buf, ++ gulong a_len, ++ enum CREncoding a_enc, ++ CRStyleSheet **a_result) ; ++ ++enum CRStatus cr_om_parser_parse_buf (CROMParser *a_this, ++ const guchar *a_buf, ++ gulong a_len, ++ enum CREncoding a_enc, ++ CRStyleSheet **a_result) ; ++ ++enum CRStatus cr_om_parser_parse_paths_to_cascade (CROMParser *a_this, ++ const guchar *a_author_path, ++ const guchar *a_user_path, ++ const guchar *a_ua_path, ++ enum CREncoding a_encoding, ++ CRCascade ** a_result) ; ++ ++enum CRStatus cr_om_parser_simply_parse_paths_to_cascade (const guchar *a_author_path, ++ const guchar *a_user_path, ++ const guchar *a_ua_path, ++ enum CREncoding a_encoding, ++ CRCascade ** a_result) ; ++ ++void cr_om_parser_destroy (CROMParser *a_this) ; ++ ++G_END_DECLS ++ ++#endif /*__CR_OM_PARSER_H__*/ +diff --git a/src/st/croco/cr-parser.c b/src/st/croco/cr-parser.c +new file mode 100644 +index 000000000..07f4ed9e8 +--- /dev/null ++++ b/src/st/croco/cr-parser.c +@@ -0,0 +1,4525 @@ ++/* -*- Mode: C; indent-tabs-mode:nil; c-basic-offset: 8-*- */ ++ ++/* ++ * This file is part of The Croco Library ++ * ++ * ++ * 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 ++ * See COPYRIGHTS file for copyrights information. ++ */ ++ ++/** ++ *@CRParser: ++ * ++ *The definition of the #CRParser class. ++ */ ++ ++#include "string.h" ++#include "cr-parser.h" ++#include "cr-num.h" ++#include "cr-term.h" ++#include "cr-simple-sel.h" ++#include "cr-attr-sel.h" ++ ++/* ++ *Random notes: ++ *CSS core syntax vs CSS level 2 syntax ++ *===================================== ++ * ++ *One must keep in mind ++ *that css UA must comply with two syntaxes. ++ * ++ *1/the specific syntax that defines the css language ++ *for a given level of specificatin (e.g css2 syntax ++ *defined in appendix D.1 of the css2 spec) ++ * ++ *2/the core (general) syntax that is there to allow ++ *UAs to parse style sheets written in levels of CSS that ++ *didn't exist at the time the UAs were created. ++ * ++ *the name of parsing functions (or methods) contained in this file ++ *follows the following scheme: cr_parser_parse_ (...) ; ++ *where is the name ++ *of a production of the css2 language. ++ *When a given production is ++ *defined by the css2 level grammar *and* by the ++ *css core syntax, there will be two functions to parse that production: ++ *one will parse the production defined by the css2 level grammar and the ++ *other will parse the production defined by the css core grammar. ++ *The css2 level grammar related parsing function will be called: ++ *cr_parser_parse_ (...) ; ++ *Then css core grammar related parsing function will be called: ++ *cr_parser_parse__core (...) ; ++ * ++ *If a production is defined only by the css core grammar, then ++ *it will be named: ++ *cr_parser_parse__core (...) ; ++ */ ++ ++typedef struct _CRParserError CRParserError; ++ ++/** ++ *An abstraction of an error reported by by the ++ *parsing routines. ++ */ ++struct _CRParserError { ++ guchar *msg; ++ enum CRStatus status; ++ glong line; ++ glong column; ++ glong byte_num; ++}; ++ ++enum CRParserState { ++ READY_STATE = 0, ++ TRY_PARSE_CHARSET_STATE, ++ CHARSET_PARSED_STATE, ++ TRY_PARSE_IMPORT_STATE, ++ IMPORT_PARSED_STATE, ++ TRY_PARSE_RULESET_STATE, ++ RULESET_PARSED_STATE, ++ TRY_PARSE_MEDIA_STATE, ++ MEDIA_PARSED_STATE, ++ TRY_PARSE_PAGE_STATE, ++ PAGE_PARSED_STATE, ++ TRY_PARSE_FONT_FACE_STATE, ++ FONT_FACE_PARSED_STATE ++} ; ++ ++/** ++ *The private attributes of ++ *#CRParser. ++ */ ++struct _CRParserPriv { ++ /** ++ *The tokenizer ++ */ ++ CRTknzr *tknzr; ++ ++ /** ++ *The sac handlers to call ++ *to notify the parsing of ++ *the css2 constructions. ++ */ ++ CRDocHandler *sac_handler; ++ ++ /** ++ *A stack of errors reported ++ *by the parsing routines. ++ *Contains instance of #CRParserError. ++ *This pointer is the top of the stack. ++ */ ++ GList *err_stack; ++ ++ enum CRParserState state; ++ gboolean resolve_import; ++ gboolean is_case_sensitive; ++ gboolean use_core_grammar; ++}; ++ ++#define PRIVATE(obj) ((obj)->priv) ++ ++#define CHARS_TAB_SIZE 12 ++ ++/** ++ * IS_NUM: ++ *@a_char: the char to test. ++ *return TRUE if the character is a number ([0-9]), FALSE otherwise ++ */ ++#define IS_NUM(a_char) (((a_char) >= '0' && (a_char) <= '9')?TRUE:FALSE) ++ ++/** ++ *Checks if 'status' equals CR_OK. If not, goto the 'error' label. ++ * ++ *@param status the status (of type enum CRStatus) to test. ++ *@param is_exception if set to FALSE, the final status returned ++ *by the current function will be CR_PARSING_ERROR. If set to TRUE, the ++ *current status will be the current value of the 'status' variable. ++ * ++ */ ++#define CHECK_PARSING_STATUS(status, is_exception) \ ++if ((status) != CR_OK) \ ++{ \ ++ if (is_exception == FALSE) \ ++ { \ ++ status = CR_PARSING_ERROR ; \ ++ } \ ++ goto error ; \ ++} ++ ++/** ++ * CHECK_PARSING_STATUS_ERR: ++ *@a_this: the current instance of #CRParser . ++ *@a_status: the status to check. Is of type enum #CRStatus. ++ *@a_is_exception: in case of error, if is TRUE, the status ++ *is set to CR_PARSING_ERROR before goto error. If is false, the ++ *real low level status is kept and will be returned by the ++ *upper level function that called this macro. Usally,this must ++ *be set to FALSE. ++ * ++ *same as CHECK_PARSING_STATUS() but this one pushes an error ++ *on the parser error stack when an error arises. ++ * ++ */ ++#define CHECK_PARSING_STATUS_ERR(a_this, a_status, a_is_exception,\ ++ a_err_msg, a_err_status) \ ++if ((a_status) != CR_OK) \ ++{ \ ++ if (a_is_exception == FALSE) a_status = CR_PARSING_ERROR ; \ ++ cr_parser_push_error (a_this, a_err_msg, a_err_status) ; \ ++ goto error ; \ ++} ++ ++/** ++ *Peeks the next char from the input stream of the current parser ++ *by invoking cr_tknzr_input_peek_char(). ++ *invokes CHECK_PARSING_STATUS on the status returned by ++ *cr_tknzr_peek_char(). ++ * ++ *@param a_this the current instance of #CRParser. ++ *@param a_to_char a pointer to the char where to store the ++ *char peeked. ++ */ ++#define PEEK_NEXT_CHAR(a_this, a_to_char) \ ++{\ ++status = cr_tknzr_peek_char (PRIVATE (a_this)->tknzr, a_to_char) ; \ ++CHECK_PARSING_STATUS (status, TRUE) \ ++} ++ ++/** ++ *Reads the next char from the input stream of the current parser. ++ *In case of error, jumps to the "error:" label located in the ++ *function where this macro is called. ++ *@param a_this the curent instance of #CRParser ++ *@param to_char a pointer to the guint32 char where to store ++ *the character read. ++ */ ++#define READ_NEXT_CHAR(a_this, a_to_char) \ ++status = cr_tknzr_read_char (PRIVATE (a_this)->tknzr, a_to_char) ; \ ++CHECK_PARSING_STATUS (status, TRUE) ++ ++/** ++ *Gets information about the current position in ++ *the input of the parser. ++ *In case of failure, this macro returns from the ++ *calling function and ++ *returns a status code of type enum #CRStatus. ++ *@param a_this the current instance of #CRParser. ++ *@param a_pos out parameter. A pointer to the position ++ *inside the current parser input. Must ++ */ ++#define RECORD_INITIAL_POS(a_this, a_pos) \ ++status = cr_tknzr_get_cur_pos (PRIVATE \ ++(a_this)->tknzr, a_pos) ; \ ++g_return_val_if_fail (status == CR_OK, status) ++ ++/** ++ *Gets the address of the current byte inside the ++ *parser input. ++ *@param parser the current instance of #CRParser. ++ *@param addr out parameter a pointer (guchar*) ++ *to where the address must be put. ++ */ ++#define RECORD_CUR_BYTE_ADDR(a_this, a_addr) \ ++status = cr_tknzr_get_cur_byte_addr \ ++ (PRIVATE (a_this)->tknzr, a_addr) ; \ ++CHECK_PARSING_STATUS (status, TRUE) ++ ++/** ++ *Peeks a byte from the topmost parser input at ++ *a given offset from the current position. ++ *If it fails, goto the "error:" label. ++ * ++ *@param a_parser the current instance of #CRParser. ++ *@param a_offset the offset of the byte to peek, the ++ *current byte having the offset '0'. ++ *@param a_byte_ptr out parameter a pointer (guchar*) to ++ *where the peeked char is to be stored. ++ */ ++#define PEEK_BYTE(a_parser, a_offset, a_byte_ptr) \ ++status = cr_tknzr_peek_byte (PRIVATE (a_this)->tknzr, \ ++ a_offset, \ ++ a_byte_ptr) ; \ ++CHECK_PARSING_STATUS (status, TRUE) ; ++ ++#define BYTE(a_parser, a_offset, a_eof) \ ++cr_tknzr_peek_byte2 (PRIVATE (a_this)->tknzr, a_offset, a_eof) ++ ++/** ++ *Reads a byte from the topmost parser input ++ *steam. ++ *If it fails, goto the "error" label. ++ *@param a_this the current instance of #CRParser. ++ *@param a_byte_ptr the guchar * where to put the read char. ++ */ ++#define READ_NEXT_BYTE(a_this, a_byte_ptr) \ ++status = cr_tknzr_read_byte (PRIVATE (a_this)->tknzr, a_byte_ptr) ; \ ++CHECK_PARSING_STATUS (status, TRUE) ; ++ ++/** ++ *Skips a given number of byte in the topmost ++ *parser input. Don't update line and column number. ++ *In case of error, jumps to the "error:" label ++ *of the surrounding function. ++ *@param a_parser the current instance of #CRParser. ++ *@param a_nb_bytes the number of bytes to skip. ++ */ ++#define SKIP_BYTES(a_this, a_nb_bytes) \ ++status = cr_tknzr_seek_index (PRIVATE (a_this)->tknzr, \ ++ CR_SEEK_CUR, a_nb_bytes) ; \ ++CHECK_PARSING_STATUS (status, TRUE) ; ++ ++/** ++ *Skip utf8 encoded characters. ++ *Updates line and column numbers. ++ *@param a_parser the current instance of #CRParser. ++ *@param a_nb_chars the number of chars to skip. Must be of ++ *type glong. ++ */ ++#define SKIP_CHARS(a_parser, a_nb_chars) \ ++{ \ ++glong nb_chars = a_nb_chars ; \ ++status = cr_tknzr_consume_chars \ ++ (PRIVATE (a_parser)->tknzr,0, &nb_chars) ; \ ++CHECK_PARSING_STATUS (status, TRUE) ; \ ++} ++ ++/** ++ *Tests the condition and if it is false, sets ++ *status to "CR_PARSING_ERROR" and goto the 'error' ++ *label. ++ *@param condition the condition to test. ++ */ ++#define ENSURE_PARSING_COND(condition) \ ++if (! (condition)) {status = CR_PARSING_ERROR; goto error ;} ++ ++#define ENSURE_PARSING_COND_ERR(a_this, a_condition, \ ++ a_err_msg, a_err_status) \ ++if (! (a_condition)) \ ++{ \ ++ status = CR_PARSING_ERROR; \ ++ cr_parser_push_error (a_this, a_err_msg, a_err_status) ; \ ++ goto error ; \ ++} ++ ++#define GET_NEXT_TOKEN(a_this, a_token_ptr) \ ++status = cr_tknzr_get_next_token (PRIVATE (a_this)->tknzr, \ ++ a_token_ptr) ; \ ++ENSURE_PARSING_COND (status == CR_OK) ; ++ ++#ifdef WITH_UNICODE_ESCAPE_AND_RANGE ++static enum CRStatus cr_parser_parse_unicode_escape (CRParser * a_this, ++ guint32 * a_unicode); ++static enum CRStatus cr_parser_parse_escape (CRParser * a_this, ++ guint32 * a_esc_code); ++ ++static enum CRStatus cr_parser_parse_unicode_range (CRParser * a_this, ++ CRString ** a_inf, ++ CRString ** a_sup); ++#endif ++ ++static enum CRStatus cr_parser_parse_stylesheet_core (CRParser * a_this); ++ ++static enum CRStatus cr_parser_parse_atrule_core (CRParser * a_this); ++ ++static enum CRStatus cr_parser_parse_ruleset_core (CRParser * a_this); ++ ++static enum CRStatus cr_parser_parse_selector_core (CRParser * a_this); ++ ++static enum CRStatus cr_parser_parse_declaration_core (CRParser * a_this); ++ ++static enum CRStatus cr_parser_parse_any_core (CRParser * a_this); ++ ++static enum CRStatus cr_parser_parse_block_core (CRParser * a_this); ++ ++static enum CRStatus cr_parser_parse_value_core (CRParser * a_this); ++ ++static enum CRStatus cr_parser_parse_string (CRParser * a_this, ++ CRString ** a_str); ++ ++static enum CRStatus cr_parser_parse_ident (CRParser * a_this, ++ CRString ** a_str); ++ ++static enum CRStatus cr_parser_parse_uri (CRParser * a_this, ++ CRString ** a_str); ++ ++static enum CRStatus cr_parser_parse_function (CRParser * a_this, ++ CRString ** a_func_name, ++ CRTerm ** a_expr); ++static enum CRStatus cr_parser_parse_property (CRParser * a_this, ++ CRString ** a_property); ++ ++static enum CRStatus cr_parser_parse_attribute_selector (CRParser * a_this, ++ CRAttrSel ** a_sel); ++ ++static enum CRStatus cr_parser_parse_simple_selector (CRParser * a_this, ++ CRSimpleSel ** a_sel); ++ ++static enum CRStatus cr_parser_parse_simple_sels (CRParser * a_this, ++ CRSimpleSel ** a_sel); ++ ++static CRParserError *cr_parser_error_new (const guchar * a_msg, ++ enum CRStatus); ++ ++static void cr_parser_error_set_msg (CRParserError * a_this, ++ const guchar * a_msg); ++ ++static void cr_parser_error_dump (CRParserError * a_this); ++ ++static void cr_parser_error_set_status (CRParserError * a_this, ++ enum CRStatus a_status); ++ ++static void cr_parser_error_set_pos (CRParserError * a_this, ++ glong a_line, ++ glong a_column, glong a_byte_num); ++static void ++ cr_parser_error_destroy (CRParserError * a_this); ++ ++static enum CRStatus cr_parser_push_error (CRParser * a_this, ++ const guchar * a_msg, ++ enum CRStatus a_status); ++ ++static enum CRStatus cr_parser_dump_err_stack (CRParser * a_this, ++ gboolean a_clear_errs); ++static enum CRStatus ++ cr_parser_clear_errors (CRParser * a_this); ++ ++/***************************** ++ *error managemet methods ++ *****************************/ ++ ++/** ++ *Constructor of #CRParserError class. ++ *@param a_msg the brute error message. ++ *@param a_status the error status. ++ *@return the newly built instance of #CRParserError. ++ */ ++static CRParserError * ++cr_parser_error_new (const guchar * a_msg, enum CRStatus a_status) ++{ ++ CRParserError *result = NULL; ++ ++ result = g_try_malloc (sizeof (CRParserError)); ++ ++ if (result == NULL) { ++ cr_utils_trace_info ("Out of memory"); ++ return NULL; ++ } ++ ++ memset (result, 0, sizeof (CRParserError)); ++ ++ cr_parser_error_set_msg (result, a_msg); ++ cr_parser_error_set_status (result, a_status); ++ ++ return result; ++} ++ ++/** ++ *Sets the message associated to this instance of #CRError. ++ *@param a_this the current instance of #CRParserError. ++ *@param a_msg the new message. ++ */ ++static void ++cr_parser_error_set_msg (CRParserError * a_this, const guchar * a_msg) ++{ ++ g_return_if_fail (a_this); ++ ++ if (a_this->msg) { ++ g_free (a_this->msg); ++ } ++ ++ a_this->msg = (guchar *) g_strdup ((const gchar *) a_msg); ++} ++ ++/** ++ *Sets the error status. ++ *@param a_this the current instance of #CRParserError. ++ *@param a_status the new error status. ++ * ++ */ ++static void ++cr_parser_error_set_status (CRParserError * a_this, enum CRStatus a_status) ++{ ++ g_return_if_fail (a_this); ++ ++ a_this->status = a_status; ++} ++ ++/** ++ *Sets the position of the parser error. ++ *@param a_this the current instance of #CRParserError. ++ *@param a_line the line number. ++ *@param a_column the column number. ++ *@param a_byte_num the byte number. ++ */ ++static void ++cr_parser_error_set_pos (CRParserError * a_this, ++ glong a_line, glong a_column, glong a_byte_num) ++{ ++ g_return_if_fail (a_this); ++ ++ a_this->line = a_line; ++ a_this->column = a_column; ++ a_this->byte_num = a_byte_num; ++} ++ ++static void ++cr_parser_error_dump (CRParserError * a_this) ++{ ++ g_return_if_fail (a_this); ++ ++ g_printerr ("parsing error: %ld:%ld:", a_this->line, a_this->column); ++ ++ g_printerr ("%s\n", a_this->msg); ++} ++ ++/** ++ *The destructor of #CRParserError. ++ *@param a_this the current instance of #CRParserError. ++ */ ++static void ++cr_parser_error_destroy (CRParserError * a_this) ++{ ++ g_return_if_fail (a_this); ++ ++ if (a_this->msg) { ++ g_free (a_this->msg); ++ a_this->msg = NULL; ++ } ++ ++ g_free (a_this); ++} ++ ++/** ++ *Pushes an error on the parser error stack. ++ *@param a_this the current instance of #CRParser. ++ *@param a_msg the error message. ++ *@param a_status the error status. ++ *@return CR_OK upon successfull completion, an error code otherwise. ++ */ ++static enum CRStatus ++cr_parser_push_error (CRParser * a_this, ++ const guchar * a_msg, enum CRStatus a_status) ++{ ++ enum CRStatus status = CR_OK; ++ ++ CRParserError *error = NULL; ++ CRInputPos pos; ++ ++ g_return_val_if_fail (a_this && PRIVATE (a_this) ++ && a_msg, CR_BAD_PARAM_ERROR); ++ ++ error = cr_parser_error_new (a_msg, a_status); ++ ++ g_return_val_if_fail (error, CR_ERROR); ++ ++ RECORD_INITIAL_POS (a_this, &pos); ++ ++ cr_parser_error_set_pos ++ (error, pos.line, pos.col, pos.next_byte_index - 1); ++ ++ PRIVATE (a_this)->err_stack = ++ g_list_prepend (PRIVATE (a_this)->err_stack, error); ++ ++ if (PRIVATE (a_this)->err_stack == NULL) ++ goto error; ++ ++ return CR_OK; ++ ++ error: ++ ++ if (error) { ++ cr_parser_error_destroy (error); ++ error = NULL; ++ } ++ ++ return status; ++} ++ ++/** ++ *Dumps the error stack on stdout. ++ *@param a_this the current instance of #CRParser. ++ *@param a_clear_errs whether to clear the error stack ++ *after the dump or not. ++ *@return CR_OK upon successfull completion, an error code ++ *otherwise. ++ */ ++static enum CRStatus ++cr_parser_dump_err_stack (CRParser * a_this, gboolean a_clear_errs) ++{ ++ GList *cur = NULL; ++ ++ g_return_val_if_fail (a_this && PRIVATE (a_this), CR_BAD_PARAM_ERROR); ++ ++ if (PRIVATE (a_this)->err_stack == NULL) ++ return CR_OK; ++ ++ for (cur = PRIVATE (a_this)->err_stack; cur; cur = cur->next) { ++ cr_parser_error_dump ((CRParserError *) cur->data); ++ } ++ ++ if (a_clear_errs == TRUE) { ++ cr_parser_clear_errors (a_this); ++ } ++ ++ return CR_OK; ++} ++ ++/** ++ *Clears all the errors contained in the parser error stack. ++ *Frees all the errors, and the stack that contains'em. ++ *@param a_this the current instance of #CRParser. ++ */ ++static enum CRStatus ++cr_parser_clear_errors (CRParser * a_this) ++{ ++ GList *cur = NULL; ++ ++ g_return_val_if_fail (a_this && PRIVATE (a_this), CR_BAD_PARAM_ERROR); ++ ++ for (cur = PRIVATE (a_this)->err_stack; cur; cur = cur->next) { ++ if (cur->data) { ++ cr_parser_error_destroy ((CRParserError *) ++ cur->data); ++ } ++ } ++ ++ if (PRIVATE (a_this)->err_stack) { ++ g_list_free (PRIVATE (a_this)->err_stack); ++ PRIVATE (a_this)->err_stack = NULL; ++ } ++ ++ return CR_OK; ++} ++ ++/** ++ * cr_parser_try_to_skip_spaces_and_comments: ++ *@a_this: the current instance of #CRParser. ++ * ++ *Same as cr_parser_try_to_skip_spaces() but this one skips ++ *spaces and comments. ++ * ++ *Returns CR_OK upon successfull completion, an error code otherwise. ++ */ ++enum CRStatus ++cr_parser_try_to_skip_spaces_and_comments (CRParser * a_this) ++{ ++ enum CRStatus status = CR_ERROR; ++ CRToken *token = NULL; ++ ++ g_return_val_if_fail (a_this && PRIVATE (a_this) ++ && PRIVATE (a_this)->tknzr, CR_BAD_PARAM_ERROR); ++ do { ++ if (token) { ++ cr_token_destroy (token); ++ token = NULL; ++ } ++ ++ status = cr_tknzr_get_next_token (PRIVATE (a_this)->tknzr, ++ &token); ++ if (status != CR_OK) ++ goto error; ++ } ++ while ((token != NULL) ++ && (token->type == COMMENT_TK || token->type == S_TK)); ++ ++ cr_tknzr_unget_token (PRIVATE (a_this)->tknzr, token); ++ ++ return status; ++ ++ error: ++ ++ if (token) { ++ cr_token_destroy (token); ++ token = NULL; ++ } ++ ++ return status; ++} ++ ++/*************************************** ++ *End of Parser input handling routines ++ ***************************************/ ++ ++ ++/************************************* ++ *Non trivial terminal productions ++ *parsing routines ++ *************************************/ ++ ++/** ++ *Parses a css stylesheet following the core css grammar. ++ *This is mainly done for test purposes. ++ *During the parsing, no callback is called. This is just ++ *to validate that the stylesheet is well formed according to the ++ *css core syntax. ++ *stylesheet : [ CDO | CDC | S | statement ]*; ++ *@param a_this the current instance of #CRParser. ++ *@return CR_OK upon successful completion, an error code otherwise. ++ */ ++static enum CRStatus ++cr_parser_parse_stylesheet_core (CRParser * a_this) ++{ ++ CRToken *token = NULL; ++ CRInputPos init_pos; ++ enum CRStatus status = CR_ERROR; ++ ++ g_return_val_if_fail (a_this && PRIVATE (a_this), CR_BAD_PARAM_ERROR); ++ ++ RECORD_INITIAL_POS (a_this, &init_pos); ++ ++ continue_parsing: ++ ++ if (token) { ++ cr_token_destroy (token); ++ token = NULL; ++ } ++ ++ cr_parser_try_to_skip_spaces_and_comments (a_this); ++ status = cr_tknzr_get_next_token (PRIVATE (a_this)->tknzr, &token); ++ if (status == CR_END_OF_INPUT_ERROR) { ++ status = CR_OK; ++ goto done; ++ } else if (status != CR_OK) { ++ goto error; ++ } ++ ++ switch (token->type) { ++ ++ case CDO_TK: ++ case CDC_TK: ++ goto continue_parsing; ++ break; ++ default: ++ status = cr_tknzr_unget_token (PRIVATE (a_this)->tknzr, ++ token); ++ CHECK_PARSING_STATUS (status, TRUE); ++ token = NULL; ++ status = cr_parser_parse_statement_core (a_this); ++ cr_parser_clear_errors (a_this); ++ if (status == CR_OK) { ++ goto continue_parsing; ++ } else if (status == CR_END_OF_INPUT_ERROR) { ++ goto done; ++ } else { ++ goto error; ++ } ++ } ++ ++ done: ++ if (token) { ++ cr_token_destroy (token); ++ token = NULL; ++ } ++ ++ cr_parser_clear_errors (a_this); ++ return CR_OK; ++ ++ error: ++ cr_parser_push_error ++ (a_this, (const guchar *) "could not recognize next production", CR_ERROR); ++ ++ cr_parser_dump_err_stack (a_this, TRUE); ++ ++ if (token) { ++ cr_token_destroy (token); ++ token = NULL; ++ } ++ ++ cr_tknzr_set_cur_pos (PRIVATE (a_this)->tknzr, &init_pos); ++ ++ return status; ++} ++ ++/** ++ *Parses an at-rule as defined by the css core grammar ++ *in chapter 4.1 in the css2 spec. ++ *at-rule : ATKEYWORD S* any* [ block | ';' S* ]; ++ *@param a_this the current instance of #CRParser. ++ *@return CR_OK upon successfull completion, an error code ++ *otherwise. ++ */ ++static enum CRStatus ++cr_parser_parse_atrule_core (CRParser * a_this) ++{ ++ CRToken *token = NULL; ++ CRInputPos init_pos; ++ enum CRStatus status = CR_ERROR; ++ ++ g_return_val_if_fail (a_this && PRIVATE (a_this), CR_BAD_PARAM_ERROR); ++ ++ RECORD_INITIAL_POS (a_this, &init_pos); ++ ++ status = cr_tknzr_get_next_token (PRIVATE (a_this)->tknzr, ++ &token); ++ ENSURE_PARSING_COND (status == CR_OK ++ && token ++ && ++ (token->type == ATKEYWORD_TK ++ || token->type == IMPORT_SYM_TK ++ || token->type == PAGE_SYM_TK ++ || token->type == MEDIA_SYM_TK ++ || token->type == FONT_FACE_SYM_TK ++ || token->type == CHARSET_SYM_TK)); ++ ++ cr_token_destroy (token); ++ token = NULL; ++ ++ cr_parser_try_to_skip_spaces_and_comments (a_this); ++ ++ do { ++ status = cr_parser_parse_any_core (a_this); ++ } while (status == CR_OK); ++ ++ status = cr_tknzr_get_next_token (PRIVATE (a_this)->tknzr, ++ &token); ++ ENSURE_PARSING_COND (status == CR_OK && token); ++ ++ if (token->type == CBO_TK) { ++ cr_tknzr_unget_token (PRIVATE (a_this)->tknzr, ++ token); ++ token = NULL; ++ status = cr_parser_parse_block_core (a_this); ++ CHECK_PARSING_STATUS (status, ++ FALSE); ++ goto done; ++ } else if (token->type == SEMICOLON_TK) { ++ goto done; ++ } else { ++ status = CR_PARSING_ERROR ; ++ goto error; ++ } ++ ++ done: ++ if (token) { ++ cr_token_destroy (token); ++ token = NULL; ++ } ++ return CR_OK; ++ ++ error: ++ if (token) { ++ cr_token_destroy (token); ++ token = NULL; ++ } ++ cr_tknzr_set_cur_pos (PRIVATE (a_this)->tknzr, ++ &init_pos); ++ return status; ++} ++ ++/** ++ *Parses a ruleset as defined by the css core grammar in chapter ++ *4.1 of the css2 spec. ++ *ruleset ::= selector? '{' S* declaration? [ ';' S* declaration? ]* '}' S*; ++ *@param a_this the current instance of #CRParser. ++ *@return CR_OK upon successfull completion, an error code otherwise. ++ */ ++static enum CRStatus ++cr_parser_parse_ruleset_core (CRParser * a_this) ++{ ++ CRToken *token = NULL; ++ CRInputPos init_pos; ++ enum CRStatus status = CR_ERROR; ++ ++ g_return_val_if_fail (a_this && PRIVATE (a_this), CR_BAD_PARAM_ERROR); ++ RECORD_INITIAL_POS (a_this, &init_pos); ++ ++ status = cr_parser_parse_selector_core (a_this); ++ ++ ENSURE_PARSING_COND (status == CR_OK ++ || status == CR_PARSING_ERROR ++ || status == CR_END_OF_INPUT_ERROR); ++ ++ status = cr_tknzr_get_next_token (PRIVATE (a_this)->tknzr, &token); ++ ENSURE_PARSING_COND (status == CR_OK && token ++ && token->type == CBO_TK); ++ cr_token_destroy (token); ++ token = NULL; ++ ++ cr_parser_try_to_skip_spaces_and_comments (a_this); ++ status = cr_parser_parse_declaration_core (a_this); ++ ++ parse_declaration_list: ++ if (token) { ++ cr_token_destroy (token); ++ token = NULL; ++ } ++ ++ status = cr_tknzr_get_next_token (PRIVATE (a_this)->tknzr, &token); ++ ENSURE_PARSING_COND (status == CR_OK && token); ++ if (token->type == CBC_TK) { ++ goto done; ++ } ++ ++ ENSURE_PARSING_COND (status == CR_OK ++ && token && token->type == SEMICOLON_TK); ++ ++ cr_token_destroy (token); ++ token = NULL; ++ cr_parser_try_to_skip_spaces_and_comments (a_this); ++ status = cr_parser_parse_declaration_core (a_this); ++ cr_parser_clear_errors (a_this); ++ ENSURE_PARSING_COND (status == CR_OK || status == CR_PARSING_ERROR); ++ status = cr_tknzr_get_next_token (PRIVATE (a_this)->tknzr, &token); ++ ENSURE_PARSING_COND (status == CR_OK && token); ++ if (token->type == CBC_TK) { ++ cr_token_destroy (token); ++ token = NULL; ++ cr_parser_try_to_skip_spaces_and_comments (a_this); ++ goto done; ++ } else { ++ status = cr_tknzr_unget_token (PRIVATE (a_this)->tknzr, ++ token); ++ token = NULL; ++ goto parse_declaration_list; ++ } ++ ++ done: ++ if (token) { ++ cr_token_destroy (token); ++ token = NULL; ++ } ++ ++ if (status == CR_OK) { ++ return CR_OK; ++ } ++ ++ error: ++ if (token) { ++ cr_token_destroy (token); ++ token = NULL; ++ } ++ ++ cr_tknzr_set_cur_pos (PRIVATE (a_this)->tknzr, &init_pos); ++ ++ return status; ++} ++ ++/** ++ *Parses a "selector" as specified by the css core ++ *grammar. ++ *selector : any+; ++ *@param a_this the current instance of #CRParser. ++ *@return CR_OK upon successfull completion, an error code ++ *otherwise. ++ */ ++static enum CRStatus ++cr_parser_parse_selector_core (CRParser * a_this) ++{ ++ CRToken *token = NULL; ++ CRInputPos init_pos; ++ enum CRStatus status = CR_ERROR; ++ ++ g_return_val_if_fail (a_this && PRIVATE (a_this), CR_BAD_PARAM_ERROR); ++ ++ RECORD_INITIAL_POS (a_this, &init_pos); ++ ++ status = cr_parser_parse_any_core (a_this); ++ CHECK_PARSING_STATUS (status, FALSE); ++ ++ do { ++ status = cr_parser_parse_any_core (a_this); ++ ++ } while (status == CR_OK); ++ ++ return CR_OK; ++ ++ error: ++ if (token) { ++ cr_token_destroy (token); ++ token = NULL; ++ } ++ ++ cr_tknzr_set_cur_pos (PRIVATE (a_this)->tknzr, &init_pos); ++ ++ return status; ++} ++ ++/** ++ *Parses a "block" as defined in the css core grammar ++ *in chapter 4.1 of the css2 spec. ++ *block ::= '{' S* [ any | block | ATKEYWORD S* | ';' ]* '}' S*; ++ *@param a_this the current instance of #CRParser. ++ *FIXME: code this function. ++ */ ++static enum CRStatus ++cr_parser_parse_block_core (CRParser * a_this) ++{ ++ CRToken *token = NULL; ++ CRInputPos init_pos; ++ enum CRStatus status = CR_ERROR; ++ ++ g_return_val_if_fail (a_this && PRIVATE (a_this), CR_BAD_PARAM_ERROR); ++ ++ RECORD_INITIAL_POS (a_this, &init_pos); ++ ++ status = cr_tknzr_get_next_token (PRIVATE (a_this)->tknzr, &token); ++ ENSURE_PARSING_COND (status == CR_OK && token ++ && token->type == CBO_TK); ++ ++ parse_block_content: ++ ++ if (token) { ++ cr_token_destroy (token); ++ token = NULL; ++ } ++ ++ cr_parser_try_to_skip_spaces_and_comments (a_this); ++ ++ status = cr_tknzr_get_next_token (PRIVATE (a_this)->tknzr, &token); ++ ENSURE_PARSING_COND (status == CR_OK && token); ++ ++ if (token->type == CBC_TK) { ++ cr_parser_try_to_skip_spaces_and_comments (a_this); ++ goto done; ++ } else if (token->type == SEMICOLON_TK) { ++ goto parse_block_content; ++ } else if (token->type == ATKEYWORD_TK) { ++ cr_parser_try_to_skip_spaces_and_comments (a_this); ++ goto parse_block_content; ++ } else if (token->type == CBO_TK) { ++ cr_tknzr_unget_token (PRIVATE (a_this)->tknzr, token); ++ token = NULL; ++ status = cr_parser_parse_block_core (a_this); ++ CHECK_PARSING_STATUS (status, FALSE); ++ goto parse_block_content; ++ } else { ++ cr_tknzr_unget_token (PRIVATE (a_this)->tknzr, token); ++ token = NULL; ++ status = cr_parser_parse_any_core (a_this); ++ CHECK_PARSING_STATUS (status, FALSE); ++ goto parse_block_content; ++ } ++ ++ done: ++ if (token) { ++ cr_token_destroy (token); ++ token = NULL; ++ } ++ ++ if (status == CR_OK) ++ return CR_OK; ++ ++ error: ++ if (token) { ++ cr_token_destroy (token); ++ token = NULL; ++ } ++ ++ cr_tknzr_set_cur_pos (PRIVATE (a_this)->tknzr, &init_pos); ++ ++ return status; ++} ++ ++static enum CRStatus ++cr_parser_parse_declaration_core (CRParser * a_this) ++{ ++ CRToken *token = NULL; ++ CRInputPos init_pos; ++ enum CRStatus status = CR_ERROR; ++ CRString *prop = NULL; ++ ++ g_return_val_if_fail (a_this && PRIVATE (a_this), CR_BAD_PARAM_ERROR); ++ ++ RECORD_INITIAL_POS (a_this, &init_pos); ++ ++ status = cr_parser_parse_property (a_this, &prop); ++ CHECK_PARSING_STATUS (status, FALSE); ++ cr_parser_clear_errors (a_this); ++ ENSURE_PARSING_COND (status == CR_OK && prop); ++ cr_string_destroy (prop); ++ prop = NULL; ++ ++ status = cr_tknzr_get_next_token (PRIVATE (a_this)->tknzr, &token); ++ ENSURE_PARSING_COND (status == CR_OK ++ && token ++ && token->type == DELIM_TK ++ && token->u.unichar == ':'); ++ cr_token_destroy (token); ++ token = NULL; ++ cr_parser_try_to_skip_spaces_and_comments (a_this); ++ status = cr_parser_parse_value_core (a_this); ++ CHECK_PARSING_STATUS (status, FALSE); ++ ++ return CR_OK; ++ ++ error: ++ ++ if (prop) { ++ cr_string_destroy (prop); ++ prop = NULL; ++ } ++ ++ if (token) { ++ cr_token_destroy (token); ++ token = NULL; ++ } ++ ++ cr_tknzr_set_cur_pos (PRIVATE (a_this)->tknzr, &init_pos); ++ ++ return status; ++} ++ ++/** ++ *Parses a "value" production as defined by the css core grammar ++ *in chapter 4.1. ++ *value ::= [ any | block | ATKEYWORD S* ]+; ++ *@param a_this the current instance of #CRParser. ++ *@return CR_OK upon successfull completion, an error code otherwise. ++ */ ++static enum CRStatus ++cr_parser_parse_value_core (CRParser * a_this) ++{ ++ CRToken *token = NULL; ++ CRInputPos init_pos; ++ enum CRStatus status = CR_ERROR; ++ glong ref = 0; ++ ++ g_return_val_if_fail (a_this && PRIVATE (a_this), CR_BAD_PARAM_ERROR); ++ RECORD_INITIAL_POS (a_this, &init_pos); ++ ++ continue_parsing: ++ ++ if (token) { ++ cr_token_destroy (token); ++ token = NULL; ++ } ++ ++ status = cr_tknzr_get_next_token (PRIVATE (a_this)->tknzr, &token); ++ ENSURE_PARSING_COND (status == CR_OK && token); ++ ++ switch (token->type) { ++ case CBO_TK: ++ status = cr_tknzr_unget_token (PRIVATE (a_this)->tknzr, ++ token); ++ token = NULL; ++ status = cr_parser_parse_block_core (a_this); ++ CHECK_PARSING_STATUS (status, FALSE); ++ ref++; ++ goto continue_parsing; ++ ++ case ATKEYWORD_TK: ++ cr_parser_try_to_skip_spaces_and_comments (a_this); ++ ref++; ++ goto continue_parsing; ++ ++ default: ++ status = cr_tknzr_unget_token (PRIVATE (a_this)->tknzr, ++ token); ++ token = NULL; ++ status = cr_parser_parse_any_core (a_this); ++ if (status == CR_OK) { ++ ref++; ++ goto continue_parsing; ++ } else if (status == CR_PARSING_ERROR) { ++ status = CR_OK; ++ goto done; ++ } else { ++ goto error; ++ } ++ } ++ ++ done: ++ if (token) { ++ cr_token_destroy (token); ++ token = NULL; ++ } ++ ++ if (status == CR_OK && ref) ++ return CR_OK; ++ error: ++ if (token) { ++ cr_token_destroy (token); ++ token = NULL; ++ } ++ ++ cr_tknzr_set_cur_pos (PRIVATE (a_this)->tknzr, &init_pos); ++ ++ return status; ++} ++ ++/** ++ *Parses an "any" as defined by the css core grammar in the ++ *css2 spec in chapter 4.1. ++ *any ::= [ IDENT | NUMBER | PERCENTAGE | DIMENSION | STRING ++ * | DELIM | URI | HASH | UNICODE-RANGE | INCLUDES ++ * | FUNCTION | DASHMATCH | '(' any* ')' | '[' any* ']' ] S*; ++ * ++ *@param a_this the current instance of #CRParser. ++ *@return CR_OK upon successfull completion, an error code otherwise. ++ */ ++static enum CRStatus ++cr_parser_parse_any_core (CRParser * a_this) ++{ ++ CRToken *token1 = NULL, ++ *token2 = NULL; ++ CRInputPos init_pos; ++ enum CRStatus status = CR_ERROR; ++ ++ g_return_val_if_fail (a_this, CR_BAD_PARAM_ERROR); ++ ++ RECORD_INITIAL_POS (a_this, &init_pos); ++ ++ status = cr_tknzr_get_next_token (PRIVATE (a_this)->tknzr, &token1); ++ ++ ENSURE_PARSING_COND (status == CR_OK && token1); ++ ++ switch (token1->type) { ++ case IDENT_TK: ++ case NUMBER_TK: ++ case RGB_TK: ++ case PERCENTAGE_TK: ++ case DIMEN_TK: ++ case EMS_TK: ++ case EXS_TK: ++ case LENGTH_TK: ++ case ANGLE_TK: ++ case FREQ_TK: ++ case TIME_TK: ++ case STRING_TK: ++ case DELIM_TK: ++ case URI_TK: ++ case HASH_TK: ++ case UNICODERANGE_TK: ++ case INCLUDES_TK: ++ case DASHMATCH_TK: ++ case S_TK: ++ case COMMENT_TK: ++ case IMPORTANT_SYM_TK: ++ status = CR_OK; ++ break; ++ case FUNCTION_TK: ++ /* ++ *this case isn't specified by the spec but it ++ *does happen. So we have to handle it. ++ *We must consider function with parameters. ++ *We consider parameter as being an "any*" production. ++ */ ++ do { ++ status = cr_parser_parse_any_core (a_this); ++ } while (status == CR_OK); ++ ++ ENSURE_PARSING_COND (status == CR_PARSING_ERROR); ++ status = cr_tknzr_get_next_token (PRIVATE (a_this)->tknzr, ++ &token2); ++ ENSURE_PARSING_COND (status == CR_OK ++ && token2 && token2->type == PC_TK); ++ break; ++ case PO_TK: ++ status = cr_tknzr_get_next_token (PRIVATE (a_this)->tknzr, ++ &token2); ++ ENSURE_PARSING_COND (status == CR_OK && token2); ++ ++ if (token2->type == PC_TK) { ++ cr_token_destroy (token2); ++ token2 = NULL; ++ goto done; ++ } else { ++ status = cr_tknzr_unget_token ++ (PRIVATE (a_this)->tknzr, token2); ++ token2 = NULL; ++ } ++ ++ do { ++ status = cr_parser_parse_any_core (a_this); ++ } while (status == CR_OK); ++ ++ ENSURE_PARSING_COND (status == CR_PARSING_ERROR); ++ ++ status = cr_tknzr_get_next_token (PRIVATE (a_this)->tknzr, ++ &token2); ++ ENSURE_PARSING_COND (status == CR_OK ++ && token2 && token2->type == PC_TK); ++ status = CR_OK; ++ break; ++ ++ case BO_TK: ++ status = cr_tknzr_get_next_token (PRIVATE (a_this)->tknzr, ++ &token2); ++ ENSURE_PARSING_COND (status == CR_OK && token2); ++ ++ if (token2->type == BC_TK) { ++ cr_token_destroy (token2); ++ token2 = NULL; ++ goto done; ++ } else { ++ status = cr_tknzr_unget_token ++ (PRIVATE (a_this)->tknzr, token2); ++ token2 = NULL; ++ } ++ ++ do { ++ status = cr_parser_parse_any_core (a_this); ++ } while (status == CR_OK); ++ ++ ENSURE_PARSING_COND (status == CR_PARSING_ERROR); ++ ++ status = cr_tknzr_get_next_token (PRIVATE (a_this)->tknzr, ++ &token2); ++ ENSURE_PARSING_COND (status == CR_OK ++ && token2 && token2->type == BC_TK); ++ status = CR_OK; ++ break; ++ default: ++ status = CR_PARSING_ERROR; ++ goto error; ++ } ++ ++ done: ++ if (token1) { ++ cr_token_destroy (token1); ++ token1 = NULL; ++ } ++ ++ if (token2) { ++ cr_token_destroy (token2); ++ token2 = NULL; ++ } ++ ++ return CR_OK; ++ ++ error: ++ ++ if (token1) { ++ cr_token_destroy (token1); ++ token1 = NULL; ++ } ++ ++ if (token2) { ++ cr_token_destroy (token2); ++ token2 = NULL; ++ } ++ ++ cr_tknzr_set_cur_pos (PRIVATE (a_this)->tknzr, &init_pos); ++ return status; ++} ++ ++/** ++ *Parses an attribute selector as defined in the css2 spec in ++ *appendix D.1: ++ *attrib ::= '[' S* IDENT S* [ [ '=' | INCLUDES | DASHMATCH ] S* ++ * [ IDENT | STRING ] S* ]? ']' ++ * ++ *@param a_this the "this pointer" of the current instance of ++ *#CRParser . ++ *@param a_sel out parameter. The successfully parsed attribute selector. ++ *@return CR_OK upon successfull completion, an error code otherwise. ++ */ ++static enum CRStatus ++cr_parser_parse_attribute_selector (CRParser * a_this, ++ CRAttrSel ** a_sel) ++{ ++ enum CRStatus status = CR_OK; ++ CRInputPos init_pos; ++ CRToken *token = NULL; ++ CRAttrSel *result = NULL; ++ CRParsingLocation location = {0} ; ++ ++ g_return_val_if_fail (a_this && a_sel, CR_BAD_PARAM_ERROR); ++ ++ RECORD_INITIAL_POS (a_this, &init_pos); ++ ++ status = cr_tknzr_get_next_token (PRIVATE (a_this)->tknzr, &token); ++ ENSURE_PARSING_COND (status == CR_OK && token ++ && token->type == BO_TK); ++ cr_parsing_location_copy ++ (&location, &token->location) ; ++ cr_token_destroy (token); ++ token = NULL; ++ ++ cr_parser_try_to_skip_spaces_and_comments (a_this); ++ ++ result = cr_attr_sel_new (); ++ if (!result) { ++ cr_utils_trace_info ("result failed") ; ++ status = CR_OUT_OF_MEMORY_ERROR ; ++ goto error ; ++ } ++ cr_parsing_location_copy (&result->location, ++ &location) ; ++ status = cr_tknzr_get_next_token (PRIVATE (a_this)->tknzr, &token); ++ ENSURE_PARSING_COND (status == CR_OK ++ && token && token->type == IDENT_TK); ++ ++ result->name = token->u.str; ++ token->u.str = NULL; ++ cr_token_destroy (token); ++ token = NULL; ++ ++ cr_parser_try_to_skip_spaces_and_comments (a_this); ++ ++ status = cr_tknzr_get_next_token (PRIVATE (a_this)->tknzr, &token); ++ ENSURE_PARSING_COND (status == CR_OK && token); ++ ++ if (token->type == INCLUDES_TK) { ++ result->match_way = INCLUDES; ++ goto parse_right_part; ++ } else if (token->type == DASHMATCH_TK) { ++ result->match_way = DASHMATCH; ++ goto parse_right_part; ++ } else if (token->type == DELIM_TK && token->u.unichar == '=') { ++ result->match_way = EQUALS; ++ goto parse_right_part; ++ } else if (token->type == BC_TK) { ++ result->match_way = SET; ++ goto done; ++ } ++ ++ parse_right_part: ++ ++ if (token) { ++ cr_token_destroy (token); ++ token = NULL; ++ } ++ ++ cr_parser_try_to_skip_spaces_and_comments (a_this); ++ ++ status = cr_tknzr_get_next_token (PRIVATE (a_this)->tknzr, &token); ++ ENSURE_PARSING_COND (status == CR_OK && token); ++ ++ if (token->type == IDENT_TK) { ++ result->value = token->u.str; ++ token->u.str = NULL; ++ } else if (token->type == STRING_TK) { ++ result->value = token->u.str; ++ token->u.str = NULL; ++ } else { ++ status = CR_PARSING_ERROR; ++ goto error; ++ } ++ ++ if (token) { ++ cr_token_destroy (token); ++ token = NULL; ++ } ++ ++ cr_parser_try_to_skip_spaces_and_comments (a_this); ++ ++ status = cr_tknzr_get_next_token (PRIVATE (a_this)->tknzr, &token); ++ ++ ENSURE_PARSING_COND (status == CR_OK && token ++ && token->type == BC_TK); ++ done: ++ if (token) { ++ cr_token_destroy (token); ++ token = NULL; ++ } ++ ++ if (*a_sel) { ++ status = cr_attr_sel_append_attr_sel (*a_sel, result); ++ CHECK_PARSING_STATUS (status, FALSE); ++ } else { ++ *a_sel = result; ++ } ++ ++ cr_parser_clear_errors (a_this); ++ return CR_OK; ++ ++ error: ++ ++ if (result) { ++ cr_attr_sel_destroy (result); ++ result = NULL; ++ } ++ ++ if (token) { ++ cr_token_destroy (token); ++ token = NULL; ++ } ++ ++ cr_tknzr_set_cur_pos (PRIVATE (a_this)->tknzr, &init_pos); ++ ++ return status; ++} ++ ++/** ++ *Parses a "property" as specified by the css2 spec at [4.1.1]: ++ *property : IDENT S*; ++ * ++ *@param a_this the "this pointer" of the current instance of #CRParser. ++ *@param GString a_property out parameter. The parsed property without the ++ *trailing spaces. If *a_property is NULL, this function allocates a ++ *new instance of GString and set it content to the parsed property. ++ *If not, the property is just appended to a_property's previous content. ++ *In both cases, it is up to the caller to free a_property. ++ *@return CR_OK upon successfull completion, CR_PARSING_ERROR if the ++ *next construction was not a "property", or an error code. ++ */ ++static enum CRStatus ++cr_parser_parse_property (CRParser * a_this, ++ CRString ** a_property) ++{ ++ enum CRStatus status = CR_OK; ++ CRInputPos init_pos; ++ ++ g_return_val_if_fail (a_this && PRIVATE (a_this) ++ && PRIVATE (a_this)->tknzr ++ && a_property, ++ CR_BAD_PARAM_ERROR); ++ ++ RECORD_INITIAL_POS (a_this, &init_pos); ++ ++ status = cr_parser_parse_ident (a_this, a_property); ++ CHECK_PARSING_STATUS (status, TRUE); ++ ++ cr_parser_try_to_skip_spaces_and_comments (a_this); ++ ++ cr_parser_clear_errors (a_this); ++ return CR_OK; ++ ++ error: ++ ++ cr_tknzr_set_cur_pos (PRIVATE (a_this)->tknzr, &init_pos); ++ ++ return status; ++} ++ ++/** ++ * cr_parser_parse_term: ++ *@a_term: out parameter. The successfully parsed term. ++ * ++ *Parses a "term" as defined in the css2 spec, appendix D.1: ++ *term ::= unary_operator? [NUMBER S* | PERCENTAGE S* | LENGTH S* | ++ *EMS S* | EXS S* | ANGLE S* | TIME S* | FREQ S* | function ] | ++ *STRING S* | IDENT S* | URI S* | RGB S* | UNICODERANGE S* | hexcolor ++ * ++ *TODO: handle parsing of 'RGB' ++ * ++ *Returns CR_OK upon successfull completion, an error code otherwise. ++ */ ++enum CRStatus ++cr_parser_parse_term (CRParser * a_this, CRTerm ** a_term) ++{ ++ enum CRStatus status = CR_PARSING_ERROR; ++ CRInputPos init_pos; ++ CRTerm *result = NULL; ++ CRTerm *param = NULL; ++ CRToken *token = NULL; ++ CRString *func_name = NULL; ++ CRParsingLocation location = {0} ; ++ ++ g_return_val_if_fail (a_this && a_term, CR_BAD_PARAM_ERROR); ++ ++ RECORD_INITIAL_POS (a_this, &init_pos); ++ ++ result = cr_term_new (); ++ ++ status = cr_tknzr_get_next_token (PRIVATE (a_this)->tknzr, ++ &token); ++ if (status != CR_OK || !token) ++ goto error; ++ ++ cr_parsing_location_copy (&location, &token->location) ; ++ if (token->type == DELIM_TK && token->u.unichar == '+') { ++ result->unary_op = PLUS_UOP; ++ cr_token_destroy (token) ; ++ token = NULL ; ++ cr_parser_try_to_skip_spaces_and_comments (a_this); ++ status = cr_tknzr_get_next_token (PRIVATE (a_this)->tknzr, ++ &token); ++ if (status != CR_OK || !token) ++ goto error; ++ } else if (token->type == DELIM_TK && token->u.unichar == '-') { ++ result->unary_op = MINUS_UOP; ++ cr_token_destroy (token) ; ++ token = NULL ; ++ cr_parser_try_to_skip_spaces_and_comments (a_this); ++ status = cr_tknzr_get_next_token (PRIVATE (a_this)->tknzr, ++ &token); ++ if (status != CR_OK || !token) ++ goto error; ++ } ++ ++ if (token->type == EMS_TK ++ || token->type == EXS_TK ++ || token->type == LENGTH_TK ++ || token->type == ANGLE_TK ++ || token->type == TIME_TK ++ || token->type == FREQ_TK ++ || token->type == PERCENTAGE_TK ++ || token->type == NUMBER_TK) { ++ status = cr_term_set_number (result, token->u.num); ++ CHECK_PARSING_STATUS (status, TRUE); ++ token->u.num = NULL; ++ status = CR_OK; ++ } else if (token && token->type == FUNCTION_TK) { ++ status = cr_tknzr_unget_token (PRIVATE (a_this)->tknzr, ++ token); ++ token = NULL; ++ status = cr_parser_parse_function (a_this, &func_name, ++ ¶m); ++ ++ if (status == CR_OK) { ++ status = cr_term_set_function (result, ++ func_name, ++ param); ++ CHECK_PARSING_STATUS (status, TRUE); ++ } ++ } else if (token && token->type == STRING_TK) { ++ status = cr_term_set_string (result, ++ token->u.str); ++ CHECK_PARSING_STATUS (status, TRUE); ++ token->u.str = NULL; ++ } else if (token && token->type == IDENT_TK) { ++ status = cr_term_set_ident (result, token->u.str); ++ CHECK_PARSING_STATUS (status, TRUE); ++ token->u.str = NULL; ++ } else if (token && token->type == URI_TK) { ++ status = cr_term_set_uri (result, token->u.str); ++ CHECK_PARSING_STATUS (status, TRUE); ++ token->u.str = NULL; ++ } else if (token && token->type == RGB_TK) { ++ status = cr_term_set_rgb (result, token->u.rgb); ++ CHECK_PARSING_STATUS (status, TRUE); ++ token->u.rgb = NULL; ++ } else if (token && token->type == UNICODERANGE_TK) { ++ result->type = TERM_UNICODERANGE; ++ status = CR_PARSING_ERROR; ++ } else if (token && token->type == HASH_TK) { ++ status = cr_term_set_hash (result, token->u.str); ++ CHECK_PARSING_STATUS (status, TRUE); ++ token->u.str = NULL; ++ } else { ++ status = CR_PARSING_ERROR; ++ } ++ ++ if (status != CR_OK) { ++ goto error; ++ } ++ cr_parsing_location_copy (&result->location, ++ &location) ; ++ *a_term = cr_term_append_term (*a_term, result); ++ ++ result = NULL; ++ ++ cr_parser_try_to_skip_spaces_and_comments (a_this); ++ ++ if (token) { ++ cr_token_destroy (token); ++ token = NULL; ++ } ++ ++ cr_parser_clear_errors (a_this); ++ return CR_OK; ++ ++ error: ++ ++ if (result) { ++ cr_term_destroy (result); ++ result = NULL; ++ } ++ ++ if (token) { ++ cr_token_destroy (token); ++ token = NULL; ++ } ++ ++ if (param) { ++ cr_term_destroy (param); ++ param = NULL; ++ } ++ ++ if (func_name) { ++ cr_string_destroy (func_name); ++ func_name = NULL; ++ } ++ ++ cr_tknzr_set_cur_pos (PRIVATE (a_this)->tknzr, &init_pos); ++ ++ return status; ++} ++ ++/** ++ * cr_parser_parse_simple_selector: ++ *@a_this: the "this pointer" of the current instance of #CRParser. ++ *@a_sel: out parameter. Is set to the successfully parsed simple ++ *selector. ++ * ++ *Parses a "simple_selector" as defined by the css2 spec in appendix D.1 : ++ *element_name? [ HASH | class | attrib | pseudo ]* S* ++ *and where pseudo is: ++ *pseudo ::= ':' [ IDENT | FUNCTION S* IDENT S* ')' ] ++ * ++ *Returns CR_OK upon successfull completion, an error code otherwise. ++ */ ++static enum CRStatus ++cr_parser_parse_simple_selector (CRParser * a_this, CRSimpleSel ** a_sel) ++{ ++ enum CRStatus status = CR_ERROR; ++ CRInputPos init_pos; ++ CRToken *token = NULL; ++ CRSimpleSel *sel = NULL; ++ CRAdditionalSel *add_sel_list = NULL; ++ gboolean found_sel = FALSE; ++ guint32 cur_char = 0; ++ ++ g_return_val_if_fail (a_this && a_sel, CR_BAD_PARAM_ERROR); ++ ++ RECORD_INITIAL_POS (a_this, &init_pos); ++ ++ status = cr_tknzr_get_next_token (PRIVATE (a_this)->tknzr, &token); ++ if (status != CR_OK) ++ goto error; ++ ++ sel = cr_simple_sel_new (); ++ ENSURE_PARSING_COND (sel); ++ ++ cr_parsing_location_copy ++ (&sel->location, ++ &token->location) ; ++ ++ if (token && token->type == DELIM_TK ++ && token->u.unichar == '*') { ++ sel->type_mask |= UNIVERSAL_SELECTOR; ++ sel->name = cr_string_new_from_string ("*"); ++ found_sel = TRUE; ++ } else if (token && token->type == IDENT_TK) { ++ sel->name = token->u.str; ++ sel->type_mask |= TYPE_SELECTOR; ++ token->u.str = NULL; ++ found_sel = TRUE; ++ } else { ++ status = cr_tknzr_unget_token ++ (PRIVATE (a_this)->tknzr, ++ token); ++ token = NULL; ++ } ++ ++ if (token) { ++ cr_token_destroy (token); ++ token = NULL; ++ } ++ ++ cr_parser_try_to_skip_spaces_and_comments (a_this); ++ ++ for (;;) { ++ if (token) { ++ cr_token_destroy (token); ++ token = NULL; ++ } ++ ++ status = cr_tknzr_get_next_token ++ (PRIVATE (a_this)->tknzr, ++ &token); ++ if (status != CR_OK) ++ goto error; ++ ++ if (token && token->type == HASH_TK) { ++ /*we parsed an attribute id */ ++ CRAdditionalSel *add_sel = NULL; ++ ++ add_sel = cr_additional_sel_new_with_type ++ (ID_ADD_SELECTOR); ++ ++ add_sel->content.id_name = token->u.str; ++ token->u.str = NULL; ++ ++ cr_parsing_location_copy ++ (&add_sel->location, ++ &token->location) ; ++ add_sel_list = ++ cr_additional_sel_append ++ (add_sel_list, add_sel); ++ found_sel = TRUE; ++ } else if (token && (token->type == DELIM_TK) ++ && (token->u.unichar == '.')) { ++ cr_token_destroy (token); ++ token = NULL; ++ ++ status = cr_tknzr_get_next_token ++ (PRIVATE (a_this)->tknzr, &token); ++ if (status != CR_OK) ++ goto error; ++ ++ if (token && token->type == IDENT_TK) { ++ CRAdditionalSel *add_sel = NULL; ++ ++ add_sel = cr_additional_sel_new_with_type ++ (CLASS_ADD_SELECTOR); ++ ++ add_sel->content.class_name = token->u.str; ++ token->u.str = NULL; ++ ++ add_sel_list = ++ cr_additional_sel_append ++ (add_sel_list, add_sel); ++ found_sel = TRUE; ++ ++ cr_parsing_location_copy ++ (&add_sel->location, ++ & token->location) ; ++ } else { ++ status = CR_PARSING_ERROR; ++ goto error; ++ } ++ } else if (token && token->type == BO_TK) { ++ CRAttrSel *attr_sel = NULL; ++ CRAdditionalSel *add_sel = NULL; ++ ++ status = cr_tknzr_unget_token ++ (PRIVATE (a_this)->tknzr, token); ++ if (status != CR_OK) ++ goto error; ++ token = NULL; ++ ++ status = cr_parser_parse_attribute_selector ++ (a_this, &attr_sel); ++ CHECK_PARSING_STATUS (status, FALSE); ++ ++ add_sel = cr_additional_sel_new_with_type ++ (ATTRIBUTE_ADD_SELECTOR); ++ ++ ENSURE_PARSING_COND (add_sel != NULL); ++ ++ add_sel->content.attr_sel = attr_sel; ++ ++ add_sel_list = ++ cr_additional_sel_append ++ (add_sel_list, add_sel); ++ found_sel = TRUE; ++ cr_parsing_location_copy ++ (&add_sel->location, ++ &attr_sel->location) ; ++ } else if (token && (token->type == DELIM_TK) ++ && (token->u.unichar == ':')) { ++ CRPseudo *pseudo = NULL; ++ ++ /*try to parse a pseudo */ ++ ++ if (token) { ++ cr_token_destroy (token); ++ token = NULL; ++ } ++ ++ pseudo = cr_pseudo_new (); ++ ++ status = cr_tknzr_get_next_token ++ (PRIVATE (a_this)->tknzr, &token); ++ ENSURE_PARSING_COND (status == CR_OK && token); ++ ++ cr_parsing_location_copy ++ (&pseudo->location, ++ &token->location) ; ++ ++ if (token->type == IDENT_TK) { ++ pseudo->type = IDENT_PSEUDO; ++ pseudo->name = token->u.str; ++ token->u.str = NULL; ++ found_sel = TRUE; ++ } else if (token->type == FUNCTION_TK) { ++ pseudo->name = token->u.str; ++ token->u.str = NULL; ++ cr_parser_try_to_skip_spaces_and_comments ++ (a_this); ++ status = cr_parser_parse_ident ++ (a_this, &pseudo->extra); ++ ++ ENSURE_PARSING_COND (status == CR_OK); ++ READ_NEXT_CHAR (a_this, &cur_char); ++ ENSURE_PARSING_COND (cur_char == ')'); ++ pseudo->type = FUNCTION_PSEUDO; ++ found_sel = TRUE; ++ } else { ++ status = CR_PARSING_ERROR; ++ goto error; ++ } ++ ++ if (status == CR_OK) { ++ CRAdditionalSel *add_sel = NULL; ++ ++ add_sel = cr_additional_sel_new_with_type ++ (PSEUDO_CLASS_ADD_SELECTOR); ++ ++ add_sel->content.pseudo = pseudo; ++ cr_parsing_location_copy ++ (&add_sel->location, ++ &pseudo->location) ; ++ add_sel_list = ++ cr_additional_sel_append ++ (add_sel_list, add_sel); ++ status = CR_OK; ++ } ++ } else { ++ status = cr_tknzr_unget_token ++ (PRIVATE (a_this)->tknzr, token); ++ token = NULL; ++ break; ++ } ++ } ++ ++ if (status == CR_OK && found_sel == TRUE) { ++ cr_parser_try_to_skip_spaces_and_comments (a_this); ++ ++ sel->add_sel = add_sel_list; ++ add_sel_list = NULL; ++ ++ if (*a_sel == NULL) { ++ *a_sel = sel; ++ } else { ++ cr_simple_sel_append_simple_sel (*a_sel, sel); ++ } ++ ++ sel = NULL; ++ ++ if (token) { ++ cr_token_destroy (token); ++ token = NULL; ++ } ++ ++ cr_parser_clear_errors (a_this); ++ return CR_OK; ++ } else { ++ status = CR_PARSING_ERROR; ++ } ++ ++ error: ++ ++ if (token) { ++ cr_token_destroy (token); ++ token = NULL; ++ } ++ ++ if (add_sel_list) { ++ cr_additional_sel_destroy (add_sel_list); ++ add_sel_list = NULL; ++ } ++ ++ if (sel) { ++ cr_simple_sel_destroy (sel); ++ sel = NULL; ++ } ++ ++ cr_tknzr_set_cur_pos (PRIVATE (a_this)->tknzr, &init_pos); ++ ++ return status; ++ ++} ++ ++/** ++ * cr_parser_parse_simple_sels: ++ *@a_this: the this pointer of the current instance of #CRParser. ++ *@a_start: a pointer to the ++ *first chararcter of the successfully parsed ++ *string. ++ *@a_end: a pointer to the last character of the successfully parsed ++ *string. ++ * ++ *Parses a "selector" as defined by the css2 spec in appendix D.1: ++ *selector ::= simple_selector [ combinator simple_selector ]* ++ * ++ *Returns CR_OK upon successfull completion, an error code otherwise. ++ */ ++static enum CRStatus ++cr_parser_parse_simple_sels (CRParser * a_this, ++ CRSimpleSel ** a_sel) ++{ ++ enum CRStatus status = CR_ERROR; ++ CRInputPos init_pos; ++ CRSimpleSel *sel = NULL; ++ guint32 cur_char = 0; ++ ++ g_return_val_if_fail (a_this ++ && PRIVATE (a_this) ++ && a_sel, ++ CR_BAD_PARAM_ERROR); ++ ++ RECORD_INITIAL_POS (a_this, &init_pos); ++ ++ status = cr_parser_parse_simple_selector (a_this, &sel); ++ CHECK_PARSING_STATUS (status, FALSE); ++ ++ *a_sel = cr_simple_sel_append_simple_sel (*a_sel, sel); ++ ++ for (;;) { ++ guint32 next_char = 0; ++ enum Combinator comb = 0; ++ ++ sel = NULL; ++ ++ PEEK_NEXT_CHAR (a_this, &next_char); ++ ++ if (next_char == '+') { ++ READ_NEXT_CHAR (a_this, &cur_char); ++ comb = COMB_PLUS; ++ cr_parser_try_to_skip_spaces_and_comments (a_this); ++ } else if (next_char == '>') { ++ READ_NEXT_CHAR (a_this, &cur_char); ++ comb = COMB_GT; ++ cr_parser_try_to_skip_spaces_and_comments (a_this); ++ } else { ++ comb = COMB_WS; ++ } ++ ++ status = cr_parser_parse_simple_selector (a_this, &sel); ++ if (status != CR_OK) ++ break; ++ ++ if (comb && sel) { ++ sel->combinator = comb; ++ comb = 0; ++ } ++ if (sel) { ++ *a_sel = cr_simple_sel_append_simple_sel (*a_sel, ++ sel) ; ++ } ++ } ++ cr_parser_clear_errors (a_this); ++ return CR_OK; ++ ++ error: ++ ++ cr_tknzr_set_cur_pos (PRIVATE (a_this)->tknzr, &init_pos); ++ ++ return status; ++} ++ ++/** ++ * cr_parser_parse_selector: ++ *@a_this: the current instance of #CRParser. ++ *@a_selector: the parsed list of comma separated ++ *selectors. ++ * ++ *Parses a comma separated list of selectors. ++ * ++ *Returns CR_OK upon successful completion, an error ++ *code otherwise. ++ */ ++static enum CRStatus ++cr_parser_parse_selector (CRParser * a_this, ++ CRSelector ** a_selector) ++{ ++ enum CRStatus status = CR_OK; ++ CRInputPos init_pos; ++ guint32 cur_char = 0, ++ next_char = 0; ++ CRSimpleSel *simple_sels = NULL; ++ CRSelector *selector = NULL; ++ ++ g_return_val_if_fail (a_this && a_selector, CR_BAD_PARAM_ERROR); ++ ++ RECORD_INITIAL_POS (a_this, &init_pos); ++ ++ status = cr_parser_parse_simple_sels (a_this, &simple_sels); ++ CHECK_PARSING_STATUS (status, FALSE); ++ ++ if (simple_sels) { ++ selector = cr_selector_append_simple_sel ++ (selector, simple_sels); ++ if (selector) { ++ cr_parsing_location_copy ++ (&selector->location, ++ &simple_sels->location) ; ++ } ++ simple_sels = NULL; ++ } else { ++ status = CR_PARSING_ERROR ; ++ goto error ; ++ } ++ ++ status = cr_tknzr_peek_char (PRIVATE (a_this)->tknzr, ++ &next_char); ++ if (status != CR_OK) { ++ if (status == CR_END_OF_INPUT_ERROR) { ++ status = CR_OK; ++ goto okay; ++ } else { ++ goto error; ++ } ++ } ++ ++ if (next_char == ',') { ++ for (;;) { ++ simple_sels = NULL; ++ ++ status = cr_tknzr_peek_char (PRIVATE (a_this)->tknzr, ++ &next_char); ++ if (status != CR_OK) { ++ if (status == CR_END_OF_INPUT_ERROR) { ++ status = CR_OK; ++ break; ++ } else { ++ goto error; ++ } ++ } ++ ++ if (next_char != ',') ++ break; ++ ++ /*consume the ',' char */ ++ READ_NEXT_CHAR (a_this, &cur_char); ++ ++ cr_parser_try_to_skip_spaces_and_comments (a_this); ++ ++ status = cr_parser_parse_simple_sels ++ (a_this, &simple_sels); ++ ++ CHECK_PARSING_STATUS (status, FALSE); ++ ++ if (simple_sels) { ++ selector = ++ cr_selector_append_simple_sel ++ (selector, simple_sels); ++ ++ simple_sels = NULL; ++ } ++ } ++ } ++ ++ okay: ++ cr_parser_try_to_skip_spaces_and_comments (a_this); ++ ++ if (!*a_selector) { ++ *a_selector = selector; ++ } else { ++ *a_selector = cr_selector_append (*a_selector, selector); ++ } ++ ++ selector = NULL; ++ return CR_OK; ++ ++ error: ++ ++ if (simple_sels) { ++ cr_simple_sel_destroy (simple_sels); ++ simple_sels = NULL; ++ } ++ ++ if (selector) { ++ cr_selector_unref (selector); ++ selector = NULL; ++ } ++ ++ cr_tknzr_set_cur_pos (PRIVATE (a_this)->tknzr, &init_pos); ++ ++ return status; ++} ++ ++/** ++ * cr_parser_parse_function: ++ *@a_this: the "this pointer" of the current instance of #CRParser. ++ * ++ *@a_func_name: out parameter. The parsed function name ++ *@a_expr: out parameter. The successfully parsed term. ++ * ++ *Parses a "function" as defined in css spec at appendix D.1: ++ *function ::= FUNCTION S* expr ')' S* ++ *FUNCTION ::= ident'(' ++ * ++ *Returns CR_OK upon successfull completion, an error code otherwise. ++ */ ++static enum CRStatus ++cr_parser_parse_function (CRParser * a_this, ++ CRString ** a_func_name, ++ CRTerm ** a_expr) ++{ ++ CRInputPos init_pos; ++ enum CRStatus status = CR_OK; ++ CRToken *token = NULL; ++ CRTerm *expr = NULL; ++ ++ g_return_val_if_fail (a_this && PRIVATE (a_this) ++ && a_func_name, ++ CR_BAD_PARAM_ERROR); ++ ++ RECORD_INITIAL_POS (a_this, &init_pos); ++ ++ status = cr_tknzr_get_next_token (PRIVATE (a_this)->tknzr, &token); ++ if (status != CR_OK) ++ goto error; ++ ++ if (token && token->type == FUNCTION_TK) { ++ *a_func_name = token->u.str; ++ token->u.str = NULL; ++ } else { ++ status = CR_PARSING_ERROR; ++ goto error; ++ } ++ cr_token_destroy (token); ++ token = NULL; ++ ++ cr_parser_try_to_skip_spaces_and_comments (a_this) ; ++ ++ status = cr_parser_parse_expr (a_this, &expr); ++ ++ CHECK_PARSING_STATUS (status, FALSE); ++ ++ status = cr_tknzr_get_next_token (PRIVATE (a_this)->tknzr, &token); ++ if (status != CR_OK) ++ goto error; ++ ++ ENSURE_PARSING_COND (token && token->type == PC_TK); ++ ++ cr_token_destroy (token); ++ token = NULL; ++ ++ if (expr) { ++ *a_expr = cr_term_append_term (*a_expr, expr); ++ expr = NULL; ++ } ++ ++ cr_parser_clear_errors (a_this); ++ return CR_OK; ++ ++ error: ++ ++ if (*a_func_name) { ++ cr_string_destroy (*a_func_name); ++ *a_func_name = NULL; ++ } ++ ++ if (expr) { ++ cr_term_destroy (expr); ++ expr = NULL; ++ } ++ ++ if (token) { ++ cr_token_destroy (token); ++ ++ } ++ ++ cr_tknzr_set_cur_pos (PRIVATE (a_this)->tknzr, &init_pos); ++ ++ return status; ++} ++ ++/** ++ * cr_parser_parse_uri: ++ *@a_this: the current instance of #CRParser. ++ *@a_str: the successfully parsed url. ++ * ++ *Parses an uri as defined by the css spec [4.1.1]: ++ * URI ::= url\({w}{string}{w}\) ++ * |url\({w}([!#$%&*-~]|{nonascii}|{escape})*{w}\) ++ * ++ *Returns CR_OK upon successfull completion, an error code otherwise. ++ */ ++static enum CRStatus ++cr_parser_parse_uri (CRParser * a_this, CRString ** a_str) ++{ ++ ++ enum CRStatus status = CR_PARSING_ERROR; ++ ++ g_return_val_if_fail (a_this && PRIVATE (a_this) ++ && PRIVATE (a_this)->tknzr, CR_BAD_PARAM_ERROR); ++ ++ status = cr_tknzr_parse_token (PRIVATE (a_this)->tknzr, ++ URI_TK, NO_ET, a_str, NULL); ++ return status; ++} ++ ++/** ++ * cr_parser_parse_string: ++ *@a_this: the current instance of #CRParser. ++ *@a_start: out parameter. Upon successfull completion, ++ *points to the beginning of the string, points to an undefined value ++ *otherwise. ++ *@a_end: out parameter. Upon successfull completion, points to ++ *the beginning of the string, points to an undefined value otherwise. ++ * ++ *Parses a string type as defined in css spec [4.1.1]: ++ * ++ *string ::= {string1}|{string2} ++ *string1 ::= \"([\t !#$%&(-~]|\\{nl}|\'|{nonascii}|{escape})*\" ++ *string2 ::= \'([\t !#$%&(-~]|\\{nl}|\"|{nonascii}|{escape})*\' ++ * ++ *Returns CR_OK upon successfull completion, an error code otherwise. ++ */ ++static enum CRStatus ++cr_parser_parse_string (CRParser * a_this, CRString ** a_str) ++{ ++ enum CRStatus status = CR_OK; ++ ++ g_return_val_if_fail (a_this && PRIVATE (a_this) ++ && PRIVATE (a_this)->tknzr ++ && a_str, CR_BAD_PARAM_ERROR); ++ ++ status = cr_tknzr_parse_token (PRIVATE (a_this)->tknzr, ++ STRING_TK, NO_ET, a_str, NULL); ++ return status; ++} ++ ++/** ++ *Parses an "ident" as defined in css spec [4.1.1]: ++ *ident ::= {nmstart}{nmchar}* ++ * ++ *@param a_this the currens instance of #CRParser. ++ * ++ *@param a_str a pointer to parsed ident. If *a_str is NULL, ++ *this function allocates a new instance of #CRString. If not, ++ *the function just appends the parsed string to the one passed. ++ *In both cases it is up to the caller to free *a_str. ++ * ++ *@return CR_OK upon successfull completion, an error code ++ *otherwise. ++ */ ++static enum CRStatus ++cr_parser_parse_ident (CRParser * a_this, CRString ** a_str) ++{ ++ enum CRStatus status = CR_OK; ++ ++ g_return_val_if_fail (a_this && PRIVATE (a_this) ++ && PRIVATE (a_this)->tknzr ++ && a_str, CR_BAD_PARAM_ERROR); ++ ++ status = cr_tknzr_parse_token (PRIVATE (a_this)->tknzr, ++ IDENT_TK, NO_ET, a_str, NULL); ++ return status; ++} ++ ++/** ++ *the next rule is ignored as well. This seems to be a bug ++ *Parses a stylesheet as defined in the css2 spec in appendix D.1: ++ *stylesheet ::= [ CHARSET_SYM S* STRING S* ';' ]? ++ * [S|CDO|CDC]* [ import [S|CDO|CDC]* ]* ++ * [ [ ruleset | media | page | font_face ] [S|CDO|CDC]* ]* ++ * ++ *TODO: Finish the code of this function. Think about splitting it into ++ *smaller functions. ++ * ++ *@param a_this the "this pointer" of the current instance of #CRParser. ++ *@param a_start out parameter. A pointer to the first character of ++ *the successfully parsed string. ++ *@param a_end out parameter. A pointer to the first character of ++ *the successfully parsed string. ++ * ++ *@return CR_OK upon successfull completion, an error code otherwise. ++ */ ++static enum CRStatus ++cr_parser_parse_stylesheet (CRParser * a_this) ++{ ++ enum CRStatus status = CR_OK; ++ CRInputPos init_pos; ++ CRToken *token = NULL; ++ CRString *charset = NULL; ++ ++ g_return_val_if_fail (a_this && PRIVATE (a_this) ++ && PRIVATE (a_this)->tknzr, CR_BAD_PARAM_ERROR); ++ ++ RECORD_INITIAL_POS (a_this, &init_pos); ++ ++ PRIVATE (a_this)->state = READY_STATE; ++ ++ if (PRIVATE (a_this)->sac_handler ++ && PRIVATE (a_this)->sac_handler->start_document) { ++ PRIVATE (a_this)->sac_handler->start_document ++ (PRIVATE (a_this)->sac_handler); ++ } ++ ++ parse_charset: ++ status = cr_tknzr_get_next_token (PRIVATE (a_this)->tknzr, &token); ++ ++ if (status == CR_END_OF_INPUT_ERROR) ++ goto done; ++ CHECK_PARSING_STATUS (status, TRUE); ++ ++ if (token && token->type == CHARSET_SYM_TK) { ++ CRParsingLocation location = {0} ; ++ status = cr_tknzr_unget_token (PRIVATE (a_this)->tknzr, ++ token); ++ CHECK_PARSING_STATUS (status, TRUE); ++ token = NULL; ++ ++ status = cr_parser_parse_charset (a_this, ++ &charset, ++ &location); ++ ++ if (status == CR_OK && charset) { ++ if (PRIVATE (a_this)->sac_handler ++ && PRIVATE (a_this)->sac_handler->charset) { ++ PRIVATE (a_this)->sac_handler->charset ++ (PRIVATE (a_this)->sac_handler, ++ charset, &location); ++ } ++ } else if (status != CR_END_OF_INPUT_ERROR) { ++ status = cr_parser_parse_atrule_core (a_this); ++ CHECK_PARSING_STATUS (status, FALSE); ++ } ++ ++ if (charset) { ++ cr_string_destroy (charset); ++ charset = NULL; ++ } ++ } else if (token ++ && (token->type == S_TK ++ || token->type == COMMENT_TK)) { ++ status = cr_tknzr_unget_token (PRIVATE (a_this)->tknzr, ++ token); ++ token = NULL; ++ CHECK_PARSING_STATUS (status, TRUE); ++ ++ cr_parser_try_to_skip_spaces_and_comments (a_this); ++ goto parse_charset ; ++ } else if (token) { ++ status = cr_tknzr_unget_token (PRIVATE (a_this)->tknzr, ++ token); ++ token = NULL; ++ CHECK_PARSING_STATUS (status, TRUE); ++ } ++ ++/* parse_imports:*/ ++ do { ++ if (token) { ++ cr_token_destroy (token); ++ token = NULL; ++ } ++ cr_parser_try_to_skip_spaces_and_comments (a_this) ; ++ status = cr_tknzr_get_next_token ++ (PRIVATE (a_this)->tknzr, &token); ++ ++ if (status == CR_END_OF_INPUT_ERROR) ++ goto done; ++ CHECK_PARSING_STATUS (status, TRUE); ++ } while (token ++ && (token->type == S_TK ++ || token->type == CDO_TK || token->type == CDC_TK)); ++ ++ if (token) { ++ status = cr_tknzr_unget_token (PRIVATE (a_this)->tknzr, ++ token); ++ token = NULL; ++ } ++ ++ for (;;) { ++ status = cr_tknzr_get_next_token ++ (PRIVATE (a_this)->tknzr, &token); ++ if (status == CR_END_OF_INPUT_ERROR) ++ goto done; ++ CHECK_PARSING_STATUS (status, TRUE); ++ ++ if (token && token->type == IMPORT_SYM_TK) { ++ GList *media_list = NULL; ++ CRString *import_string = NULL; ++ CRParsingLocation location = {0} ; ++ ++ status = cr_tknzr_unget_token ++ (PRIVATE (a_this)->tknzr, token); ++ token = NULL; ++ CHECK_PARSING_STATUS (status, TRUE); ++ ++ status = cr_parser_parse_import (a_this, ++ &media_list, ++ &import_string, ++ &location); ++ if (status == CR_OK) { ++ if (import_string ++ && PRIVATE (a_this)->sac_handler ++ && PRIVATE (a_this)->sac_handler->import_style) { ++ PRIVATE (a_this)->sac_handler->import_style ++ (PRIVATE(a_this)->sac_handler, ++ media_list, ++ import_string, ++ NULL, &location) ; ++ ++ if ((PRIVATE (a_this)->sac_handler->resolve_import == TRUE)) { ++ /* ++ *TODO: resolve the ++ *import rule. ++ */ ++ } ++ ++ if ((PRIVATE (a_this)->sac_handler->import_style_result)) { ++ PRIVATE (a_this)->sac_handler->import_style_result ++ (PRIVATE (a_this)->sac_handler, ++ media_list, import_string, ++ NULL, NULL); ++ } ++ } ++ } else if (status != CR_END_OF_INPUT_ERROR) { ++ if (PRIVATE (a_this)->sac_handler ++ && PRIVATE (a_this)->sac_handler->error) { ++ PRIVATE (a_this)->sac_handler->error ++ (PRIVATE (a_this)->sac_handler); ++ } ++ status = cr_parser_parse_atrule_core (a_this); ++ CHECK_PARSING_STATUS (status, TRUE) ; ++ } else { ++ goto error ; ++ } ++ ++ /* ++ *then, after calling the appropriate ++ *SAC handler, free ++ *the media_list and import_string. ++ */ ++ if (media_list) { ++ GList *cur = NULL; ++ ++ /*free the medium list */ ++ for (cur = media_list; cur; cur = cur->next) { ++ if (cur->data) { ++ cr_string_destroy (cur->data); ++ } ++ } ++ ++ g_list_free (media_list); ++ media_list = NULL; ++ } ++ ++ if (import_string) { ++ cr_string_destroy (import_string); ++ import_string = NULL; ++ } ++ ++ cr_parser_try_to_skip_spaces_and_comments (a_this); ++ } else if (token ++ && (token->type == S_TK ++ || token->type == CDO_TK ++ || token->type == CDC_TK)) { ++ status = cr_tknzr_unget_token ++ (PRIVATE (a_this)->tknzr, token); ++ token = NULL; ++ ++ do { ++ if (token) { ++ cr_token_destroy (token); ++ token = NULL; ++ } ++ ++ status = cr_tknzr_get_next_token ++ (PRIVATE (a_this)->tknzr, &token); ++ ++ if (status == CR_END_OF_INPUT_ERROR) ++ goto done; ++ CHECK_PARSING_STATUS (status, TRUE); ++ } while (token ++ && (token->type == S_TK ++ || token->type == CDO_TK ++ || token->type == CDC_TK)); ++ } else { ++ if (token) { ++ status = cr_tknzr_unget_token ++ (PRIVATE (a_this)->tknzr, token); ++ token = NULL; ++ } ++ goto parse_ruleset_and_others; ++ } ++ } ++ ++ parse_ruleset_and_others: ++ ++ cr_parser_try_to_skip_spaces_and_comments (a_this); ++ ++ for (;;) { ++ status = cr_tknzr_get_next_token ++ (PRIVATE (a_this)->tknzr, &token); ++ if (status == CR_END_OF_INPUT_ERROR) ++ goto done; ++ CHECK_PARSING_STATUS (status, TRUE); ++ ++ if (token ++ && (token->type == S_TK ++ || token->type == CDO_TK || token->type == CDC_TK)) { ++ status = cr_tknzr_unget_token ++ (PRIVATE (a_this)->tknzr, token); ++ token = NULL; ++ ++ do { ++ if (token) { ++ cr_token_destroy (token); ++ token = NULL; ++ } ++ ++ cr_parser_try_to_skip_spaces_and_comments ++ (a_this); ++ status = cr_tknzr_get_next_token ++ (PRIVATE (a_this)->tknzr, &token); ++ } while (token ++ && (token->type == S_TK ++ || token->type == COMMENT_TK ++ || token->type == CDO_TK ++ || token->type == CDC_TK)); ++ if (token) { ++ cr_tknzr_unget_token ++ (PRIVATE (a_this)->tknzr, token); ++ token = NULL; ++ } ++ } else if (token ++ && (token->type == HASH_TK ++ || (token->type == DELIM_TK ++ && token->u.unichar == '.') ++ || (token->type == DELIM_TK ++ && token->u.unichar == ':') ++ || (token->type == DELIM_TK ++ && token->u.unichar == '*') ++ || (token->type == BO_TK) ++ || token->type == IDENT_TK)) { ++ /* ++ *Try to parse a CSS2 ruleset. ++ *if the parsing fails, try to parse ++ *a css core ruleset. ++ */ ++ status = cr_tknzr_unget_token ++ (PRIVATE (a_this)->tknzr, token); ++ CHECK_PARSING_STATUS (status, TRUE); ++ token = NULL; ++ ++ status = cr_parser_parse_ruleset (a_this); ++ ++ if (status == CR_OK) { ++ continue; ++ } else { ++ if (PRIVATE (a_this)->sac_handler ++ && PRIVATE (a_this)->sac_handler->error) { ++ PRIVATE (a_this)->sac_handler-> ++ error ++ (PRIVATE (a_this)-> ++ sac_handler); ++ } ++ ++ status = cr_parser_parse_ruleset_core ++ (a_this); ++ ++ if (status == CR_OK) { ++ continue; ++ } else { ++ break; ++ } ++ } ++ } else if (token && token->type == MEDIA_SYM_TK) { ++ status = cr_tknzr_unget_token ++ (PRIVATE (a_this)->tknzr, token); ++ CHECK_PARSING_STATUS (status, TRUE); ++ token = NULL; ++ ++ status = cr_parser_parse_media (a_this); ++ if (status == CR_OK) { ++ continue; ++ } else { ++ if (PRIVATE (a_this)->sac_handler ++ && PRIVATE (a_this)->sac_handler->error) { ++ PRIVATE (a_this)->sac_handler-> ++ error ++ (PRIVATE (a_this)-> ++ sac_handler); ++ } ++ ++ status = cr_parser_parse_atrule_core (a_this); ++ ++ if (status == CR_OK) { ++ continue; ++ } else { ++ break; ++ } ++ } ++ ++ } else if (token && token->type == PAGE_SYM_TK) { ++ status = cr_tknzr_unget_token ++ (PRIVATE (a_this)->tknzr, token); ++ CHECK_PARSING_STATUS (status, TRUE); ++ token = NULL; ++ status = cr_parser_parse_page (a_this); ++ ++ if (status == CR_OK) { ++ continue; ++ } else { ++ if (PRIVATE (a_this)->sac_handler ++ && PRIVATE (a_this)->sac_handler->error) { ++ PRIVATE (a_this)->sac_handler-> ++ error ++ (PRIVATE (a_this)-> ++ sac_handler); ++ } ++ ++ status = cr_parser_parse_atrule_core (a_this); ++ ++ if (status == CR_OK) { ++ continue; ++ } else { ++ break; ++ } ++ } ++ } else if (token && token->type == FONT_FACE_SYM_TK) { ++ status = cr_tknzr_unget_token ++ (PRIVATE (a_this)->tknzr, token); ++ CHECK_PARSING_STATUS (status, TRUE); ++ token = NULL; ++ status = cr_parser_parse_font_face (a_this); ++ ++ if (status == CR_OK) { ++ continue; ++ } else { ++ if (PRIVATE (a_this)->sac_handler ++ && PRIVATE (a_this)->sac_handler->error) { ++ PRIVATE (a_this)->sac_handler-> ++ error ++ (PRIVATE (a_this)-> ++ sac_handler); ++ } ++ ++ status = cr_parser_parse_atrule_core (a_this); ++ ++ if (status == CR_OK) { ++ continue; ++ } else { ++ break; ++ } ++ } ++ } else { ++ status = cr_tknzr_unget_token ++ (PRIVATE (a_this)->tknzr, token); ++ CHECK_PARSING_STATUS (status, TRUE); ++ token = NULL; ++ status = cr_parser_parse_statement_core (a_this); ++ ++ if (status == CR_OK) { ++ continue; ++ } else { ++ break; ++ } ++ } ++ } ++ ++ done: ++ if (token) { ++ cr_token_destroy (token); ++ token = NULL; ++ } ++ ++ if (status == CR_END_OF_INPUT_ERROR || status == CR_OK) { ++ ++ if (PRIVATE (a_this)->sac_handler ++ && PRIVATE (a_this)->sac_handler->end_document) { ++ PRIVATE (a_this)->sac_handler->end_document ++ (PRIVATE (a_this)->sac_handler); ++ } ++ ++ return CR_OK; ++ } ++ ++ cr_parser_push_error ++ (a_this, (const guchar *) "could not recognize next production", CR_ERROR); ++ ++ if (PRIVATE (a_this)->sac_handler ++ && PRIVATE (a_this)->sac_handler->unrecoverable_error) { ++ PRIVATE (a_this)->sac_handler-> ++ unrecoverable_error (PRIVATE (a_this)->sac_handler); ++ } ++ ++ cr_parser_dump_err_stack (a_this, TRUE); ++ ++ return status; ++ ++ error: ++ ++ if (token) { ++ cr_token_destroy (token); ++ token = NULL; ++ } ++ ++ if (PRIVATE (a_this)->sac_handler ++ && PRIVATE (a_this)->sac_handler->unrecoverable_error) { ++ PRIVATE (a_this)->sac_handler-> ++ unrecoverable_error (PRIVATE (a_this)->sac_handler); ++ } ++ ++ cr_tknzr_set_cur_pos (PRIVATE (a_this)->tknzr, &init_pos); ++ ++ return status; ++} ++ ++/**************************************** ++ *Public CRParser Methods ++ ****************************************/ ++ ++/** ++ * cr_parser_new: ++ * @a_tknzr: the tokenizer to use for the parsing. ++ * ++ *Creates a new parser to parse data ++ *coming the input stream given in parameter. ++ * ++ *Returns the newly created instance of #CRParser, ++ *or NULL if an error occurred. ++ */ ++CRParser * ++cr_parser_new (CRTknzr * a_tknzr) ++{ ++ CRParser *result = NULL; ++ enum CRStatus status = CR_OK; ++ ++ result = g_malloc0 (sizeof (CRParser)); ++ ++ PRIVATE (result) = g_malloc0 (sizeof (CRParserPriv)); ++ ++ if (a_tknzr) { ++ status = cr_parser_set_tknzr (result, a_tknzr); ++ } ++ ++ g_return_val_if_fail (status == CR_OK, NULL); ++ ++ return result; ++} ++ ++/** ++ * cr_parser_new_from_buf: ++ *@a_buf: the buffer to parse. ++ *@a_len: the length of the data in the buffer. ++ *@a_enc: the encoding of the input buffer a_buf. ++ *@a_free_buf: if set to TRUE, a_buf will be freed ++ *during the destruction of the newly built instance ++ *of #CRParser. If set to FALSE, it is up to the caller to ++ *eventually free it. ++ * ++ *Instanciates a new parser from a memory buffer. ++ * ++ *Returns the newly built parser, or NULL if an error arises. ++ */ ++CRParser * ++cr_parser_new_from_buf (guchar * a_buf, ++ gulong a_len, ++ enum CREncoding a_enc, ++ gboolean a_free_buf) ++{ ++ CRParser *result = NULL; ++ CRInput *input = NULL; ++ ++ g_return_val_if_fail (a_buf && a_len, NULL); ++ ++ input = cr_input_new_from_buf (a_buf, a_len, a_enc, a_free_buf); ++ g_return_val_if_fail (input, NULL); ++ ++ result = cr_parser_new_from_input (input); ++ if (!result) { ++ cr_input_destroy (input); ++ input = NULL; ++ return NULL; ++ } ++ return result; ++} ++ ++/** ++ * cr_parser_new_from_input: ++ * @a_input: the parser input stream to use. ++ * ++ * Returns a newly built parser input. ++ */ ++CRParser * ++cr_parser_new_from_input (CRInput * a_input) ++{ ++ CRParser *result = NULL; ++ CRTknzr *tokenizer = NULL; ++ ++ if (a_input) { ++ tokenizer = cr_tknzr_new (a_input); ++ g_return_val_if_fail (tokenizer, NULL); ++ } ++ ++ result = cr_parser_new (tokenizer); ++ g_return_val_if_fail (result, NULL); ++ ++ return result; ++} ++ ++/** ++ * cr_parser_new_from_file: ++ * @a_file_uri: the uri of the file to parse. ++ * @a_enc: the file encoding to use. ++ * ++ * Returns the newly built parser. ++ */ ++CRParser * ++cr_parser_new_from_file (const guchar * a_file_uri, enum CREncoding a_enc) ++{ ++ CRParser *result = NULL; ++ CRTknzr *tokenizer = NULL; ++ ++ tokenizer = cr_tknzr_new_from_uri (a_file_uri, a_enc); ++ if (!tokenizer) { ++ cr_utils_trace_info ("Could not open input file"); ++ return NULL; ++ } ++ ++ result = cr_parser_new (tokenizer); ++ g_return_val_if_fail (result, NULL); ++ return result; ++} ++ ++/** ++ * cr_parser_set_sac_handler: ++ *@a_this: the "this pointer" of the current instance of #CRParser. ++ *@a_handler: the handler to set. ++ * ++ *Sets a SAC document handler to the parser. ++ * ++ *Returns CR_OK upon successfull completion, an error code otherwise. ++ */ ++enum CRStatus ++cr_parser_set_sac_handler (CRParser * a_this, CRDocHandler * a_handler) ++{ ++ g_return_val_if_fail (a_this, CR_BAD_PARAM_ERROR); ++ ++ if (PRIVATE (a_this)->sac_handler) { ++ cr_doc_handler_unref (PRIVATE (a_this)->sac_handler); ++ } ++ ++ PRIVATE (a_this)->sac_handler = a_handler; ++ cr_doc_handler_ref (a_handler); ++ ++ return CR_OK; ++} ++ ++/** ++ * cr_parser_get_sac_handler: ++ *@a_this: the "this pointer" of the current instance of ++ *#CRParser. ++ *@a_handler: out parameter. The returned handler. ++ * ++ *Gets the SAC document handler. ++ * ++ *Returns CR_OK upon successfull completion, an error code ++ *otherwise. ++ */ ++enum CRStatus ++cr_parser_get_sac_handler (CRParser * a_this, CRDocHandler ** a_handler) ++{ ++ g_return_val_if_fail (a_this, CR_BAD_PARAM_ERROR); ++ ++ *a_handler = PRIVATE (a_this)->sac_handler; ++ ++ return CR_OK; ++} ++ ++/** ++ * cr_parser_set_default_sac_handler: ++ *@a_this: a pointer to the current instance of #CRParser. ++ * ++ *Sets the SAC handler associated to the current instance ++ *of #CRParser to the default SAC handler. ++ * ++ *Returns CR_OK upon successfull completion, an error code otherwise. ++ */ ++enum CRStatus ++cr_parser_set_default_sac_handler (CRParser * a_this) ++{ ++ CRDocHandler *default_sac_handler = NULL; ++ enum CRStatus status = CR_ERROR; ++ ++ g_return_val_if_fail (a_this && PRIVATE (a_this), CR_BAD_PARAM_ERROR); ++ ++ default_sac_handler = cr_doc_handler_new (); ++ ++ cr_doc_handler_set_default_sac_handler (default_sac_handler); ++ ++ status = cr_parser_set_sac_handler (a_this, default_sac_handler); ++ ++ if (status != CR_OK) { ++ cr_doc_handler_destroy (default_sac_handler); ++ default_sac_handler = NULL; ++ } ++ ++ return status; ++} ++ ++/** ++ * cr_parser_set_use_core_grammar: ++ * @a_this: the current instance of #CRParser. ++ * @a_use_core_grammar: where to parse against the css core grammar. ++ * ++ * Returns CR_OK upon succesful completion, an error code otherwise. ++ */ ++enum CRStatus ++cr_parser_set_use_core_grammar (CRParser * a_this, ++ gboolean a_use_core_grammar) ++{ ++ g_return_val_if_fail (a_this && PRIVATE (a_this), CR_BAD_PARAM_ERROR); ++ ++ PRIVATE (a_this)->use_core_grammar = a_use_core_grammar; ++ ++ return CR_OK; ++} ++ ++/** ++ * cr_parser_get_use_core_grammar: ++ * @a_this: the current instance of #CRParser. ++ * @a_use_core_grammar: wether to use the core grammar or not. ++ * ++ * Returns CR_OK upon succesful completion, an error code otherwise. ++ */ ++enum CRStatus ++cr_parser_get_use_core_grammar (CRParser const * a_this, ++ gboolean * a_use_core_grammar) ++{ ++ g_return_val_if_fail (a_this && PRIVATE (a_this), CR_BAD_PARAM_ERROR); ++ ++ *a_use_core_grammar = PRIVATE (a_this)->use_core_grammar; ++ ++ return CR_OK; ++} ++ ++/** ++ * cr_parser_parse_file: ++ *@a_this: a pointer to the current instance of #CRParser. ++ *@a_file_uri: the uri to the file to load. For the time being, ++ *@a_enc: the encoding of the file to parse. ++ *only local files are supported. ++ * ++ *Parses a the given in parameter. ++ * ++ *Returns CR_OK upon successfull completion, an error code otherwise. ++ */ ++enum CRStatus ++cr_parser_parse_file (CRParser * a_this, ++ const guchar * a_file_uri, enum CREncoding a_enc) ++{ ++ enum CRStatus status = CR_ERROR; ++ CRTknzr *tknzr = NULL; ++ ++ g_return_val_if_fail (a_this && PRIVATE (a_this) ++ && a_file_uri, CR_BAD_PARAM_ERROR); ++ ++ tknzr = cr_tknzr_new_from_uri (a_file_uri, a_enc); ++ ++ g_return_val_if_fail (tknzr != NULL, CR_ERROR); ++ ++ status = cr_parser_set_tknzr (a_this, tknzr); ++ g_return_val_if_fail (status == CR_OK, CR_ERROR); ++ ++ status = cr_parser_parse (a_this); ++ ++ return status; ++} ++ ++/** ++ * cr_parser_parse_expr: ++ * @a_this: the current instance of #CRParser. ++ * @a_expr: out parameter. the parsed expression. ++ * ++ *Parses an expression as defined by the css2 spec in appendix ++ *D.1: ++ *expr: term [ operator term ]* ++ * ++ * ++ * Returns CR_OK upon successful completion, an error code otherwise. ++ */ ++enum CRStatus ++cr_parser_parse_expr (CRParser * a_this, CRTerm ** a_expr) ++{ ++ enum CRStatus status = CR_ERROR; ++ CRInputPos init_pos; ++ CRTerm *expr = NULL, ++ *expr2 = NULL; ++ guchar next_byte = 0; ++ gulong nb_terms = 0; ++ ++ g_return_val_if_fail (a_this && PRIVATE (a_this) ++ && a_expr, CR_BAD_PARAM_ERROR); ++ ++ RECORD_INITIAL_POS (a_this, &init_pos); ++ ++ status = cr_parser_parse_term (a_this, &expr); ++ ++ CHECK_PARSING_STATUS (status, FALSE); ++ ++ for (;;) { ++ guchar operator = 0; ++ ++ status = cr_tknzr_peek_byte (PRIVATE (a_this)->tknzr, ++ 1, &next_byte); ++ if (status != CR_OK) { ++ if (status == CR_END_OF_INPUT_ERROR) { ++ /* ++ if (!nb_terms) ++ { ++ goto error ; ++ } ++ */ ++ status = CR_OK; ++ break; ++ } else { ++ goto error; ++ } ++ } ++ ++ if (next_byte == '/' || next_byte == ',') { ++ READ_NEXT_BYTE (a_this, &operator); ++ } ++ ++ cr_parser_try_to_skip_spaces_and_comments (a_this); ++ ++ status = cr_parser_parse_term (a_this, &expr2); ++ ++ if (status != CR_OK || expr2 == NULL) { ++ status = CR_OK; ++ break; ++ } ++ ++ switch (operator) { ++ case '/': ++ expr2->the_operator = DIVIDE; ++ break; ++ case ',': ++ expr2->the_operator = COMMA; ++ ++ default: ++ break; ++ } ++ ++ expr = cr_term_append_term (expr, expr2); ++ expr2 = NULL; ++ operator = 0; ++ nb_terms++; ++ } ++ ++ if (status == CR_OK) { ++ *a_expr = cr_term_append_term (*a_expr, expr); ++ expr = NULL; ++ ++ cr_parser_clear_errors (a_this); ++ return CR_OK; ++ } ++ ++ error: ++ ++ if (expr) { ++ cr_term_destroy (expr); ++ expr = NULL; ++ } ++ ++ if (expr2) { ++ cr_term_destroy (expr2); ++ expr2 = NULL; ++ } ++ ++ cr_tknzr_set_cur_pos (PRIVATE (a_this)->tknzr, &init_pos); ++ ++ return status; ++} ++ ++/** ++ * cr_parser_parse_prio: ++ *@a_this: the current instance of #CRParser. ++ *@a_prio: a string representing the priority. ++ *Today, only "!important" is returned as only this ++ *priority is defined by css2. ++ * ++ *Parses a declaration priority as defined by ++ *the css2 grammar in appendix C: ++ *prio: IMPORTANT_SYM S* ++ * ++ * Returns CR_OK upon successful completion, an error code otherwise. ++ */ ++enum CRStatus ++cr_parser_parse_prio (CRParser * a_this, CRString ** a_prio) ++{ ++ enum CRStatus status = CR_ERROR; ++ CRInputPos init_pos; ++ CRToken *token = NULL; ++ ++ g_return_val_if_fail (a_this && PRIVATE (a_this) ++ && a_prio ++ && *a_prio == NULL, CR_BAD_PARAM_ERROR); ++ ++ RECORD_INITIAL_POS (a_this, &init_pos); ++ ++ status = cr_tknzr_get_next_token (PRIVATE (a_this)->tknzr, &token); ++ if (status == CR_END_OF_INPUT_ERROR) { ++ goto error; ++ } ++ ENSURE_PARSING_COND (status == CR_OK ++ && token && token->type == IMPORTANT_SYM_TK); ++ ++ cr_parser_try_to_skip_spaces_and_comments (a_this); ++ *a_prio = cr_string_new_from_string ("!important"); ++ cr_token_destroy (token); ++ token = NULL; ++ return CR_OK; ++ ++ error: ++ if (token) { ++ cr_token_destroy (token); ++ token = NULL; ++ } ++ cr_tknzr_set_cur_pos (PRIVATE (a_this)->tknzr, &init_pos); ++ ++ return status; ++} ++ ++/** ++ * cr_parser_parse_declaration: ++ *@a_this: the "this pointer" of the current instance of #CRParser. ++ *@a_property: the successfully parsed property. The caller ++ * *must* free the returned pointer. ++ *@a_expr: the expression that represents the attribute value. ++ *The caller *must* free the returned pointer. ++ * ++ *TODO: return the parsed priority, so that ++ *upper layers can take benefit from it. ++ *Parses a "declaration" as defined by the css2 spec in appendix D.1: ++ *declaration ::= [property ':' S* expr prio?]? ++ * ++ *Returns CR_OK upon successfull completion, an error code otherwise. ++ */ ++enum CRStatus ++cr_parser_parse_declaration (CRParser * a_this, ++ CRString ** a_property, ++ CRTerm ** a_expr, gboolean * a_important) ++{ ++ enum CRStatus status = CR_ERROR; ++ CRInputPos init_pos; ++ guint32 cur_char = 0; ++ CRTerm *expr = NULL; ++ CRString *prio = NULL; ++ ++ g_return_val_if_fail (a_this && PRIVATE (a_this) ++ && a_property && a_expr ++ && a_important, CR_BAD_PARAM_ERROR); ++ ++ RECORD_INITIAL_POS (a_this, &init_pos); ++ ++ status = cr_parser_parse_property (a_this, a_property); ++ ++ if (status == CR_END_OF_INPUT_ERROR) ++ goto error; ++ ++ CHECK_PARSING_STATUS_ERR ++ (a_this, status, FALSE, ++ (const guchar *) "while parsing declaration: next property is malformed", ++ CR_SYNTAX_ERROR); ++ ++ READ_NEXT_CHAR (a_this, &cur_char); ++ ++ if (cur_char != ':') { ++ status = CR_PARSING_ERROR; ++ cr_parser_push_error ++ (a_this, ++ (const guchar *) "while parsing declaration: this char must be ':'", ++ CR_SYNTAX_ERROR); ++ goto error; ++ } ++ ++ cr_parser_try_to_skip_spaces_and_comments (a_this); ++ ++ status = cr_parser_parse_expr (a_this, &expr); ++ ++ CHECK_PARSING_STATUS_ERR ++ (a_this, status, FALSE, ++ (const guchar *) "while parsing declaration: next expression is malformed", ++ CR_SYNTAX_ERROR); ++ ++ cr_parser_try_to_skip_spaces_and_comments (a_this); ++ status = cr_parser_parse_prio (a_this, &prio); ++ if (prio) { ++ cr_string_destroy (prio); ++ prio = NULL; ++ *a_important = TRUE; ++ } else { ++ *a_important = FALSE; ++ } ++ if (*a_expr) { ++ cr_term_append_term (*a_expr, expr); ++ expr = NULL; ++ } else { ++ *a_expr = expr; ++ expr = NULL; ++ } ++ ++ cr_parser_clear_errors (a_this); ++ return CR_OK; ++ ++ error: ++ ++ if (expr) { ++ cr_term_destroy (expr); ++ expr = NULL; ++ } ++ ++ if (*a_property) { ++ cr_string_destroy (*a_property); ++ *a_property = NULL; ++ } ++ ++ cr_tknzr_set_cur_pos (PRIVATE (a_this)->tknzr, &init_pos); ++ ++ return status; ++} ++ ++/** ++ * cr_parser_parse_statement_core: ++ *@a_this: the current instance of #CRParser. ++ * ++ *Parses a statement as defined by the css core grammar in ++ *chapter 4.1 of the css2 spec. ++ *statement : ruleset | at-rule; ++ * ++ *Returns CR_OK upon successfull completion, an error code otherwise. ++ */ ++enum CRStatus ++cr_parser_parse_statement_core (CRParser * a_this) ++{ ++ CRToken *token = NULL; ++ CRInputPos init_pos; ++ enum CRStatus status = CR_ERROR; ++ ++ g_return_val_if_fail (a_this && PRIVATE (a_this), CR_BAD_PARAM_ERROR); ++ ++ RECORD_INITIAL_POS (a_this, &init_pos); ++ ++ status = cr_tknzr_get_next_token (PRIVATE (a_this)->tknzr, &token); ++ ++ ENSURE_PARSING_COND (status == CR_OK && token); ++ ++ switch (token->type) { ++ case ATKEYWORD_TK: ++ case IMPORT_SYM_TK: ++ case PAGE_SYM_TK: ++ case MEDIA_SYM_TK: ++ case FONT_FACE_SYM_TK: ++ case CHARSET_SYM_TK: ++ cr_tknzr_unget_token (PRIVATE (a_this)->tknzr, token); ++ token = NULL; ++ status = cr_parser_parse_atrule_core (a_this); ++ CHECK_PARSING_STATUS (status, TRUE); ++ break; ++ ++ default: ++ cr_tknzr_unget_token (PRIVATE (a_this)->tknzr, token); ++ token = NULL; ++ status = cr_parser_parse_ruleset_core (a_this); ++ cr_parser_clear_errors (a_this); ++ CHECK_PARSING_STATUS (status, TRUE); ++ } ++ ++ return CR_OK; ++ ++ error: ++ if (token) { ++ cr_token_destroy (token); ++ token = NULL; ++ } ++ ++ cr_tknzr_set_cur_pos (PRIVATE (a_this)->tknzr, &init_pos); ++ ++ return status; ++} ++ ++/** ++ * cr_parser_parse_ruleset: ++ *@a_this: the "this pointer" of the current instance of #CRParser. ++ * ++ *Parses a "ruleset" as defined in the css2 spec at appendix D.1. ++ *ruleset ::= selector [ ',' S* selector ]* ++ *'{' S* declaration? [ ';' S* declaration? ]* '}' S*; ++ * ++ *This methods calls the the SAC handler on the relevant SAC handler ++ *callbacks whenever it encounters some specific constructions. ++ *See the documentation of #CRDocHandler (the SAC handler) to know ++ *when which SAC handler is called. ++ * ++ *Returns CR_OK upon successfull completion, an error code otherwise. ++ */ ++enum CRStatus ++cr_parser_parse_ruleset (CRParser * a_this) ++{ ++ enum CRStatus status = CR_OK; ++ CRInputPos init_pos; ++ guint32 cur_char = 0, ++ next_char = 0; ++ CRString *property = NULL; ++ CRTerm *expr = NULL; ++ CRSimpleSel *simple_sels = NULL; ++ CRSelector *selector = NULL; ++ gboolean start_selector = FALSE, ++ is_important = FALSE; ++ CRParsingLocation end_parsing_location; ++ ++ g_return_val_if_fail (a_this, CR_BAD_PARAM_ERROR); ++ ++ RECORD_INITIAL_POS (a_this, &init_pos); ++ ++ status = cr_parser_parse_selector (a_this, &selector); ++ CHECK_PARSING_STATUS (status, FALSE); ++ ++ READ_NEXT_CHAR (a_this, &cur_char); ++ ++ ENSURE_PARSING_COND_ERR ++ (a_this, cur_char == '{', ++ (const guchar *) "while parsing rulset: current char should be '{'", ++ CR_SYNTAX_ERROR); ++ ++ if (PRIVATE (a_this)->sac_handler ++ && PRIVATE (a_this)->sac_handler->start_selector) { ++ /* ++ *the selector is ref counted so that the parser's user ++ *can choose to keep it. ++ */ ++ if (selector) { ++ cr_selector_ref (selector); ++ } ++ ++ PRIVATE (a_this)->sac_handler->start_selector ++ (PRIVATE (a_this)->sac_handler, selector); ++ start_selector = TRUE; ++ } ++ ++ cr_parser_try_to_skip_spaces_and_comments (a_this); ++ ++ PRIVATE (a_this)->state = TRY_PARSE_RULESET_STATE; ++ ++ status = cr_parser_parse_declaration (a_this, &property, ++ &expr, ++ &is_important); ++ if (expr) { ++ cr_term_ref (expr); ++ } ++ if (status == CR_OK ++ && PRIVATE (a_this)->sac_handler ++ && PRIVATE (a_this)->sac_handler->property) { ++ PRIVATE (a_this)->sac_handler->property ++ (PRIVATE (a_this)->sac_handler, property, expr, ++ is_important); ++ } ++ if (status == CR_OK) { ++ /* ++ *free the allocated ++ *'property' and 'term' before parsing ++ *next declarations. ++ */ ++ if (property) { ++ cr_string_destroy (property); ++ property = NULL; ++ } ++ if (expr) { ++ cr_term_unref (expr); ++ expr = NULL; ++ } ++ } else {/*status != CR_OK*/ ++ guint32 c = 0 ; ++ /* ++ *test if we have reached '}', which ++ *would mean that we are parsing an empty ruleset (eg. x{ }) ++ *In that case, goto end_of_ruleset. ++ */ ++ status = cr_tknzr_peek_char (PRIVATE (a_this)->tknzr, &c) ; ++ if (status == CR_OK && c == '}') { ++ status = CR_OK ; ++ goto end_of_ruleset ; ++ } ++ } ++ CHECK_PARSING_STATUS_ERR ++ (a_this, status, FALSE, ++ (const guchar *) "while parsing ruleset: next construction should be a declaration", ++ CR_SYNTAX_ERROR); ++ ++ for (;;) { ++ PEEK_NEXT_CHAR (a_this, &next_char); ++ if (next_char != ';') ++ break; ++ ++ /*consume the ';' char */ ++ READ_NEXT_CHAR (a_this, &cur_char); ++ ++ cr_parser_try_to_skip_spaces_and_comments (a_this); ++ ++ status = cr_parser_parse_declaration (a_this, &property, ++ &expr, &is_important); ++ ++ if (expr) { ++ cr_term_ref (expr); ++ } ++ if (status == CR_OK ++ && PRIVATE (a_this)->sac_handler ++ && PRIVATE (a_this)->sac_handler->property) { ++ PRIVATE (a_this)->sac_handler->property ++ (PRIVATE (a_this)->sac_handler, ++ property, expr, is_important); ++ } ++ if (property) { ++ cr_string_destroy (property); ++ property = NULL; ++ } ++ if (expr) { ++ cr_term_unref (expr); ++ expr = NULL; ++ } ++ } ++ ++ end_of_ruleset: ++ cr_parser_try_to_skip_spaces_and_comments (a_this); ++ cr_parser_get_parsing_location (a_this, &end_parsing_location); ++ READ_NEXT_CHAR (a_this, &cur_char); ++ ENSURE_PARSING_COND_ERR ++ (a_this, cur_char == '}', ++ (const guchar *) "while parsing rulset: current char must be a '}'", ++ CR_SYNTAX_ERROR); ++ ++ selector->location = end_parsing_location; ++ if (PRIVATE (a_this)->sac_handler ++ && PRIVATE (a_this)->sac_handler->end_selector) { ++ PRIVATE (a_this)->sac_handler->end_selector ++ (PRIVATE (a_this)->sac_handler, selector); ++ start_selector = FALSE; ++ } ++ ++ if (expr) { ++ cr_term_unref (expr); ++ expr = NULL; ++ } ++ ++ if (simple_sels) { ++ cr_simple_sel_destroy (simple_sels); ++ simple_sels = NULL; ++ } ++ ++ if (selector) { ++ cr_selector_unref (selector); ++ selector = NULL; ++ } ++ ++ cr_parser_clear_errors (a_this); ++ PRIVATE (a_this)->state = RULESET_PARSED_STATE; ++ ++ return CR_OK; ++ ++ error: ++ if (start_selector == TRUE ++ && PRIVATE (a_this)->sac_handler ++ && PRIVATE (a_this)->sac_handler->error) { ++ PRIVATE (a_this)->sac_handler->error ++ (PRIVATE (a_this)->sac_handler); ++ } ++ if (expr) { ++ cr_term_unref (expr); ++ expr = NULL; ++ } ++ if (simple_sels) { ++ cr_simple_sel_destroy (simple_sels); ++ simple_sels = NULL; ++ } ++ if (property) { ++ cr_string_destroy (property); ++ } ++ if (selector) { ++ cr_selector_unref (selector); ++ selector = NULL; ++ } ++ ++ cr_tknzr_set_cur_pos (PRIVATE (a_this)->tknzr, &init_pos); ++ ++ return status; ++} ++ ++/** ++ * cr_parser_parse_import: ++ *@a_this: the "this pointer" of the current instance ++ *of #CRParser. ++ *@a_media_list: out parameter. A linked list of ++ *#CRString ++ *Each CRString is a string that contains ++ *a 'medium' declaration part of the successfully ++ *parsed 'import' declaration. ++ *@a_import_string: out parameter. ++ *A string that contains the 'import ++ *string". The import string can be either an uri (if it starts with ++ *the substring "uri(") or a any other css2 string. Note that ++ * *a_import_string must be initially set to NULL or else, this function ++ *will return CR_BAD_PARAM_ERROR. ++ *@a_location: the location (line, column) where the import has been parsed ++ * ++ *Parses an 'import' declaration as defined in the css2 spec ++ *in appendix D.1: ++ * ++ *import ::= ++ *\@import [STRING|URI] S* [ medium [ ',' S* medium]* ]? ';' S* ++ * ++ *Returns CR_OK upon sucessfull completion, an error code otherwise. ++ */ ++enum CRStatus ++cr_parser_parse_import (CRParser * a_this, ++ GList ** a_media_list, ++ CRString ** a_import_string, ++ CRParsingLocation *a_location) ++{ ++ enum CRStatus status = CR_OK; ++ CRInputPos init_pos; ++ guint32 cur_char = 0, ++ next_char = 0; ++ CRString *medium = NULL; ++ ++ g_return_val_if_fail (a_this ++ && a_import_string ++ && (*a_import_string == NULL), ++ CR_BAD_PARAM_ERROR); ++ ++ RECORD_INITIAL_POS (a_this, &init_pos); ++ ++ if (BYTE (a_this, 1, NULL) == '@' ++ && BYTE (a_this, 2, NULL) == 'i' ++ && BYTE (a_this, 3, NULL) == 'm' ++ && BYTE (a_this, 4, NULL) == 'p' ++ && BYTE (a_this, 5, NULL) == 'o' ++ && BYTE (a_this, 6, NULL) == 'r' ++ && BYTE (a_this, 7, NULL) == 't') { ++ SKIP_CHARS (a_this, 1); ++ if (a_location) { ++ cr_parser_get_parsing_location ++ (a_this, a_location) ; ++ } ++ SKIP_CHARS (a_this, 6); ++ status = CR_OK; ++ } else { ++ status = CR_PARSING_ERROR; ++ goto error; ++ } ++ ++ cr_parser_try_to_skip_spaces_and_comments (a_this); ++ ++ PRIVATE (a_this)->state = TRY_PARSE_IMPORT_STATE; ++ ++ PEEK_NEXT_CHAR (a_this, &next_char); ++ ++ if (next_char == '"' || next_char == '\'') { ++ status = cr_parser_parse_string (a_this, a_import_string); ++ ++ CHECK_PARSING_STATUS (status, FALSE); ++ } else { ++ status = cr_parser_parse_uri (a_this, a_import_string); ++ ++ CHECK_PARSING_STATUS (status, FALSE); ++ } ++ ++ cr_parser_try_to_skip_spaces_and_comments (a_this); ++ ++ status = cr_parser_parse_ident (a_this, &medium); ++ ++ if (status == CR_OK && medium) { ++ *a_media_list = g_list_append (*a_media_list, medium); ++ medium = NULL; ++ } ++ ++ cr_parser_try_to_skip_spaces_and_comments (a_this); ++ ++ for (; status == CR_OK;) { ++ if ((status = cr_tknzr_peek_char (PRIVATE (a_this)->tknzr, ++ &next_char)) != CR_OK) { ++ if (status == CR_END_OF_INPUT_ERROR) { ++ status = CR_OK; ++ goto okay; ++ } ++ goto error; ++ } ++ ++ if (next_char == ',') { ++ READ_NEXT_CHAR (a_this, &cur_char); ++ } else { ++ break; ++ } ++ ++ cr_parser_try_to_skip_spaces_and_comments (a_this); ++ ++ status = cr_parser_parse_ident (a_this, &medium); ++ ++ cr_parser_try_to_skip_spaces_and_comments (a_this); ++ ++ if ((status == CR_OK) && medium) { ++ *a_media_list = g_list_append (*a_media_list, medium); ++ ++ medium = NULL; ++ } ++ ++ CHECK_PARSING_STATUS (status, FALSE); ++ cr_parser_try_to_skip_spaces_and_comments (a_this); ++ } ++ cr_parser_try_to_skip_spaces_and_comments (a_this); ++ READ_NEXT_CHAR (a_this, &cur_char); ++ ENSURE_PARSING_COND (cur_char == ';'); ++ cr_parser_try_to_skip_spaces_and_comments (a_this); ++ okay: ++ cr_parser_clear_errors (a_this); ++ PRIVATE (a_this)->state = IMPORT_PARSED_STATE; ++ ++ return CR_OK; ++ ++ error: ++ ++ if (*a_media_list) { ++ GList *cur = NULL; ++ ++ /* ++ *free each element of *a_media_list. ++ *Note that each element of *a_medium list *must* ++ *be a GString* or else, the code that is coming next ++ *will corrupt the memory and lead to hard to debug ++ *random crashes. ++ *This is where C++ and its compile time ++ *type checking mecanism (through STL containers) would ++ *have prevented us to go through this hassle. ++ */ ++ for (cur = *a_media_list; cur; cur = cur->next) { ++ if (cur->data) { ++ cr_string_destroy (cur->data); ++ } ++ } ++ ++ g_list_free (*a_media_list); ++ *a_media_list = NULL; ++ } ++ ++ if (*a_import_string) { ++ cr_string_destroy (*a_import_string); ++ *a_import_string = NULL; ++ } ++ ++ if (medium) { ++ cr_string_destroy (medium); ++ medium = NULL; ++ } ++ ++ cr_tknzr_set_cur_pos (PRIVATE (a_this)->tknzr, &init_pos); ++ ++ return status; ++} ++ ++/** ++ * cr_parser_parse_media: ++ *@a_this: the "this pointer" of the current instance of #CRParser. ++ * ++ *Parses a 'media' declaration as specified in the css2 spec at ++ *appendix D.1: ++ * ++ *media ::= \@media S* medium [ ',' S* medium ]* '{' S* ruleset* '}' S* ++ * ++ *Note that this function calls the required sac handlers during the parsing ++ *to notify media productions. See #CRDocHandler to know the callback called ++ *during \@media parsing. ++ * ++ *Returns CR_OK upon successfull completion, an error code otherwise. ++ */ ++enum CRStatus ++cr_parser_parse_media (CRParser * a_this) ++{ ++ enum CRStatus status = CR_OK; ++ CRInputPos init_pos; ++ CRToken *token = NULL; ++ guint32 next_char = 0, ++ cur_char = 0; ++ CRString *medium = NULL; ++ GList *media_list = NULL; ++ CRParsingLocation location = {0} ; ++ ++ g_return_val_if_fail (a_this ++ && PRIVATE (a_this), ++ CR_BAD_PARAM_ERROR); ++ ++ RECORD_INITIAL_POS (a_this, &init_pos); ++ ++ status = cr_tknzr_get_next_token (PRIVATE (a_this)->tknzr, ++ &token); ++ ENSURE_PARSING_COND (status == CR_OK ++ && token ++ && token->type == MEDIA_SYM_TK); ++ cr_parsing_location_copy (&location, &token->location) ; ++ cr_token_destroy (token); ++ token = NULL; ++ ++ cr_parser_try_to_skip_spaces_and_comments (a_this); ++ ++ status = cr_tknzr_get_next_token (PRIVATE (a_this)->tknzr, &token); ++ ENSURE_PARSING_COND (status == CR_OK ++ && token && token->type == IDENT_TK); ++ ++ medium = token->u.str; ++ token->u.str = NULL; ++ cr_token_destroy (token); ++ token = NULL; ++ ++ if (medium) { ++ media_list = g_list_append (media_list, medium); ++ medium = NULL; ++ } ++ ++ for (; status == CR_OK;) { ++ cr_parser_try_to_skip_spaces_and_comments (a_this); ++ PEEK_NEXT_CHAR (a_this, &next_char); ++ ++ if (next_char == ',') { ++ READ_NEXT_CHAR (a_this, &cur_char); ++ } else { ++ break; ++ } ++ ++ cr_parser_try_to_skip_spaces_and_comments (a_this); ++ ++ status = cr_parser_parse_ident (a_this, &medium); ++ ++ CHECK_PARSING_STATUS (status, FALSE); ++ ++ if (medium) { ++ media_list = g_list_append (media_list, medium); ++ medium = NULL; ++ } ++ } ++ ++ READ_NEXT_CHAR (a_this, &cur_char); ++ ++ ENSURE_PARSING_COND (cur_char == '{'); ++ ++ /* ++ *call the SAC handler api here. ++ */ ++ if (PRIVATE (a_this)->sac_handler ++ && PRIVATE (a_this)->sac_handler->start_media) { ++ PRIVATE (a_this)->sac_handler->start_media ++ (PRIVATE (a_this)->sac_handler, media_list, ++ &location); ++ } ++ ++ cr_parser_try_to_skip_spaces_and_comments (a_this); ++ ++ PRIVATE (a_this)->state = TRY_PARSE_MEDIA_STATE; ++ ++ for (; status == CR_OK;) { ++ status = cr_parser_parse_ruleset (a_this); ++ cr_parser_try_to_skip_spaces_and_comments (a_this); ++ } ++ ++ READ_NEXT_CHAR (a_this, &cur_char); ++ ++ ENSURE_PARSING_COND (cur_char == '}'); ++ ++ /* ++ *call the right SAC handler api here. ++ */ ++ if (PRIVATE (a_this)->sac_handler ++ && PRIVATE (a_this)->sac_handler->end_media) { ++ PRIVATE (a_this)->sac_handler->end_media ++ (PRIVATE (a_this)->sac_handler, media_list); ++ } ++ ++ cr_parser_try_to_skip_spaces_and_comments (a_this); ++ ++ /* ++ *Then, free the data structures passed to ++ *the last call to the SAC handler. ++ */ ++ if (medium) { ++ cr_string_destroy (medium); ++ medium = NULL; ++ } ++ ++ if (media_list) { ++ GList *cur = NULL; ++ ++ for (cur = media_list; cur; cur = cur->next) { ++ cr_string_destroy (cur->data); ++ } ++ ++ g_list_free (media_list); ++ media_list = NULL; ++ } ++ ++ cr_parser_clear_errors (a_this); ++ PRIVATE (a_this)->state = MEDIA_PARSED_STATE; ++ ++ return CR_OK; ++ ++ error: ++ ++ if (token) { ++ cr_token_destroy (token); ++ token = NULL; ++ } ++ ++ if (medium) { ++ cr_string_destroy (medium); ++ medium = NULL; ++ } ++ ++ if (media_list) { ++ GList *cur = NULL; ++ ++ for (cur = media_list; cur; cur = cur->next) { ++ cr_string_destroy (cur->data); ++ } ++ ++ g_list_free (media_list); ++ media_list = NULL; ++ } ++ ++ cr_tknzr_set_cur_pos (PRIVATE (a_this)->tknzr, &init_pos); ++ ++ return status; ++} ++ ++/** ++ * cr_parser_parse_page: ++ *@a_this: the "this pointer" of the current instance of #CRParser. ++ * ++ *Parses '\@page' rule as specified in the css2 spec in appendix D.1: ++ *page ::= PAGE_SYM S* IDENT? pseudo_page? S* ++ *'{' S* declaration [ ';' S* declaration ]* '}' S* ++ * ++ *This function also calls the relevant SAC handlers whenever it ++ *encounters a construction that must ++ *be reported to the calling application. ++ * ++ *Returns CR_OK upon successfull completion, an error code otherwise. ++ */ ++enum CRStatus ++cr_parser_parse_page (CRParser * a_this) ++{ ++ enum CRStatus status = CR_OK; ++ CRInputPos init_pos; ++ CRToken *token = NULL; ++ CRTerm *css_expression = NULL; ++ CRString *page_selector = NULL, ++ *page_pseudo_class = NULL, ++ *property = NULL; ++ gboolean important = TRUE; ++ CRParsingLocation location = {0} ; ++ ++ g_return_val_if_fail (a_this, CR_BAD_PARAM_ERROR); ++ ++ RECORD_INITIAL_POS (a_this, &init_pos); ++ ++ status = cr_tknzr_get_next_token (PRIVATE (a_this)->tknzr, ++ &token) ; ++ ENSURE_PARSING_COND (status == CR_OK ++ && token ++ && token->type == PAGE_SYM_TK); ++ ++ cr_parsing_location_copy (&location, &token->location) ; ++ cr_token_destroy (token); ++ token = NULL; ++ ++ cr_parser_try_to_skip_spaces_and_comments (a_this); ++ ++ status = cr_tknzr_get_next_token (PRIVATE (a_this)->tknzr, &token); ++ ENSURE_PARSING_COND (status == CR_OK && token); ++ ++ if (token->type == IDENT_TK) { ++ page_selector = token->u.str; ++ token->u.str = NULL; ++ cr_token_destroy (token); ++ token = NULL; ++ } else { ++ cr_tknzr_unget_token (PRIVATE (a_this)->tknzr, token); ++ token = NULL; ++ } ++ ++ /* ++ *try to parse pseudo_page ++ */ ++ cr_parser_try_to_skip_spaces_and_comments (a_this); ++ status = cr_tknzr_get_next_token (PRIVATE (a_this)->tknzr, &token); ++ ENSURE_PARSING_COND (status == CR_OK && token); ++ ++ if (token->type == DELIM_TK && token->u.unichar == ':') { ++ cr_token_destroy (token); ++ token = NULL; ++ status = cr_parser_parse_ident (a_this, &page_pseudo_class); ++ CHECK_PARSING_STATUS (status, FALSE); ++ } else { ++ cr_tknzr_unget_token (PRIVATE (a_this)->tknzr, token); ++ token = NULL; ++ } ++ ++ /* ++ *parse_block ++ * ++ */ ++ cr_parser_try_to_skip_spaces_and_comments (a_this); ++ ++ status = cr_tknzr_get_next_token (PRIVATE (a_this)->tknzr, &token); ++ ++ ENSURE_PARSING_COND (status == CR_OK && token ++ && token->type == CBO_TK); ++ ++ cr_token_destroy (token); ++ token = NULL; ++ ++ /* ++ *Call the appropriate SAC handler here. ++ */ ++ if (PRIVATE (a_this)->sac_handler ++ && PRIVATE (a_this)->sac_handler->start_page) { ++ PRIVATE (a_this)->sac_handler->start_page ++ (PRIVATE (a_this)->sac_handler, ++ page_selector, page_pseudo_class, ++ &location); ++ } ++ cr_parser_try_to_skip_spaces_and_comments (a_this); ++ ++ PRIVATE (a_this)->state = TRY_PARSE_PAGE_STATE; ++ ++ status = cr_parser_parse_declaration (a_this, &property, ++ &css_expression, ++ &important); ++ ENSURE_PARSING_COND (status == CR_OK); ++ ++ /* ++ *call the relevant SAC handler here... ++ */ ++ if (PRIVATE (a_this)->sac_handler ++ && PRIVATE (a_this)->sac_handler->property) { ++ if (css_expression) ++ cr_term_ref (css_expression); ++ ++ PRIVATE (a_this)->sac_handler->property ++ (PRIVATE (a_this)->sac_handler, ++ property, css_expression, important); ++ } ++ /* ++ *... and free the data structure passed to that last ++ *SAC handler. ++ */ ++ if (property) { ++ cr_string_destroy (property); ++ property = NULL; ++ } ++ if (css_expression) { ++ cr_term_unref (css_expression); ++ css_expression = NULL; ++ } ++ ++ for (;;) { ++ /*parse the other ';' separated declarations */ ++ if (token) { ++ cr_token_destroy (token); ++ token = NULL; ++ } ++ status = cr_tknzr_get_next_token ++ (PRIVATE (a_this)->tknzr, &token); ++ ++ ENSURE_PARSING_COND (status == CR_OK && token); ++ ++ if (token->type != SEMICOLON_TK) { ++ cr_tknzr_unget_token ++ (PRIVATE (a_this)->tknzr, ++ token); ++ token = NULL ; ++ break; ++ } ++ ++ cr_token_destroy (token); ++ token = NULL; ++ cr_parser_try_to_skip_spaces_and_comments (a_this); ++ ++ status = cr_parser_parse_declaration (a_this, &property, ++ &css_expression, ++ &important); ++ if (status != CR_OK) ++ break ; ++ ++ /* ++ *call the relevant SAC handler here... ++ */ ++ if (PRIVATE (a_this)->sac_handler ++ && PRIVATE (a_this)->sac_handler->property) { ++ cr_term_ref (css_expression); ++ PRIVATE (a_this)->sac_handler->property ++ (PRIVATE (a_this)->sac_handler, ++ property, css_expression, important); ++ } ++ /* ++ *... and free the data structure passed to that last ++ *SAC handler. ++ */ ++ if (property) { ++ cr_string_destroy (property); ++ property = NULL; ++ } ++ if (css_expression) { ++ cr_term_unref (css_expression); ++ css_expression = NULL; ++ } ++ } ++ cr_parser_try_to_skip_spaces_and_comments ++ (a_this) ; ++ if (token) { ++ cr_token_destroy (token) ; ++ token = NULL ; ++ } ++ ++ status = cr_tknzr_get_next_token ++ (PRIVATE (a_this)->tknzr, &token); ++ ENSURE_PARSING_COND (status == CR_OK ++ && token ++ && token->type == CBC_TK) ; ++ cr_token_destroy (token) ; ++ token = NULL ; ++ /* ++ *call the relevant SAC handler here. ++ */ ++ if (PRIVATE (a_this)->sac_handler ++ && PRIVATE (a_this)->sac_handler->end_page) { ++ PRIVATE (a_this)->sac_handler->end_page ++ (PRIVATE (a_this)->sac_handler, ++ page_selector, page_pseudo_class); ++ } ++ ++ if (page_selector) { ++ cr_string_destroy (page_selector); ++ page_selector = NULL; ++ } ++ ++ if (page_pseudo_class) { ++ cr_string_destroy (page_pseudo_class); ++ page_pseudo_class = NULL; ++ } ++ ++ cr_parser_try_to_skip_spaces_and_comments (a_this); ++ ++ /*here goes the former implem of this function ... */ ++ ++ cr_parser_clear_errors (a_this); ++ PRIVATE (a_this)->state = PAGE_PARSED_STATE; ++ ++ return CR_OK; ++ ++ error: ++ if (token) { ++ cr_token_destroy (token); ++ token = NULL; ++ } ++ if (page_selector) { ++ cr_string_destroy (page_selector); ++ page_selector = NULL; ++ } ++ if (page_pseudo_class) { ++ cr_string_destroy (page_pseudo_class); ++ page_pseudo_class = NULL; ++ } ++ if (property) { ++ cr_string_destroy (property); ++ property = NULL; ++ } ++ if (css_expression) { ++ cr_term_destroy (css_expression); ++ css_expression = NULL; ++ } ++ cr_tknzr_set_cur_pos (PRIVATE (a_this)->tknzr, &init_pos); ++ return status; ++} ++ ++/** ++ * cr_parser_parse_charset: ++ *@a_this: the "this pointer" of the current instance of #CRParser. ++ *@a_value: out parameter. The actual parsed value of the charset ++ *declararation. Note that for safety check reasons, *a_value must be ++ *set to NULL. ++ *@a_charset_sym_location: the parsing location of the charset rule ++ * ++ *Parses a charset declaration as defined implictly by the css2 spec in ++ *appendix D.1: ++ *charset ::= CHARSET_SYM S* STRING S* ';' ++ * ++ *Returns CR_OK upon successfull completion, an error code otherwise. ++ */ ++enum CRStatus ++cr_parser_parse_charset (CRParser * a_this, CRString ** a_value, ++ CRParsingLocation *a_charset_sym_location) ++{ ++ enum CRStatus status = CR_OK; ++ CRInputPos init_pos; ++ CRToken *token = NULL; ++ CRString *charset_str = NULL; ++ ++ g_return_val_if_fail (a_this && a_value ++ && (*a_value == NULL), ++ CR_BAD_PARAM_ERROR); ++ ++ RECORD_INITIAL_POS (a_this, &init_pos); ++ ++ status = cr_tknzr_get_next_token (PRIVATE (a_this)->tknzr, &token); ++ ++ ENSURE_PARSING_COND (status == CR_OK ++ && token && token->type == CHARSET_SYM_TK); ++ if (a_charset_sym_location) { ++ cr_parsing_location_copy (a_charset_sym_location, ++ &token->location) ; ++ } ++ cr_token_destroy (token); ++ token = NULL; ++ ++ PRIVATE (a_this)->state = TRY_PARSE_CHARSET_STATE; ++ ++ cr_parser_try_to_skip_spaces_and_comments (a_this); ++ ++ status = cr_tknzr_get_next_token (PRIVATE (a_this)->tknzr, &token); ++ ENSURE_PARSING_COND (status == CR_OK ++ && token && token->type == STRING_TK); ++ charset_str = token->u.str; ++ token->u.str = NULL; ++ cr_token_destroy (token); ++ token = NULL; ++ ++ cr_parser_try_to_skip_spaces_and_comments (a_this); ++ ++ status = cr_tknzr_get_next_token (PRIVATE (a_this)->tknzr, &token); ++ ++ ENSURE_PARSING_COND (status == CR_OK ++ && token && token->type == SEMICOLON_TK); ++ cr_token_destroy (token); ++ token = NULL; ++ ++ if (charset_str) { ++ *a_value = charset_str; ++ charset_str = NULL; ++ } ++ ++ PRIVATE (a_this)->state = CHARSET_PARSED_STATE; ++ return CR_OK; ++ ++ error: ++ ++ if (token) { ++ cr_token_destroy (token); ++ token = NULL; ++ } ++ ++ if (*a_value) { ++ cr_string_destroy (*a_value); ++ *a_value = NULL; ++ } ++ ++ if (charset_str) { ++ cr_string_destroy (charset_str); ++ charset_str = NULL; ++ } ++ ++ cr_tknzr_set_cur_pos (PRIVATE (a_this)->tknzr, &init_pos); ++ ++ return status; ++} ++ ++/** ++ * cr_parser_parse_font_face: ++ *@a_this: the current instance of #CRParser. ++ * ++ *Parses the "\@font-face" rule specified in the css1 spec in ++ *appendix D.1: ++ * ++ *font_face ::= FONT_FACE_SYM S* ++ *'{' S* declaration [ ';' S* declaration ]* '}' S* ++ * ++ *This function will call SAC handlers whenever it is necessary. ++ * ++ *Returns CR_OK upon successfull completion, an error code otherwise. ++ */ ++enum CRStatus ++cr_parser_parse_font_face (CRParser * a_this) ++{ ++ enum CRStatus status = CR_ERROR; ++ CRInputPos init_pos; ++ CRString *property = NULL; ++ CRTerm *css_expression = NULL; ++ CRToken *token = NULL; ++ gboolean important = FALSE; ++ guint32 next_char = 0, ++ cur_char = 0; ++ CRParsingLocation location = {0} ; ++ ++ g_return_val_if_fail (a_this, CR_BAD_PARAM_ERROR); ++ ++ RECORD_INITIAL_POS (a_this, &init_pos); ++ ++ status = cr_tknzr_get_next_token (PRIVATE (a_this)->tknzr, &token); ++ ENSURE_PARSING_COND (status == CR_OK ++ && token ++ && token->type == FONT_FACE_SYM_TK); ++ ++ cr_parser_try_to_skip_spaces_and_comments (a_this); ++ if (token) { ++ cr_parsing_location_copy (&location, ++ &token->location) ; ++ cr_token_destroy (token); ++ token = NULL; ++ } ++ status = cr_tknzr_get_next_token (PRIVATE (a_this)->tknzr, ++ &token); ++ ENSURE_PARSING_COND (status == CR_OK && token ++ && token->type == CBO_TK); ++ if (token) { ++ cr_token_destroy (token); ++ token = NULL; ++ } ++ /* ++ *here, call the relevant SAC handler. ++ */ ++ if (PRIVATE (a_this)->sac_handler ++ && PRIVATE (a_this)->sac_handler->start_font_face) { ++ PRIVATE (a_this)->sac_handler->start_font_face ++ (PRIVATE (a_this)->sac_handler, &location); ++ } ++ PRIVATE (a_this)->state = TRY_PARSE_FONT_FACE_STATE; ++ /* ++ *and resume the parsing. ++ */ ++ cr_parser_try_to_skip_spaces_and_comments (a_this); ++ status = cr_parser_parse_declaration (a_this, &property, ++ &css_expression, &important); ++ if (status == CR_OK) { ++ /* ++ *here, call the relevant SAC handler. ++ */ ++ cr_term_ref (css_expression); ++ if (PRIVATE (a_this)->sac_handler && ++ PRIVATE (a_this)->sac_handler->property) { ++ PRIVATE (a_this)->sac_handler->property ++ (PRIVATE (a_this)->sac_handler, ++ property, css_expression, important); ++ } ++ ENSURE_PARSING_COND (css_expression && property); ++ } ++ /*free the data structures allocated during last parsing. */ ++ if (property) { ++ cr_string_destroy (property); ++ property = NULL; ++ } ++ if (css_expression) { ++ cr_term_unref (css_expression); ++ css_expression = NULL; ++ } ++ for (;;) { ++ PEEK_NEXT_CHAR (a_this, &next_char); ++ if (next_char == ';') { ++ READ_NEXT_CHAR (a_this, &cur_char); ++ } else { ++ break; ++ } ++ cr_parser_try_to_skip_spaces_and_comments (a_this); ++ status = cr_parser_parse_declaration (a_this, ++ &property, ++ &css_expression, ++ &important); ++ if (status != CR_OK) ++ break; ++ /* ++ *here, call the relevant SAC handler. ++ */ ++ cr_term_ref (css_expression); ++ if (PRIVATE (a_this)->sac_handler->property) { ++ PRIVATE (a_this)->sac_handler->property ++ (PRIVATE (a_this)->sac_handler, ++ property, css_expression, important); ++ } ++ /* ++ *Then, free the data structures allocated during ++ *last parsing. ++ */ ++ if (property) { ++ cr_string_destroy (property); ++ property = NULL; ++ } ++ if (css_expression) { ++ cr_term_unref (css_expression); ++ css_expression = NULL; ++ } ++ } ++ cr_parser_try_to_skip_spaces_and_comments (a_this); ++ READ_NEXT_CHAR (a_this, &cur_char); ++ ENSURE_PARSING_COND (cur_char == '}'); ++ /* ++ *here, call the relevant SAC handler. ++ */ ++ if (PRIVATE (a_this)->sac_handler->end_font_face) { ++ PRIVATE (a_this)->sac_handler->end_font_face ++ (PRIVATE (a_this)->sac_handler); ++ } ++ cr_parser_try_to_skip_spaces_and_comments (a_this); ++ ++ if (token) { ++ cr_token_destroy (token); ++ token = NULL; ++ } ++ cr_parser_clear_errors (a_this); ++ PRIVATE (a_this)->state = FONT_FACE_PARSED_STATE; ++ return CR_OK; ++ ++ error: ++ if (token) { ++ cr_token_destroy (token); ++ token = NULL; ++ } ++ if (property) { ++ cr_string_destroy (property); ++ property = NULL; ++ } ++ if (css_expression) { ++ cr_term_destroy (css_expression); ++ css_expression = NULL; ++ } ++ cr_tknzr_set_cur_pos (PRIVATE (a_this)->tknzr, &init_pos); ++ return status; ++} ++ ++/** ++ * cr_parser_parse: ++ *@a_this: the current instance of #CRParser. ++ * ++ *Parses the data that comes from the ++ *input previously associated to the current instance of ++ *#CRParser. ++ * ++ *Returns CR_OK upon succesful completion, an error code otherwise. ++ */ ++enum CRStatus ++cr_parser_parse (CRParser * a_this) ++{ ++ enum CRStatus status = CR_ERROR; ++ ++ g_return_val_if_fail (a_this && PRIVATE (a_this) ++ && PRIVATE (a_this)->tknzr, CR_BAD_PARAM_ERROR); ++ ++ if (PRIVATE (a_this)->use_core_grammar == FALSE) { ++ status = cr_parser_parse_stylesheet (a_this); ++ } else { ++ status = cr_parser_parse_stylesheet_core (a_this); ++ } ++ ++ return status; ++} ++ ++/** ++ * cr_parser_set_tknzr: ++ * @a_this: the current instance of #CRParser; ++ * @a_tknzr: the new tokenizer. ++ * ++ * Returns CR_OK upon successful completion, an error code otherwise. ++ */ ++enum CRStatus ++cr_parser_set_tknzr (CRParser * a_this, CRTknzr * a_tknzr) ++{ ++ g_return_val_if_fail (a_this && PRIVATE (a_this), CR_BAD_PARAM_ERROR); ++ ++ if (PRIVATE (a_this)->tknzr) { ++ cr_tknzr_unref (PRIVATE (a_this)->tknzr); ++ } ++ ++ PRIVATE (a_this)->tknzr = a_tknzr; ++ ++ if (a_tknzr) ++ cr_tknzr_ref (a_tknzr); ++ ++ return CR_OK; ++} ++ ++/** ++ * cr_parser_get_tknzr: ++ *@a_this: the current instance of #CRParser ++ *@a_tknzr: out parameter. The returned tokenizer ++ * ++ *Getter of the parser's underlying tokenizer ++ * ++ *Returns CR_OK upon succesful completion, an error code ++ *otherwise ++ */ ++enum CRStatus ++cr_parser_get_tknzr (CRParser * a_this, CRTknzr ** a_tknzr) ++{ ++ g_return_val_if_fail (a_this && PRIVATE (a_this) ++ && a_tknzr, CR_BAD_PARAM_ERROR); ++ ++ *a_tknzr = PRIVATE (a_this)->tknzr; ++ return CR_OK; ++} ++ ++/** ++ * cr_parser_get_parsing_location: ++ *@a_this: the current instance of #CRParser ++ *@a_loc: the parsing location to get. ++ * ++ *Gets the current parsing location. ++ * ++ *Returns CR_OK upon succesful completion, an error code ++ *otherwise. ++ */ ++enum CRStatus ++cr_parser_get_parsing_location (CRParser const *a_this, ++ CRParsingLocation *a_loc) ++{ ++ g_return_val_if_fail (a_this ++ && PRIVATE (a_this) ++ && a_loc, CR_BAD_PARAM_ERROR) ; ++ ++ return cr_tknzr_get_parsing_location ++ (PRIVATE (a_this)->tknzr, a_loc) ; ++} ++ ++/** ++ * cr_parser_parse_buf: ++ *@a_this: the current instance of #CRparser ++ *@a_buf: the input buffer ++ *@a_len: the length of the input buffer ++ *@a_enc: the encoding of the buffer ++ * ++ *Parses a stylesheet from a buffer ++ * ++ *Returns CR_OK upon successful completion, an error code otherwise. ++ */ ++enum CRStatus ++cr_parser_parse_buf (CRParser * a_this, ++ const guchar * a_buf, ++ gulong a_len, enum CREncoding a_enc) ++{ ++ enum CRStatus status = CR_ERROR; ++ CRTknzr *tknzr = NULL; ++ ++ g_return_val_if_fail (a_this && PRIVATE (a_this) ++ && a_buf, CR_BAD_PARAM_ERROR); ++ ++ tknzr = cr_tknzr_new_from_buf ((guchar*)a_buf, a_len, a_enc, FALSE); ++ ++ g_return_val_if_fail (tknzr != NULL, CR_ERROR); ++ ++ status = cr_parser_set_tknzr (a_this, tknzr); ++ g_return_val_if_fail (status == CR_OK, CR_ERROR); ++ ++ status = cr_parser_parse (a_this); ++ ++ return status; ++} ++ ++/** ++ * cr_parser_destroy: ++ *@a_this: the current instance of #CRParser to ++ *destroy. ++ * ++ *Destroys the current instance ++ *of #CRParser. ++ */ ++void ++cr_parser_destroy (CRParser * a_this) ++{ ++ g_return_if_fail (a_this && PRIVATE (a_this)); ++ ++ if (PRIVATE (a_this)->tknzr) { ++ if (cr_tknzr_unref (PRIVATE (a_this)->tknzr) == TRUE) ++ PRIVATE (a_this)->tknzr = NULL; ++ } ++ ++ if (PRIVATE (a_this)->sac_handler) { ++ cr_doc_handler_unref (PRIVATE (a_this)->sac_handler); ++ PRIVATE (a_this)->sac_handler = NULL; ++ } ++ ++ if (PRIVATE (a_this)->err_stack) { ++ cr_parser_clear_errors (a_this); ++ PRIVATE (a_this)->err_stack = NULL; ++ } ++ ++ if (PRIVATE (a_this)) { ++ g_free (PRIVATE (a_this)); ++ PRIVATE (a_this) = NULL; ++ } ++ ++ if (a_this) { ++ g_free (a_this); ++ a_this = NULL; /*useless. Just for the sake of coherence */ ++ } ++} +diff --git a/src/st/croco/cr-parser.h b/src/st/croco/cr-parser.h +new file mode 100644 +index 000000000..6dce9439e +--- /dev/null ++++ b/src/st/croco/cr-parser.h +@@ -0,0 +1,128 @@ ++/* -*- Mode: C; indent-tabs-mode:nil; c-basic-offset: 8-*- */ ++ ++/* ++ * This file is part of The Croco Library ++ * ++ * 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 ++ * See COPYRIGHTS file for copyrights information. ++ */ ++ ++#ifndef __CR_PARSER_H__ ++#define __CR_PARSER_H__ ++ ++#include ++#include "cr-input.h" ++#include "cr-tknzr.h" ++#include "cr-utils.h" ++#include "cr-doc-handler.h" ++ ++G_BEGIN_DECLS ++ ++/** ++ *@file ++ *The declaration file ++ *of the #CRParser class. ++ */ ++typedef struct _CRParser CRParser ; ++typedef struct _CRParserPriv CRParserPriv ; ++ ++ ++/** ++ *The implementation of ++ *the SAC parser. ++ *The Class is opaque ++ *and must be manipulated through ++ *the provided methods. ++ */ ++struct _CRParser { ++ CRParserPriv *priv ; ++} ; ++ ++ ++CRParser * cr_parser_new (CRTknzr *a_tknzr) ; ++ ++CRParser * cr_parser_new_from_buf (guchar *a_buf, gulong a_len, ++ enum CREncoding a_enc, ++ gboolean a_free_buf) ; ++ ++CRParser * cr_parser_new_from_file (const guchar *a_file_uri, ++ enum CREncoding a_enc) ; ++ ++CRParser * cr_parser_new_from_input (CRInput *a_input) ; ++ ++enum CRStatus cr_parser_set_tknzr (CRParser *a_this, CRTknzr *a_tknzr) ; ++ ++enum CRStatus cr_parser_get_tknzr (CRParser *a_this, CRTknzr **a_tknzr) ; ++ ++enum CRStatus cr_parser_get_parsing_location (CRParser const *a_this, CRParsingLocation *a_loc) ; ++ ++enum CRStatus cr_parser_try_to_skip_spaces_and_comments (CRParser *a_this) ; ++ ++ ++enum CRStatus cr_parser_set_sac_handler (CRParser *a_this, ++ CRDocHandler *a_handler) ; ++ ++enum CRStatus cr_parser_get_sac_handler (CRParser *a_this, ++ CRDocHandler **a_handler) ; ++ ++enum CRStatus cr_parser_set_use_core_grammar (CRParser *a_this, ++ gboolean a_use_core_grammar) ; ++enum CRStatus cr_parser_get_use_core_grammar (CRParser const *a_this, ++ gboolean *a_use_core_grammar) ; ++ ++enum CRStatus cr_parser_parse (CRParser *a_this) ; ++ ++enum CRStatus cr_parser_parse_file (CRParser *a_this, ++ const guchar *a_file_uri, ++ enum CREncoding a_enc) ; ++ ++enum CRStatus cr_parser_parse_buf (CRParser *a_this, const guchar *a_buf, ++ gulong a_len, enum CREncoding a_enc) ; ++ ++enum CRStatus cr_parser_set_default_sac_handler (CRParser *a_this) ; ++ ++enum CRStatus cr_parser_parse_term (CRParser *a_this, CRTerm **a_term) ; ++ ++enum CRStatus cr_parser_parse_expr (CRParser *a_this, CRTerm **a_expr) ; ++ ++enum CRStatus cr_parser_parse_prio (CRParser *a_this, CRString **a_prio) ; ++ ++enum CRStatus cr_parser_parse_declaration (CRParser *a_this, CRString **a_property, ++ CRTerm **a_expr, gboolean *a_important) ; ++ ++enum CRStatus cr_parser_parse_statement_core (CRParser *a_this) ; ++ ++enum CRStatus cr_parser_parse_ruleset (CRParser *a_this) ; ++ ++enum CRStatus cr_parser_parse_import (CRParser *a_this, GList ** a_media_list, ++ CRString **a_import_string, ++ CRParsingLocation *a_location) ; ++ ++enum CRStatus cr_parser_parse_media (CRParser *a_this) ; ++ ++enum CRStatus cr_parser_parse_page (CRParser *a_this) ; ++ ++enum CRStatus cr_parser_parse_charset (CRParser *a_this, CRString **a_value, ++ CRParsingLocation *a_charset_sym_location) ; ++ ++enum CRStatus cr_parser_parse_font_face (CRParser *a_this) ; ++ ++void cr_parser_destroy (CRParser *a_this) ; ++ ++G_END_DECLS ++ ++#endif /*__CR_PARSER_H__*/ +diff --git a/src/st/croco/cr-parsing-location.c b/src/st/croco/cr-parsing-location.c +new file mode 100644 +index 000000000..4fe4acc30 +--- /dev/null ++++ b/src/st/croco/cr-parsing-location.c +@@ -0,0 +1,172 @@ ++/* -*- Mode: C; indent-tabs-mode: nil; c-basic-offset: 8 -*- */ ++ ++/* ++ * This file is part of The Croco Library ++ * ++ * 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. ++ * See the COPYRIGHTS file for copyright information. ++ */ ++ ++#include ++#include "cr-parsing-location.h" ++ ++/** ++ *@CRParsingLocation: ++ * ++ *Definition of the #CRparsingLocation class. ++ */ ++ ++ ++/** ++ * cr_parsing_location_new: ++ *Instanciates a new parsing location. ++ * ++ *Returns the newly instanciated #CRParsingLocation. ++ *Must be freed by cr_parsing_location_destroy() ++ */ ++CRParsingLocation * ++cr_parsing_location_new (void) ++{ ++ CRParsingLocation * result = NULL ; ++ ++ result = g_try_malloc (sizeof (CRParsingLocation)) ; ++ if (!result) { ++ cr_utils_trace_info ("Out of memory error") ; ++ return NULL ; ++ } ++ cr_parsing_location_init (result) ; ++ return result ; ++} ++ ++/** ++ * cr_parsing_location_init: ++ *@a_this: the current instance of #CRParsingLocation. ++ * ++ *Initializes the an instance of #CRparsingLocation. ++ * ++ *Returns CR_OK upon succesful completion, an error code otherwise. ++ */ ++enum CRStatus ++cr_parsing_location_init (CRParsingLocation *a_this) ++{ ++ g_return_val_if_fail (a_this, CR_BAD_PARAM_ERROR) ; ++ ++ memset (a_this, 0, sizeof (CRParsingLocation)) ; ++ return CR_OK ; ++} ++ ++/** ++ * cr_parsing_location_copy: ++ *@a_to: the destination of the copy. ++ *Must be allocated by the caller. ++ *@a_from: the source of the copy. ++ * ++ *Copies an instance of CRParsingLocation into another one. ++ * ++ *Returns CR_OK upon succesful completion, an error code ++ *otherwise. ++ */ ++enum CRStatus ++cr_parsing_location_copy (CRParsingLocation *a_to, ++ CRParsingLocation const *a_from) ++{ ++ g_return_val_if_fail (a_to && a_from, CR_BAD_PARAM_ERROR) ; ++ ++ memcpy (a_to, a_from, sizeof (CRParsingLocation)) ; ++ return CR_OK ; ++} ++ ++/** ++ * cr_parsing_location_to_string: ++ *@a_this: the current instance of #CRParsingLocation. ++ *@a_mask: a bitmap that defines which parts of the ++ *parsing location are to be serialized (line, column or byte offset) ++ * ++ *Returns the serialized string or NULL in case of an error. ++ */ ++gchar * ++cr_parsing_location_to_string (CRParsingLocation const *a_this, ++ enum CRParsingLocationSerialisationMask a_mask) ++{ ++ GString *result = NULL ; ++ gchar *str = NULL ; ++ ++ g_return_val_if_fail (a_this, NULL) ; ++ ++ if (!a_mask) { ++ a_mask = DUMP_LINE | DUMP_COLUMN | DUMP_BYTE_OFFSET ; ++ } ++ result =g_string_new (NULL) ; ++ if (!result) ++ return NULL ; ++ if (a_mask & DUMP_LINE) { ++ g_string_append_printf (result, "line:%d ", ++ a_this->line) ; ++ } ++ if (a_mask & DUMP_COLUMN) { ++ g_string_append_printf (result, "column:%d ", ++ a_this->column) ; ++ } ++ if (a_mask & DUMP_BYTE_OFFSET) { ++ g_string_append_printf (result, "byte offset:%d ", ++ a_this->byte_offset) ; ++ } ++ if (result->len) { ++ str = result->str ; ++ g_string_free (result, FALSE) ; ++ } else { ++ g_string_free (result, TRUE) ; ++ } ++ return str ; ++} ++ ++/** ++ * cr_parsing_location_dump: ++ * @a_this: current instance of #CRParsingLocation ++ * @a_mask: the serialization mask. ++ * @a_fp: the file pointer to dump the parsing location to. ++ */ ++void ++cr_parsing_location_dump (CRParsingLocation const *a_this, ++ enum CRParsingLocationSerialisationMask a_mask, ++ FILE *a_fp) ++{ ++ gchar *str = NULL ; ++ ++ g_return_if_fail (a_this && a_fp) ; ++ str = cr_parsing_location_to_string (a_this, a_mask) ; ++ if (str) { ++ fprintf (a_fp, "%s", str) ; ++ g_free (str) ; ++ str = NULL ; ++ } ++} ++ ++/** ++ * cr_parsing_location_destroy: ++ *@a_this: the current instance of #CRParsingLocation. Must ++ *have been allocated with cr_parsing_location_new(). ++ * ++ *Destroys the current instance of #CRParsingLocation ++ */ ++void ++cr_parsing_location_destroy (CRParsingLocation *a_this) ++{ ++ g_return_if_fail (a_this) ; ++ g_free (a_this) ; ++} ++ +diff --git a/src/st/croco/cr-parsing-location.h b/src/st/croco/cr-parsing-location.h +new file mode 100644 +index 000000000..b8064a560 +--- /dev/null ++++ b/src/st/croco/cr-parsing-location.h +@@ -0,0 +1,70 @@ ++/* -*- Mode: C; indent-tabs-mode: nil; c-basic-offset: 8 -*- */ ++ ++/* ++ * This file is part of The Croco Library ++ * ++ * 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. ++ * See the COPYRIGHTS file for copyright information. ++ */ ++ ++#ifndef __CR_PARSING_LOCATION_H__ ++#define __CR_PARSING_LOCATION_H__ ++ ++#include "cr-utils.h" ++ ++G_BEGIN_DECLS ++ ++/** ++ *@file ++ *The declaration of the CRParsingLocation ++ *object. This object keeps track of line/column/byte offset/ ++ *at which the parsing of a given CSS construction appears. ++ */ ++ ++typedef struct _CRParsingLocation CRParsingLocation; ++struct _CRParsingLocation { ++ guint line ; ++ guint column ; ++ guint byte_offset ; ++} ; ++ ++ ++enum CRParsingLocationSerialisationMask { ++ DUMP_LINE = 1, ++ DUMP_COLUMN = 1 << 1, ++ DUMP_BYTE_OFFSET = 1 << 2 ++} ; ++ ++CRParsingLocation * cr_parsing_location_new (void) ; ++ ++enum CRStatus cr_parsing_location_init (CRParsingLocation *a_this) ; ++ ++enum CRStatus cr_parsing_location_copy (CRParsingLocation *a_to, ++ CRParsingLocation const *a_from) ; ++ ++gchar * cr_parsing_location_to_string (CRParsingLocation const *a_this, ++ enum CRParsingLocationSerialisationMask a_mask) ; ++void cr_parsing_location_dump (CRParsingLocation const *a_this, ++ enum CRParsingLocationSerialisationMask a_mask, ++ FILE *a_fp) ; ++ ++void cr_parsing_location_destroy (CRParsingLocation *a_this) ; ++ ++ ++ ++G_END_DECLS ++#endif +diff --git a/src/st/croco/cr-prop-list.c b/src/st/croco/cr-prop-list.c +new file mode 100644 +index 000000000..70a04f337 +--- /dev/null ++++ b/src/st/croco/cr-prop-list.c +@@ -0,0 +1,404 @@ ++/* ++ * This file is part of The Croco Library ++ * ++ * 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 ++ * See COPYRIGHTS file for copyrights information. ++ */ ++ ++#include ++#include "cr-prop-list.h" ++ ++#define PRIVATE(a_obj) (a_obj)->priv ++ ++struct _CRPropListPriv { ++ CRString *prop; ++ CRDeclaration *decl; ++ CRPropList *next; ++ CRPropList *prev; ++}; ++ ++static CRPropList *cr_prop_list_allocate (void); ++ ++/** ++ *Default allocator of CRPropList ++ *@return the newly allocated CRPropList or NULL ++ *if an error arises. ++ */ ++static CRPropList * ++cr_prop_list_allocate (void) ++{ ++ CRPropList *result = NULL; ++ ++ result = g_try_malloc (sizeof (CRPropList)); ++ if (!result) { ++ cr_utils_trace_info ("could not allocate CRPropList"); ++ return NULL; ++ } ++ memset (result, 0, sizeof (CRPropList)); ++ PRIVATE (result) = g_try_malloc (sizeof (CRPropListPriv)); ++ if (!result) { ++ cr_utils_trace_info ("could not allocate CRPropListPriv"); ++ g_free (result); ++ return NULL; ++ } ++ memset (PRIVATE (result), 0, sizeof (CRPropListPriv)); ++ return result; ++} ++ ++/**************** ++ *public methods ++ ***************/ ++ ++/** ++ * cr_prop_list_append: ++ *@a_this: the current instance of #CRPropList ++ *@a_to_append: the property list to append ++ * ++ *Appends a property list to the current one. ++ * ++ *Returns the resulting prop list, or NULL if an error ++ *occurred ++ */ ++CRPropList * ++cr_prop_list_append (CRPropList * a_this, CRPropList * a_to_append) ++{ ++ CRPropList *cur = NULL; ++ ++ g_return_val_if_fail (a_to_append, NULL); ++ ++ if (!a_this) ++ return a_to_append; ++ ++ /*go fetch the last element of the list */ ++ for (cur = a_this; ++ cur && PRIVATE (cur) && PRIVATE (cur)->next; ++ cur = PRIVATE (cur)->next) ; ++ g_return_val_if_fail (cur, NULL); ++ PRIVATE (cur)->next = a_to_append; ++ PRIVATE (a_to_append)->prev = cur; ++ return a_this; ++} ++ ++/** ++ * cr_prop_list_append2: ++ *Appends a pair of prop/declaration to ++ *the current prop list. ++ *@a_this: the current instance of #CRPropList ++ *@a_prop: the property to consider ++ *@a_decl: the declaration to consider ++ * ++ *Returns the resulting property list, or NULL in case ++ *of an error. ++ */ ++CRPropList * ++cr_prop_list_append2 (CRPropList * a_this, ++ CRString * a_prop, ++ CRDeclaration * a_decl) ++{ ++ CRPropList *list = NULL, ++ *result = NULL; ++ ++ g_return_val_if_fail (a_prop && a_decl, NULL); ++ ++ list = cr_prop_list_allocate (); ++ g_return_val_if_fail (list && PRIVATE (list), NULL); ++ ++ PRIVATE (list)->prop = a_prop; ++ PRIVATE (list)->decl = a_decl; ++ ++ result = cr_prop_list_append (a_this, list); ++ return result; ++} ++ ++/** ++ * cr_prop_list_prepend: ++ *@a_this: the current instance of #CRPropList ++ *@a_to_prepend: the new list to prepend. ++ * ++ *Prepends a list to the current list ++ *Returns the new properties list. ++ */ ++CRPropList * ++cr_prop_list_prepend (CRPropList * a_this, CRPropList * a_to_prepend) ++{ ++ CRPropList *cur = NULL; ++ ++ g_return_val_if_fail (a_to_prepend, NULL); ++ ++ if (!a_this) ++ return a_to_prepend; ++ ++ for (cur = a_to_prepend; cur && PRIVATE (cur)->next; ++ cur = PRIVATE (cur)->next) ; ++ g_return_val_if_fail (cur, NULL); ++ PRIVATE (cur)->next = a_this; ++ PRIVATE (a_this)->prev = cur; ++ return a_to_prepend; ++} ++ ++/** ++ * cr_prop_list_prepend2: ++ *@a_this: the current instance of #CRPropList ++ *@a_prop_name: property name to append ++ *@a_decl: the property value to append. ++ * ++ *Prepends a propertie to a list of properties ++ * ++ *Returns the new property list. ++ */ ++CRPropList * ++cr_prop_list_prepend2 (CRPropList * a_this, ++ CRString * a_prop_name, CRDeclaration * a_decl) ++{ ++ CRPropList *list = NULL, ++ *result = NULL; ++ ++ g_return_val_if_fail (a_this && PRIVATE (a_this) ++ && a_prop_name && a_decl, NULL); ++ ++ list = cr_prop_list_allocate (); ++ g_return_val_if_fail (list, NULL); ++ PRIVATE (list)->prop = a_prop_name; ++ PRIVATE (list)->decl = a_decl; ++ result = cr_prop_list_prepend (a_this, list); ++ return result; ++} ++ ++/** ++ * cr_prop_list_set_prop: ++ *@a_this: the current instance of #CRPropList ++ *@a_prop: the property to set ++ * ++ *Sets the property of a CRPropList ++ */ ++enum CRStatus ++cr_prop_list_set_prop (CRPropList * a_this, CRString * a_prop) ++{ ++ g_return_val_if_fail (a_this && PRIVATE (a_this) ++ && a_prop, CR_BAD_PARAM_ERROR); ++ ++ PRIVATE (a_this)->prop = a_prop; ++ return CR_OK; ++} ++ ++/** ++ * cr_prop_list_get_prop: ++ *@a_this: the current instance of #CRPropList ++ *@a_prop: out parameter. The returned property ++ * ++ *Getter of the property associated to the current instance ++ *of #CRPropList ++ * ++ *Returns CR_OK upon successful completion, an error code ++ *otherwise. ++ */ ++enum CRStatus ++cr_prop_list_get_prop (CRPropList const * a_this, CRString ** a_prop) ++{ ++ g_return_val_if_fail (a_this && PRIVATE (a_this) ++ && a_prop, CR_BAD_PARAM_ERROR); ++ ++ *a_prop = PRIVATE (a_this)->prop; ++ return CR_OK; ++} ++ ++/** ++ * cr_prop_list_set_decl: ++ * @a_this: the current instance of #CRPropList ++ * @a_decl: the new property value. ++ * ++ * Returns CR_OK upon successful completion, an error code otherwise. ++ */ ++enum CRStatus ++cr_prop_list_set_decl (CRPropList * a_this, CRDeclaration * a_decl) ++{ ++ g_return_val_if_fail (a_this && PRIVATE (a_this) ++ && a_decl, CR_BAD_PARAM_ERROR); ++ ++ PRIVATE (a_this)->decl = a_decl; ++ return CR_OK; ++} ++ ++/** ++ * cr_prop_list_get_decl: ++ * @a_this: the current instance of #CRPropList ++ * @a_decl: out parameter. The property value ++ * ++ * Returns CR_OK upon successful completion. ++ */ ++enum CRStatus ++cr_prop_list_get_decl (CRPropList const * a_this, CRDeclaration ** a_decl) ++{ ++ g_return_val_if_fail (a_this && PRIVATE (a_this) ++ && a_decl, CR_BAD_PARAM_ERROR); ++ ++ *a_decl = PRIVATE (a_this)->decl; ++ return CR_OK; ++} ++ ++/** ++ * cr_prop_list_lookup_prop: ++ *@a_this: the current instance of #CRPropList ++ *@a_prop: the property to lookup ++ *@a_prop_list: out parameter. The property/declaration ++ *pair found (if and only if the function returned code if CR_OK) ++ * ++ *Lookup a given property/declaration pair ++ * ++ *Returns CR_OK if a prop/decl pair has been found, ++ *CR_VALUE_NOT_FOUND_ERROR if not, or an error code if something ++ *bad happens. ++ */ ++enum CRStatus ++cr_prop_list_lookup_prop (CRPropList * a_this, ++ CRString * a_prop, CRPropList ** a_pair) ++{ ++ CRPropList *cur = NULL; ++ ++ g_return_val_if_fail (a_prop && a_pair, CR_BAD_PARAM_ERROR); ++ ++ if (!a_this) ++ return CR_VALUE_NOT_FOUND_ERROR; ++ ++ g_return_val_if_fail (PRIVATE (a_this), CR_BAD_PARAM_ERROR); ++ ++ for (cur = a_this; cur; cur = PRIVATE (cur)->next) { ++ if (PRIVATE (cur)->prop ++ && PRIVATE (cur)->prop->stryng ++ && PRIVATE (cur)->prop->stryng->str ++ && a_prop->stryng ++ && a_prop->stryng->str ++ && !strcmp (PRIVATE (cur)->prop->stryng->str, ++ a_prop->stryng->str)) ++ break; ++ } ++ ++ if (cur) { ++ *a_pair = cur; ++ return CR_OK; ++ } ++ ++ return CR_VALUE_NOT_FOUND_ERROR; ++} ++ ++/** ++ * cr_prop_list_get_next: ++ *@a_this: the current instance of CRPropList ++ * ++ *Gets the next prop/decl pair in the list ++ * ++ *Returns the next prop/declaration pair of the list, ++ *or NULL if we reached end of list (or if an error occurs) ++ */ ++CRPropList * ++cr_prop_list_get_next (CRPropList * a_this) ++{ ++ g_return_val_if_fail (a_this && PRIVATE (a_this), NULL); ++ ++ return PRIVATE (a_this)->next; ++} ++ ++/** ++ * cr_prop_list_get_prev: ++ *@a_this: the current instance of CRPropList ++ * ++ *Gets the previous prop/decl pair in the list ++ * ++ *Returns the previous prop/declaration pair of the list, ++ *or NULL if we reached end of list (or if an error occurs) ++ */ ++CRPropList * ++cr_prop_list_get_prev (CRPropList * a_this) ++{ ++ g_return_val_if_fail (a_this && PRIVATE (a_this), NULL); ++ ++ return PRIVATE (a_this)->prev; ++} ++ ++/** ++ * cr_prop_list_unlink: ++ *@a_this: the current list of prop/decl pairs ++ *@a_pair: the prop/decl pair to unlink. ++ * ++ *Unlinks a prop/decl pair from the list ++ * ++ *Returns the new list or NULL in case of an error. ++ */ ++CRPropList * ++cr_prop_list_unlink (CRPropList * a_this, CRPropList * a_pair) ++{ ++ CRPropList *prev = NULL, ++ *next = NULL; ++ ++ g_return_val_if_fail (a_this && PRIVATE (a_this) && a_pair, NULL); ++ ++ /*some sanity checks */ ++ if (PRIVATE (a_pair)->next) { ++ next = PRIVATE (a_pair)->next; ++ g_return_val_if_fail (PRIVATE (next), NULL); ++ g_return_val_if_fail (PRIVATE (next)->prev == a_pair, NULL); ++ } ++ if (PRIVATE (a_pair)->prev) { ++ prev = PRIVATE (a_pair)->prev; ++ g_return_val_if_fail (PRIVATE (prev), NULL); ++ g_return_val_if_fail (PRIVATE (prev)->next == a_pair, NULL); ++ } ++ if (prev) { ++ PRIVATE (prev)->next = next; ++ } ++ if (next) { ++ PRIVATE (next)->prev = prev; ++ } ++ PRIVATE (a_pair)->prev = PRIVATE (a_pair)->next = NULL; ++ if (a_this == a_pair) { ++ if (next) ++ return next; ++ return NULL; ++ } ++ return a_this; ++} ++ ++/** ++ * cr_prop_list_destroy: ++ * @a_this: the current instance of #CRPropList ++ */ ++void ++cr_prop_list_destroy (CRPropList * a_this) ++{ ++ CRPropList *tail = NULL, ++ *cur = NULL; ++ ++ g_return_if_fail (a_this && PRIVATE (a_this)); ++ ++ for (tail = a_this; ++ tail && PRIVATE (tail) && PRIVATE (tail)->next; ++ tail = cr_prop_list_get_next (tail)) ; ++ g_return_if_fail (tail); ++ ++ cur = tail; ++ ++ while (cur) { ++ tail = PRIVATE (cur)->prev; ++ if (tail && PRIVATE (tail)) ++ PRIVATE (tail)->next = NULL; ++ PRIVATE (cur)->prev = NULL; ++ g_free (PRIVATE (cur)); ++ PRIVATE (cur) = NULL; ++ g_free (cur); ++ cur = tail; ++ } ++} +diff --git a/src/st/croco/cr-prop-list.h b/src/st/croco/cr-prop-list.h +new file mode 100644 +index 000000000..797ba43ea +--- /dev/null ++++ b/src/st/croco/cr-prop-list.h +@@ -0,0 +1,80 @@ ++/* ++ * This file is part of The Croco Library ++ * ++ * 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 ++ * See COPYRIGHTS file for copyrights information. ++ */ ++ ++#ifndef __CR_PROP_LIST_H__ ++#define __CR_PROP_LIST_H__ ++ ++#include "cr-utils.h" ++#include "cr-declaration.h" ++#include "cr-string.h" ++ ++G_BEGIN_DECLS ++ ++typedef struct _CRPropList CRPropList ; ++typedef struct _CRPropListPriv CRPropListPriv ; ++ ++struct _CRPropList ++{ ++ CRPropListPriv * priv; ++} ; ++ ++CRPropList * cr_prop_list_append (CRPropList *a_this, ++ CRPropList *a_to_append) ; ++ ++CRPropList * cr_prop_list_append2 (CRPropList *a_this, ++ CRString *a_prop, ++ CRDeclaration *a_decl) ; ++ ++CRPropList * cr_prop_list_prepend (CRPropList *a_this, ++ CRPropList *a_to_append) ; ++ ++CRPropList * cr_prop_list_prepend2 (CRPropList *a_this, ++ CRString *a_prop, ++ CRDeclaration *a_decl) ; ++ ++enum CRStatus cr_prop_list_set_prop (CRPropList *a_this, ++ CRString *a_prop) ; ++ ++enum CRStatus cr_prop_list_get_prop (CRPropList const *a_this, ++ CRString **a_prop) ; ++ ++enum CRStatus cr_prop_list_lookup_prop (CRPropList *a_this, ++ CRString *a_prop, ++ CRPropList**a_pair) ; ++ ++CRPropList * cr_prop_list_get_next (CRPropList *a_this) ; ++ ++CRPropList * cr_prop_list_get_prev (CRPropList *a_this) ; ++ ++enum CRStatus cr_prop_list_set_decl (CRPropList *a_this, ++ CRDeclaration *a_decl); ++ ++enum CRStatus cr_prop_list_get_decl (CRPropList const *a_this, ++ CRDeclaration **a_decl) ; ++ ++CRPropList * cr_prop_list_unlink (CRPropList *a_this, ++ CRPropList *a_pair) ; ++ ++void cr_prop_list_destroy (CRPropList *a_this) ; ++ ++G_END_DECLS ++ ++#endif /*__CR_PROP_LIST_H__*/ +diff --git a/src/st/croco/cr-pseudo.c b/src/st/croco/cr-pseudo.c +new file mode 100644 +index 000000000..cee3fc869 +--- /dev/null ++++ b/src/st/croco/cr-pseudo.c +@@ -0,0 +1,167 @@ ++/* -*- Mode: C; indent-tabs-mode:nil; c-basic-offset: 8-*- */ ++ ++/* ++ * This file is part of The Croco Library ++ * ++ * 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 ++ * See COPYRIGHTS file for copyright information. ++ */ ++ ++#include "cr-pseudo.h" ++ ++/** ++ *@CRPseudo: ++ *The definition of the #CRPseudo class. ++ */ ++ ++/** ++ * cr_pseudo_new: ++ *Constructor of the #CRPseudo class. ++ * ++ *Returns the newly build instance. ++ */ ++CRPseudo * ++cr_pseudo_new (void) ++{ ++ CRPseudo *result = NULL; ++ ++ result = g_malloc0 (sizeof (CRPseudo)); ++ ++ return result; ++} ++ ++/** ++ * cr_pseudo_to_string: ++ * @a_this: the current instance of #CRPseud. ++ * ++ * Returns the serialized pseudo. Caller must free the returned ++ * string using g_free(). ++ */ ++guchar * ++cr_pseudo_to_string (CRPseudo const * a_this) ++{ ++ guchar *result = NULL; ++ GString *str_buf = NULL; ++ ++ g_return_val_if_fail (a_this, NULL); ++ ++ str_buf = g_string_new (NULL); ++ ++ if (a_this->type == IDENT_PSEUDO) { ++ guchar *name = NULL; ++ ++ if (a_this->name == NULL) { ++ goto error; ++ } ++ ++ name = (guchar *) g_strndup (a_this->name->stryng->str, ++ a_this->name->stryng->len); ++ ++ if (name) { ++ g_string_append (str_buf, (const gchar *) name); ++ g_free (name); ++ name = NULL; ++ } ++ } else if (a_this->type == FUNCTION_PSEUDO) { ++ guchar *name = NULL, ++ *arg = NULL; ++ ++ if (a_this->name == NULL) ++ goto error; ++ ++ name = (guchar *) g_strndup (a_this->name->stryng->str, ++ a_this->name->stryng->len); ++ ++ if (a_this->extra) { ++ arg = (guchar *) g_strndup (a_this->extra->stryng->str, ++ a_this->extra->stryng->len); ++ } ++ ++ if (name) { ++ g_string_append_printf (str_buf, "%s(", name); ++ g_free (name); ++ name = NULL; ++ ++ if (arg) { ++ g_string_append (str_buf, (const gchar *) arg); ++ g_free (arg); ++ arg = NULL; ++ } ++ ++ g_string_append_c (str_buf, ')'); ++ } ++ } ++ ++ if (str_buf) { ++ result = (guchar *) str_buf->str; ++ g_string_free (str_buf, FALSE); ++ str_buf = NULL; ++ } ++ ++ return result; ++ ++ error: ++ g_string_free (str_buf, TRUE); ++ return NULL; ++} ++ ++/** ++ * cr_pseudo_dump: ++ *@a_this: the current instance of pseudo ++ *@a_fp: the destination file pointer. ++ * ++ *Dumps the pseudo to a file. ++ * ++ */ ++void ++cr_pseudo_dump (CRPseudo const * a_this, FILE * a_fp) ++{ ++ guchar *tmp_str = NULL; ++ ++ if (a_this) { ++ tmp_str = cr_pseudo_to_string (a_this); ++ if (tmp_str) { ++ fprintf (a_fp, "%s", tmp_str); ++ g_free (tmp_str); ++ tmp_str = NULL; ++ } ++ } ++} ++ ++/** ++ * cr_pseudo_destroy: ++ *@a_this: the current instance to destroy. ++ * ++ *destructor of the #CRPseudo class. ++ */ ++void ++cr_pseudo_destroy (CRPseudo * a_this) ++{ ++ g_return_if_fail (a_this); ++ ++ if (a_this->name) { ++ cr_string_destroy (a_this->name); ++ a_this->name = NULL; ++ } ++ ++ if (a_this->extra) { ++ cr_string_destroy (a_this->extra); ++ a_this->extra = NULL; ++ } ++ ++ g_free (a_this); ++} +diff --git a/src/st/croco/cr-pseudo.h b/src/st/croco/cr-pseudo.h +new file mode 100644 +index 000000000..8917da45e +--- /dev/null ++++ b/src/st/croco/cr-pseudo.h +@@ -0,0 +1,64 @@ ++/* -*- Mode: C; indent-tabs-mode:nil; c-basic-offset: 8-*- */ ++ ++/* ++ * This file is part of The Croco Library ++ * ++ * 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 ++ * ++ * See COPYRIGHTS file for copyright information ++ */ ++ ++#ifndef __CR_PSEUDO_H__ ++#define __CR_PSEUDO_H__ ++ ++#include ++#include ++#include "cr-attr-sel.h" ++#include "cr-parsing-location.h" ++ ++G_BEGIN_DECLS ++ ++enum CRPseudoType ++{ ++ IDENT_PSEUDO = 0, ++ FUNCTION_PSEUDO ++} ; ++ ++typedef struct _CRPseudo CRPseudo ; ++ ++/** ++ *The CRPseudo Class. ++ *Abstract a "pseudo" as defined by the css2 spec ++ *in appendix D.1 . ++ */ ++struct _CRPseudo ++{ ++ enum CRPseudoType type ; ++ CRString *name ; ++ CRString *extra ; ++ CRParsingLocation location ; ++} ; ++ ++CRPseudo * cr_pseudo_new (void) ; ++ ++guchar * cr_pseudo_to_string (CRPseudo const *a_this) ; ++ ++void cr_pseudo_dump (CRPseudo const *a_this, FILE *a_fp) ; ++ ++void cr_pseudo_destroy (CRPseudo *a_this) ; ++ ++G_END_DECLS ++ ++#endif /*__CR_PSEUDO_H__*/ +diff --git a/src/st/croco/cr-rgb.c b/src/st/croco/cr-rgb.c +new file mode 100644 +index 000000000..1b8b66256 +--- /dev/null ++++ b/src/st/croco/cr-rgb.c +@@ -0,0 +1,687 @@ ++/* -*- Mode: C; indent-tabs-mode:nil; c-basic-offset: 8-*- */ ++ ++/* ++ * This file is part of The Croco Library ++ * ++ * 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 ++ * See COPYRIGHTS file for copyrights information. ++ */ ++ ++#include "config.h" ++ ++#include ++#include ++#include ++#include "cr-rgb.h" ++#include "cr-term.h" ++#include "cr-parser.h" ++ ++static const CRRgb gv_standard_colors[] = { ++ {(const guchar*)"aliceblue", 240, 248, 255, FALSE, FALSE, FALSE, {0,0,0}}, ++ {(const guchar*)"antiquewhite", 250, 235, 215, FALSE, FALSE, FALSE, {0,0,0}}, ++ {(const guchar*)"aqua", 0, 255, 255, FALSE, FALSE, FALSE, {0,0,0}}, ++ {(const guchar*)"aquamarine", 127, 255, 212, FALSE, FALSE, FALSE, {0,0,0}}, ++ {(const guchar*)"azure", 240, 255, 255, FALSE, FALSE, FALSE, {0,0,0}}, ++ {(const guchar*)"beige", 245, 245, 220, FALSE, FALSE, FALSE, {0,0,0}}, ++ {(const guchar*)"bisque", 255, 228, 196, FALSE, FALSE, FALSE, {0,0,0}}, ++ {(const guchar*)"black", 0, 0, 0, FALSE, FALSE, FALSE, {0,0,0}}, ++ {(const guchar*)"blanchedalmond", 255, 235, 205, FALSE, FALSE, FALSE, {0,0,0}}, ++ {(const guchar*)"blue", 0, 0, 255, FALSE, FALSE, FALSE, {0,0,0}}, ++ {(const guchar*)"blueviolet", 138, 43, 226, FALSE, FALSE, FALSE, {0,0,0}}, ++ {(const guchar*)"brown", 165, 42, 42, FALSE, FALSE, FALSE, {0,0,0}}, ++ {(const guchar*)"burlywood", 222, 184, 135, FALSE, FALSE, FALSE, {0,0,0}}, ++ {(const guchar*)"cadetblue", 95, 158, 160, FALSE, FALSE, FALSE, {0,0,0}}, ++ {(const guchar*)"chartreuse", 127, 255, 0, FALSE, FALSE, FALSE, {0,0,0}}, ++ {(const guchar*)"chocolate", 210, 105, 30, FALSE, FALSE, FALSE, {0,0,0}}, ++ {(const guchar*)"coral", 255, 127, 80, FALSE, FALSE, FALSE, {0,0,0}}, ++ {(const guchar*)"cornflowerblue", 100, 149, 237, FALSE, FALSE, FALSE, {0,0,0}}, ++ {(const guchar*)"cornsilk", 255, 248, 220, FALSE, FALSE, FALSE, {0,0,0}}, ++ {(const guchar*)"crimson", 220, 20, 60, FALSE, FALSE, FALSE, {0,0,0}}, ++ {(const guchar*)"cyan", 0, 255, 255, FALSE, FALSE, FALSE, {0,0,0}}, ++ {(const guchar*)"darkblue", 0, 0, 139, FALSE, FALSE, FALSE, {0,0,0}}, ++ {(const guchar*)"darkcyan", 0, 139, 139, FALSE, FALSE, FALSE, {0,0,0}}, ++ {(const guchar*)"darkgoldenrod", 184, 134, 11, FALSE, FALSE, FALSE, {0,0,0}}, ++ {(const guchar*)"darkgray", 169, 169, 169, FALSE, FALSE, FALSE, {0,0,0}}, ++ {(const guchar*)"darkgreen", 0, 100, 0, FALSE, FALSE, FALSE, {0,0,0}}, ++ {(const guchar*)"darkgrey", 169, 169, 169, FALSE, FALSE, FALSE, {0,0,0}}, ++ {(const guchar*)"darkkhaki", 189, 183, 107, FALSE, FALSE, FALSE, {0,0,0}}, ++ {(const guchar*)"darkmagenta", 139, 0, 139, FALSE, FALSE, FALSE, {0,0,0}}, ++ {(const guchar*)"darkolivegreen", 85, 107, 47, FALSE, FALSE, FALSE, {0,0,0}}, ++ {(const guchar*)"darkorange", 255, 140, 0, FALSE, FALSE, FALSE, {0,0,0}}, ++ {(const guchar*)"darkorchid", 153, 50, 204, FALSE, FALSE, FALSE, {0,0,0}}, ++ {(const guchar*)"darkred", 139, 0, 0, FALSE, FALSE, FALSE, {0,0,0}}, ++ {(const guchar*)"darksalmon", 233, 150, 122, FALSE, FALSE, FALSE, {0,0,0}}, ++ {(const guchar*)"darkseagreen", 143, 188, 143, FALSE, FALSE, FALSE, {0,0,0}}, ++ {(const guchar*)"darkslateblue", 72, 61, 139, FALSE, FALSE, FALSE, {0,0,0}}, ++ {(const guchar*)"darkslategray", 47, 79, 79, FALSE, FALSE, FALSE, {0,0,0}}, ++ {(const guchar*)"darkslategrey", 47, 79, 79, FALSE, FALSE, FALSE, {0,0,0}}, ++ {(const guchar*)"darkturquoise", 0, 206, 209, FALSE, FALSE, FALSE, {0,0,0}}, ++ {(const guchar*)"darkviolet", 148, 0, 211, FALSE, FALSE, FALSE, {0,0,0}}, ++ {(const guchar*)"deeppink", 255, 20, 147, FALSE, FALSE, FALSE, {0,0,0}}, ++ {(const guchar*)"deepskyblue", 0, 191, 255, FALSE, FALSE, FALSE, {0,0,0}}, ++ {(const guchar*)"dimgray", 105, 105, 105, FALSE, FALSE, FALSE, {0,0,0}}, ++ {(const guchar*)"dimgrey", 105, 105, 105, FALSE, FALSE, FALSE, {0,0,0}}, ++ {(const guchar*)"dodgerblue", 30, 144, 255, FALSE, FALSE, FALSE, {0,0,0}}, ++ {(const guchar*)"firebrick", 178, 34, 34, FALSE, FALSE, FALSE, {0,0,0}}, ++ {(const guchar*)"floralwhite", 255, 250, 240, FALSE, FALSE, FALSE, {0,0,0}}, ++ {(const guchar*)"forestgreen", 34, 139, 34, FALSE, FALSE, FALSE, {0,0,0}}, ++ {(const guchar*)"fuchsia", 255, 0, 255, FALSE, FALSE, FALSE, {0,0,0}}, ++ {(const guchar*)"gainsboro", 220, 220, 220, FALSE, FALSE, FALSE, {0,0,0}}, ++ {(const guchar*)"ghostwhite", 248, 248, 255, FALSE, FALSE, FALSE, {0,0,0}}, ++ {(const guchar*)"gold", 255, 215, 0, FALSE, FALSE, FALSE, {0,0,0}}, ++ {(const guchar*)"goldenrod", 218, 165, 32, FALSE, FALSE, FALSE, {0,0,0}}, ++ {(const guchar*)"gray", 128, 128, 128, FALSE, FALSE, FALSE, {0,0,0}}, ++ {(const guchar*)"green", 0, 128, 0, FALSE, FALSE, FALSE, {0,0,0}}, ++ {(const guchar*)"greenyellow", 173, 255, 47, FALSE, FALSE, FALSE, {0,0,0}}, ++ {(const guchar*)"grey", 128, 128, 128, FALSE, FALSE, FALSE, {0,0,0}}, ++ {(const guchar*)"honeydew", 240, 255, 240, FALSE, FALSE, FALSE, {0,0,0}}, ++ {(const guchar*)"hotpink", 255, 105, 180, FALSE, FALSE, FALSE, {0,0,0}}, ++ {(const guchar*)"indianred", 205, 92, 92, FALSE, FALSE, FALSE, {0,0,0}}, ++ {(const guchar*)"indigo", 75, 0, 130, FALSE, FALSE, FALSE, {0,0,0}}, ++ {(const guchar*)"ivory", 255, 255, 240, FALSE, FALSE, FALSE, {0,0,0}}, ++ {(const guchar*)"khaki", 240, 230, 140, FALSE, FALSE, FALSE, {0,0,0}}, ++ {(const guchar*)"lavender", 230, 230, 250, FALSE, FALSE, FALSE, {0,0,0}}, ++ {(const guchar*)"lavenderblush", 255, 240, 245, FALSE, FALSE, FALSE, {0,0,0}}, ++ {(const guchar*)"lawngreen", 124, 252, 0, FALSE, FALSE, FALSE, {0,0,0}}, ++ {(const guchar*)"lemonchiffon", 255, 250, 205, FALSE, FALSE, FALSE, {0,0,0}}, ++ {(const guchar*)"lightblue", 173, 216, 230, FALSE, FALSE, FALSE, {0,0,0}}, ++ {(const guchar*)"lightcoral", 240, 128, 128, FALSE, FALSE, FALSE, {0,0,0}}, ++ {(const guchar*)"lightcyan", 224, 255, 255, FALSE, FALSE, FALSE, {0,0,0}}, ++ {(const guchar*)"lightgoldenrodyellow", 250, 250, 210, FALSE, FALSE, FALSE, {0,0,0}}, ++ {(const guchar*)"lightgray", 211, 211, 211, FALSE, FALSE, FALSE, {0,0,0}}, ++ {(const guchar*)"lightgreen", 144, 238, 144, FALSE, FALSE, FALSE, {0,0,0}}, ++ {(const guchar*)"lightgrey", 211, 211, 211, FALSE, FALSE, FALSE, {0,0,0}}, ++ {(const guchar*)"lightpink", 255, 182, 193, FALSE, FALSE, FALSE, {0,0,0}}, ++ {(const guchar*)"lightsalmon", 255, 160, 122, FALSE, FALSE, FALSE, {0,0,0}}, ++ {(const guchar*)"lightseagreen", 32, 178, 170, FALSE, FALSE, FALSE, {0,0,0}}, ++ {(const guchar*)"lightskyblue", 135, 206, 250, FALSE, FALSE, FALSE, {0,0,0}}, ++ {(const guchar*)"lightslategray", 119, 136, 153, FALSE, FALSE, FALSE, {0,0,0}}, ++ {(const guchar*)"lightslategrey", 119, 136, 153, FALSE, FALSE, FALSE, {0,0,0}}, ++ {(const guchar*)"lightsteelblue", 176, 196, 222, FALSE, FALSE, FALSE, {0,0,0}}, ++ {(const guchar*)"lightyellow", 255, 255, 224, FALSE, FALSE, FALSE, {0,0,0}}, ++ {(const guchar*)"lime", 0, 255, 0, FALSE, FALSE, FALSE, {0,0,0}}, ++ {(const guchar*)"limegreen", 50, 205, 50, FALSE, FALSE, FALSE, {0,0,0}}, ++ {(const guchar*)"linen", 250, 240, 230, FALSE, FALSE, FALSE, {0,0,0}}, ++ {(const guchar*)"magenta", 255, 0, 255, FALSE, FALSE, FALSE, {0,0,0}}, ++ {(const guchar*)"maroon", 128, 0, 0, FALSE, FALSE, FALSE, {0,0,0}}, ++ {(const guchar*)"mediumaquamarine", 102, 205, 170, FALSE, FALSE, FALSE, {0,0,0}}, ++ {(const guchar*)"mediumblue", 0, 0, 205, FALSE, FALSE, FALSE, {0,0,0}}, ++ {(const guchar*)"mediumorchid", 186, 85, 211, FALSE, FALSE, FALSE, {0,0,0}}, ++ {(const guchar*)"mediumpurple", 147, 112, 219, FALSE, FALSE, FALSE, {0,0,0}}, ++ {(const guchar*)"mediumseagreen", 60, 179, 113, FALSE, FALSE, FALSE, {0,0,0}}, ++ {(const guchar*)"mediumslateblue", 123, 104, 238, FALSE, FALSE, FALSE, {0,0,0}}, ++ {(const guchar*)"mediumspringgreen", 0, 250, 154, FALSE, FALSE, FALSE, {0,0,0}}, ++ {(const guchar*)"mediumturquoise", 72, 209, 204, FALSE, FALSE, FALSE, {0,0,0}}, ++ {(const guchar*)"mediumvioletred", 199, 21, 133, FALSE, FALSE, FALSE, {0,0,0}}, ++ {(const guchar*)"midnightblue", 25, 25, 112, FALSE, FALSE, FALSE, {0,0,0}}, ++ {(const guchar*)"mintcream", 245, 255, 250, FALSE, FALSE, FALSE, {0,0,0}}, ++ {(const guchar*)"mistyrose", 255, 228, 225, FALSE, FALSE, FALSE, {0,0,0}}, ++ {(const guchar*)"moccasin", 255, 228, 181, FALSE, FALSE, FALSE, {0,0,0}}, ++ {(const guchar*)"navajowhite", 255, 222, 173, FALSE, FALSE, FALSE, {0,0,0}}, ++ {(const guchar*)"navy", 0, 0, 128, FALSE, FALSE, FALSE, {0,0,0}}, ++ {(const guchar*)"oldlace", 253, 245, 230, FALSE, FALSE, FALSE, {0,0,0}}, ++ {(const guchar*)"olive", 128, 128, 0, FALSE, FALSE, FALSE, {0,0,0}}, ++ {(const guchar*)"olivedrab", 107, 142, 35, FALSE, FALSE, FALSE, {0,0,0}}, ++ {(const guchar*)"orange", 255, 165, 0, FALSE, FALSE, FALSE, {0,0,0}}, ++ {(const guchar*)"orangered", 255, 69, 0, FALSE, FALSE, FALSE, {0,0,0}}, ++ {(const guchar*)"orchid", 218, 112, 214, FALSE, FALSE, FALSE, {0,0,0}}, ++ {(const guchar*)"palegoldenrod", 238, 232, 170, FALSE, FALSE, FALSE, {0,0,0}}, ++ {(const guchar*)"palegreen", 152, 251, 152, FALSE, FALSE, FALSE, {0,0,0}}, ++ {(const guchar*)"paleturquoise", 175, 238, 238, FALSE, FALSE, FALSE, {0,0,0}}, ++ {(const guchar*)"palevioletred", 219, 112, 147, FALSE, FALSE, FALSE, {0,0,0}}, ++ {(const guchar*)"papayawhip", 255, 239, 213, FALSE, FALSE, FALSE, {0,0,0}}, ++ {(const guchar*)"peachpuff", 255, 218, 185, FALSE, FALSE, FALSE, {0,0,0}}, ++ {(const guchar*)"peru", 205, 133, 63, FALSE, FALSE, FALSE, {0,0,0}}, ++ {(const guchar*)"pink", 255, 192, 203, FALSE, FALSE, FALSE, {0,0,0}}, ++ {(const guchar*)"plum", 221, 160, 221, FALSE, FALSE, FALSE, {0,0,0}}, ++ {(const guchar*)"powderblue", 176, 224, 230, FALSE, FALSE, FALSE, {0,0,0}}, ++ {(const guchar*)"purple", 128, 0, 128, FALSE, FALSE, FALSE, {0,0,0}}, ++ {(const guchar*)"red", 255, 0, 0, FALSE, FALSE, FALSE, {0,0,0}}, ++ {(const guchar*)"rosybrown", 188, 143, 143, FALSE, FALSE, FALSE, {0,0,0}}, ++ {(const guchar*)"royalblue", 65, 105, 225, FALSE, FALSE, FALSE, {0,0,0}}, ++ {(const guchar*)"saddlebrown", 139, 69, 19, FALSE, FALSE, FALSE, {0,0,0}}, ++ {(const guchar*)"salmon", 250, 128, 114, FALSE, FALSE, FALSE, {0,0,0}}, ++ {(const guchar*)"sandybrown", 244, 164, 96, FALSE, FALSE, FALSE, {0,0,0}}, ++ {(const guchar*)"seagreen", 46, 139, 87, FALSE, FALSE, FALSE, {0,0,0}}, ++ {(const guchar*)"seashell", 255, 245, 238, FALSE, FALSE, FALSE, {0,0,0}}, ++ {(const guchar*)"sienna", 160, 82, 45, FALSE, FALSE, FALSE, {0,0,0}}, ++ {(const guchar*)"silver", 192, 192, 192, FALSE, FALSE, FALSE, {0,0,0}}, ++ {(const guchar*)"skyblue", 135, 206, 235, FALSE, FALSE, FALSE, {0,0,0}}, ++ {(const guchar*)"slateblue", 106, 90, 205, FALSE, FALSE, FALSE, {0,0,0}}, ++ {(const guchar*)"slategray", 112, 128, 144, FALSE, FALSE, FALSE, {0,0,0}}, ++ {(const guchar*)"slategrey", 112, 128, 144, FALSE, FALSE, FALSE, {0,0,0}}, ++ {(const guchar*)"snow", 255, 250, 250, FALSE, FALSE, FALSE, {0,0,0}}, ++ {(const guchar*)"springgreen", 0, 255, 127, FALSE, FALSE, FALSE, {0,0,0}}, ++ {(const guchar*)"steelblue", 70, 130, 180, FALSE, FALSE, FALSE, {0,0,0}}, ++ {(const guchar*)"tan", 210, 180, 140, FALSE, FALSE, FALSE, {0,0,0}}, ++ {(const guchar*)"teal", 0, 128, 128, FALSE, FALSE, FALSE, {0,0,0}}, ++ {(const guchar*)"thistle", 216, 191, 216, FALSE, FALSE, FALSE, {0,0,0}}, ++ {(const guchar*)"tomato", 255, 99, 71, FALSE, FALSE, FALSE, {0,0,0}}, ++ {(const guchar*)"transparent", 255, 255, 255, FALSE, FALSE, TRUE, {0,0,0}}, ++ {(const guchar*)"turquoise", 64, 224, 208, FALSE, FALSE, FALSE, {0,0,0}}, ++ {(const guchar*)"violet", 238, 130, 238, FALSE, FALSE, FALSE, {0,0,0}}, ++ {(const guchar*)"wheat", 245, 222, 179, FALSE, FALSE, FALSE, {0,0,0}}, ++ {(const guchar*)"white", 255, 255, 255, FALSE, FALSE, FALSE, {0,0,0}}, ++ {(const guchar*)"whitesmoke", 245, 245, 245, FALSE, FALSE, FALSE, {0,0,0}}, ++ {(const guchar*)"yellow", 255, 255, 0, FALSE, FALSE, FALSE, {0,0,0}}, ++ {(const guchar*)"yellowgreen", 154, 205, 50, FALSE, FALSE, FALSE, {0,0,0}} ++}; ++ ++/** ++ * cr_rgb_new: ++ * ++ *The default constructor of #CRRgb. ++ * ++ *Returns the newly built instance of #CRRgb ++ */ ++CRRgb * ++cr_rgb_new (void) ++{ ++ CRRgb *result = NULL; ++ ++ result = g_try_malloc (sizeof (CRRgb)); ++ ++ if (result == NULL) { ++ cr_utils_trace_info ("No more memory"); ++ return NULL; ++ } ++ ++ memset (result, 0, sizeof (CRRgb)); ++ ++ return result; ++} ++ ++/** ++ * cr_rgb_new_with_vals: ++ *@a_red: the red component of the color. ++ *@a_green: the green component of the color. ++ *@a_blue: the blue component of the color. ++ *@a_unit: the unit of the rgb values. ++ *(either percentage or integer values) ++ * ++ *A constructor of #CRRgb. ++ * ++ *Returns the newly built instance of #CRRgb. ++ */ ++CRRgb * ++cr_rgb_new_with_vals (gulong a_red, gulong a_green, ++ gulong a_blue, gboolean a_is_percentage) ++{ ++ CRRgb *result = NULL; ++ ++ result = cr_rgb_new (); ++ ++ g_return_val_if_fail (result, NULL); ++ ++ result->red = a_red; ++ result->green = a_green; ++ result->blue = a_blue; ++ result->is_percentage = a_is_percentage; ++ ++ return result; ++} ++ ++/** ++ * cr_rgb_to_string: ++ *@a_this: the instance of #CRRgb to serialize. ++ * ++ *Serializes the rgb into a zero terminated string. ++ * ++ *Returns the zero terminated string containing the serialized ++ *rgb. MUST BE FREED by the caller using g_free(). ++ */ ++guchar * ++cr_rgb_to_string (CRRgb const * a_this) ++{ ++ guchar *result = NULL; ++ GString *str_buf = NULL; ++ ++ str_buf = g_string_new (NULL); ++ g_return_val_if_fail (str_buf, NULL); ++ ++ if (a_this->is_percentage == 1) { ++ g_string_append_printf (str_buf, "%ld", a_this->red); ++ ++ g_string_append (str_buf, "%, "); ++ ++ g_string_append_printf (str_buf, "%ld", a_this->green); ++ g_string_append (str_buf, "%, "); ++ ++ g_string_append_printf (str_buf, "%ld", a_this->blue); ++ g_string_append_c (str_buf, '%'); ++ } else { ++ g_string_append_printf (str_buf, "%ld", a_this->red); ++ g_string_append (str_buf, ", "); ++ ++ g_string_append_printf (str_buf, "%ld", a_this->green); ++ g_string_append (str_buf, ", "); ++ ++ g_string_append_printf (str_buf, "%ld", a_this->blue); ++ } ++ ++ if (str_buf) { ++ result = (guchar *) str_buf->str; ++ g_string_free (str_buf, FALSE); ++ } ++ ++ return result; ++} ++ ++/** ++ * cr_rgb_dump: ++ *@a_this: the "this pointer" of ++ *the current instance of #CRRgb. ++ *@a_fp: the destination file pointer. ++ * ++ *Dumps the current instance of #CRRgb ++ *to a file. ++ */ ++void ++cr_rgb_dump (CRRgb const * a_this, FILE * a_fp) ++{ ++ guchar *str = NULL; ++ ++ g_return_if_fail (a_this); ++ ++ str = cr_rgb_to_string (a_this); ++ ++ if (str) { ++ fprintf (a_fp, "%s", str); ++ g_free (str); ++ str = NULL; ++ } ++} ++ ++/** ++ * cr_rgb_compute_from_percentage: ++ *@a_this: the current instance of #CRRgb ++ * ++ *If the rgb values are expressed in percentage, ++ *compute their real value. ++ * ++ *Returns CR_OK upon successful completion, an error code otherwise. ++ */ ++enum CRStatus ++cr_rgb_compute_from_percentage (CRRgb * a_this) ++{ ++ g_return_val_if_fail (a_this, CR_BAD_PARAM_ERROR); ++ ++ if (a_this->is_percentage == FALSE) ++ return CR_OK; ++ a_this->red = a_this->red * 255 / 100; ++ a_this->green = a_this->green * 255 / 100; ++ a_this->blue = a_this->blue * 255 / 100; ++ a_this->is_percentage = FALSE; ++ return CR_OK; ++} ++ ++/** ++ * cr_rgb_set: ++ *@a_this: the current instance of #CRRgb. ++ *@a_red: the red value. ++ *@a_green: the green value. ++ *@a_blue: the blue value. ++ * ++ *Sets rgb values to the RGB. ++ * ++ *Returns CR_OK upon successful completion, an error code ++ *otherwise. ++ */ ++enum CRStatus ++cr_rgb_set (CRRgb * a_this, gulong a_red, ++ gulong a_green, gulong a_blue, gboolean a_is_percentage) ++{ ++ g_return_val_if_fail (a_this, CR_BAD_PARAM_ERROR); ++ if (a_is_percentage != FALSE) { ++ g_return_val_if_fail (a_red <= 100 ++ && a_green <= 100 ++ && a_blue <= 100, CR_BAD_PARAM_ERROR); ++ } ++ ++ a_this->is_percentage = a_is_percentage; ++ ++ a_this->red = a_red; ++ a_this->green = a_green; ++ a_this->blue = a_blue; ++ a_this->inherit = FALSE ; ++ a_this->is_transparent = FALSE ; ++ return CR_OK; ++} ++ ++/** ++ * cr_rgb_set_to_inherit: ++ *@a_this: the current instance of #CRRgb ++ * ++ *sets the value of the rgb to inherit. ++ *Look at the css spec from chapter 6.1 to 6.2 to understand ++ *the meaning of "inherit". ++ * ++ * Returns CR_OK upon succesful completion, an error code otherwise. ++ */ ++enum CRStatus ++cr_rgb_set_to_inherit (CRRgb *a_this, gboolean a_inherit) ++{ ++ g_return_val_if_fail (a_this, CR_BAD_PARAM_ERROR) ; ++ ++ a_this->inherit = a_inherit ; ++ ++ return CR_OK ; ++} ++ ++/** ++ * cr_rgb_is_set_to_inherit: ++ * ++ * @a_this: the current instance of #CRRgb. ++ * ++ * Returns TRUE if the rgb is set to the value "inherit", FALSE otherwise. ++ */ ++gboolean ++cr_rgb_is_set_to_inherit (CRRgb const *a_this) ++{ ++ g_return_val_if_fail (a_this, CR_BAD_PARAM_ERROR) ; ++ ++ return a_this->inherit ; ++} ++ ++/** ++ * cr_rgb_is_set_to_transparent: ++ *@a_this: the current instance of ++ *#CRRgb ++ * ++ *Tests if the the rgb is set to the ++ *value "transparent" or not. ++ * ++ *Returns TRUE if the rgb has been set to ++ *transparent, FALSE otherwise. ++ */ ++gboolean ++cr_rgb_is_set_to_transparent (CRRgb const *a_this) ++{ ++ g_return_val_if_fail (a_this, FALSE) ; ++ return a_this->is_transparent ; ++} ++ ++ ++/** ++ * cr_rgb_set_to_transparent: ++ *@a_this: the current instance of #CRRgb ++ *@a_is_transparent: set to transparent or not. ++ * ++ *Sets the rgb to the "transparent" value (or not) ++ *Returns CR_OK upon successfull completion, an error code otherwise. ++ */ ++enum CRStatus ++cr_rgb_set_to_transparent (CRRgb *a_this, ++ gboolean a_is_transparent) ++{ ++ g_return_val_if_fail (a_this, CR_BAD_PARAM_ERROR) ; ++ a_this->is_transparent = a_is_transparent ; ++ return CR_OK ; ++} ++ ++/** ++ * cr_rgb_set_from_rgb: ++ *@a_this: the current instance of #CRRgb. ++ *@a_rgb: the rgb to "copy" ++ * ++ *Sets the rgb from an other one. ++ * ++ *Returns CR_OK upon successful completion, an error code otherwise. ++ */ ++enum CRStatus ++cr_rgb_set_from_rgb (CRRgb * a_this, CRRgb const * a_rgb) ++{ ++ g_return_val_if_fail (a_this && a_rgb, CR_BAD_PARAM_ERROR); ++ ++ cr_rgb_copy (a_this, a_rgb) ; ++ ++ return CR_OK; ++} ++ ++static int ++cr_rgb_color_name_compare (const void *a, ++ const void *b) ++{ ++ const char *a_color_name = a; ++ const CRRgb *rgb = b; ++ ++ return g_ascii_strcasecmp (a_color_name, (const char *) rgb->name); ++} ++ ++/** ++ * cr_rgb_set_from_name: ++ * @a_this: the current instance of #CRRgb ++ * @a_color_name: the color name ++ * ++ * Returns CR_OK upon successful completion, an error code otherwise. ++ */ ++enum CRStatus ++cr_rgb_set_from_name (CRRgb * a_this, const guchar * a_color_name) ++{ ++ enum CRStatus status = CR_OK; ++ CRRgb *result; ++ ++ g_return_val_if_fail (a_this && a_color_name, CR_BAD_PARAM_ERROR); ++ ++ result = bsearch (a_color_name, ++ gv_standard_colors, ++ G_N_ELEMENTS (gv_standard_colors), ++ sizeof (gv_standard_colors[0]), ++ cr_rgb_color_name_compare); ++ if (result != NULL) ++ cr_rgb_set_from_rgb (a_this, result); ++ else ++ status = CR_UNKNOWN_TYPE_ERROR; ++ ++ return status; ++} ++ ++/** ++ * cr_rgb_set_from_hex_str: ++ * @a_this: the current instance of #CRRgb ++ * @a_hex: the hexadecimal value to set. ++ * ++ * Returns CR_OK upon successful completion. ++ */ ++enum CRStatus ++cr_rgb_set_from_hex_str (CRRgb * a_this, const guchar * a_hex) ++{ ++ enum CRStatus status = CR_OK; ++ gulong i = 0; ++ guchar colors[3] = { 0 }; ++ ++ g_return_val_if_fail (a_this && a_hex, CR_BAD_PARAM_ERROR); ++ ++ if (strlen ((const char *) a_hex) == 3) { ++ for (i = 0; i < 3; i++) { ++ if (a_hex[i] >= '0' && a_hex[i] <= '9') { ++ colors[i] = a_hex[i] - '0'; ++ colors[i] = (colors[i] << 4) | colors[i]; ++ } else if (a_hex[i] >= 'a' && a_hex[i] <= 'z') { ++ colors[i] = 10 + a_hex[i] - 'a'; ++ colors[i] = (colors[i] << 4) | colors[i]; ++ } else if (a_hex[i] >= 'A' && a_hex[i] <= 'Z') { ++ colors[i] = 10 + a_hex[i] - 'A'; ++ colors[i] = (colors[i] << 4) | colors[i]; ++ } else { ++ status = CR_UNKNOWN_TYPE_ERROR; ++ } ++ } ++ } else if (strlen ((const char *) a_hex) == 6) { ++ for (i = 0; i < 6; i++) { ++ if (a_hex[i] >= '0' && a_hex[i] <= '9') { ++ colors[i / 2] <<= 4; ++ colors[i / 2] |= a_hex[i] - '0'; ++ status = CR_OK; ++ } else if (a_hex[i] >= 'a' && a_hex[i] <= 'z') { ++ colors[i / 2] <<= 4; ++ colors[i / 2] |= 10 + a_hex[i] - 'a'; ++ status = CR_OK; ++ } else if (a_hex[i] >= 'A' && a_hex[i] <= 'Z') { ++ colors[i / 2] <<= 4; ++ colors[i / 2] |= 10 + a_hex[i] - 'A'; ++ status = CR_OK; ++ } else { ++ status = CR_UNKNOWN_TYPE_ERROR; ++ } ++ } ++ } else { ++ status = CR_UNKNOWN_TYPE_ERROR; ++ } ++ ++ if (status == CR_OK) { ++ status = cr_rgb_set (a_this, colors[0], ++ colors[1], colors[2], FALSE); ++ cr_rgb_set_to_transparent (a_this, FALSE) ; ++ } ++ return status; ++} ++ ++/** ++ * cr_rgb_set_from_term: ++ *@a_this: the instance of #CRRgb to set ++ *@a_value: the terminal from which to set ++ * ++ *Set the rgb from a terminal symbol ++ * ++ * Returns CR_OK upon successful completion, an error code otherwise. ++ */ ++enum CRStatus ++cr_rgb_set_from_term (CRRgb *a_this, const struct _CRTerm *a_value) ++{ ++ enum CRStatus status = CR_OK ; ++ g_return_val_if_fail (a_this && a_value, ++ CR_BAD_PARAM_ERROR) ; ++ ++ switch(a_value->type) { ++ case TERM_RGB: ++ if (a_value->content.rgb) { ++ cr_rgb_set_from_rgb ++ (a_this, a_value->content.rgb) ; ++ } ++ break ; ++ case TERM_IDENT: ++ if (a_value->content.str ++ && a_value->content.str->stryng ++ && a_value->content.str->stryng->str) { ++ if (!strncmp ("inherit", ++ a_value->content.str->stryng->str, ++ sizeof ("inherit")-1)) { ++ a_this->inherit = TRUE; ++ a_this->is_transparent = FALSE ; ++ } else { ++ status = cr_rgb_set_from_name ++ (a_this, ++ (const guchar *) a_value->content.str->stryng->str) ; ++ } ++ } else { ++ cr_utils_trace_info ++ ("a_value has NULL string value") ; ++ } ++ break ; ++ case TERM_HASH: ++ if (a_value->content.str ++ && a_value->content.str->stryng ++ && a_value->content.str->stryng->str) { ++ status = cr_rgb_set_from_hex_str ++ (a_this, ++ (const guchar *) a_value->content.str->stryng->str) ; ++ } else { ++ cr_utils_trace_info ++ ("a_value has NULL string value") ; ++ } ++ break ; ++ default: ++ status = CR_UNKNOWN_TYPE_ERROR ; ++ } ++ return status ; ++} ++ ++enum CRStatus ++cr_rgb_copy (CRRgb *a_dest, CRRgb const *a_src) ++{ ++ g_return_val_if_fail (a_dest && a_src, ++ CR_BAD_PARAM_ERROR) ; ++ ++ memcpy (a_dest, a_src, sizeof (CRRgb)) ; ++ return CR_OK ; ++} ++ ++/** ++ * cr_rgb_destroy: ++ *@a_this: the "this pointer" of the ++ *current instance of #CRRgb. ++ * ++ *Destructor of #CRRgb. ++ */ ++void ++cr_rgb_destroy (CRRgb * a_this) ++{ ++ g_return_if_fail (a_this); ++ g_free (a_this); ++} ++ ++/** ++ * cr_rgb_parse_from_buf: ++ *@a_str: a string that contains a color description ++ *@a_enc: the encoding of a_str ++ * ++ *Parses a text buffer that contains a rgb color ++ * ++ *Returns the parsed color, or NULL in case of error ++ */ ++CRRgb * ++cr_rgb_parse_from_buf (const guchar *a_str, ++ enum CREncoding a_enc) ++{ ++ enum CRStatus status = CR_OK ; ++ CRTerm *value = NULL ; ++ CRParser * parser = NULL; ++ CRRgb *result = NULL; ++ ++ g_return_val_if_fail (a_str, NULL); ++ ++ parser = cr_parser_new_from_buf ((guchar *) a_str, strlen ((const char *) a_str), a_enc, FALSE); ++ ++ g_return_val_if_fail (parser, NULL); ++ ++ status = cr_parser_try_to_skip_spaces_and_comments (parser) ; ++ if (status != CR_OK) ++ goto cleanup; ++ ++ status = cr_parser_parse_term (parser, &value); ++ if (status != CR_OK) ++ goto cleanup; ++ ++ result = cr_rgb_new (); ++ if (!result) ++ goto cleanup; ++ ++ status = cr_rgb_set_from_term (result, value); ++ ++cleanup: ++ if (parser) { ++ cr_parser_destroy (parser); ++ parser = NULL; ++ } ++ if (value) { ++ cr_term_destroy(value); ++ value = NULL; ++ } ++ return result ; ++} ++ +diff --git a/src/st/croco/cr-rgb.h b/src/st/croco/cr-rgb.h +new file mode 100644 +index 000000000..a127a440e +--- /dev/null ++++ b/src/st/croco/cr-rgb.h +@@ -0,0 +1,94 @@ ++/* -*- Mode: C; indent-tabs-mode:nil; c-basic-offset: 8-*- */ ++ ++/* ++ * This file is part of The Croco Library ++ * ++ * 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 ++ * ++ * see COPYRIGHTS file for copyright information. ++ */ ++ ++#ifndef __CR_RGB_H__ ++#define __CR_RGB_H__ ++ ++#include ++#include ++#include "cr-utils.h" ++#include "cr-parsing-location.h" ++ ++G_BEGIN_DECLS ++ ++ ++typedef struct _CRRgb CRRgb ; ++struct _CRRgb ++{ ++ /* ++ *the unit of the rgb. ++ *Either NO_UNIT (integer) or ++ *UNIT_PERCENTAGE (percentage). ++ */ ++ const guchar *name ; ++ glong red ; ++ glong green ; ++ glong blue ; ++ gboolean is_percentage ; ++ gboolean inherit ; ++ gboolean is_transparent ; ++ CRParsingLocation location ; ++} ; ++ ++CRRgb * cr_rgb_new (void) ; ++ ++CRRgb * cr_rgb_new_with_vals (gulong a_red, gulong a_green, ++ gulong a_blue, gboolean a_is_percentage) ; ++ ++CRRgb *cr_rgb_parse_from_buf(const guchar *a_str, ++ enum CREncoding a_enc); ++ ++enum CRStatus cr_rgb_compute_from_percentage (CRRgb *a_this) ; ++ ++enum CRStatus cr_rgb_set (CRRgb *a_this, gulong a_red, ++ gulong a_green, gulong a_blue, ++ gboolean a_is_percentage) ; ++ ++enum CRStatus cr_rgb_copy (CRRgb *a_dest, CRRgb const *a_src) ; ++ ++enum CRStatus cr_rgb_set_to_inherit (CRRgb *a_this, gboolean a_inherit) ; ++ ++gboolean cr_rgb_is_set_to_inherit (CRRgb const *a_this) ; ++ ++gboolean cr_rgb_is_set_to_transparent (CRRgb const *a_this) ; ++ ++enum CRStatus cr_rgb_set_to_transparent (CRRgb *a_this, ++ gboolean a_is_transparent) ; ++enum CRStatus cr_rgb_set_from_rgb (CRRgb *a_this, CRRgb const *a_rgb) ; ++ ++enum CRStatus cr_rgb_set_from_name (CRRgb *a_this, const guchar *a_color_name) ; ++ ++enum CRStatus cr_rgb_set_from_hex_str (CRRgb *a_this, const guchar * a_hex_value) ; ++ ++struct _CRTerm; ++ ++enum CRStatus cr_rgb_set_from_term (CRRgb *a_this, const struct _CRTerm *a_value); ++ ++guchar * cr_rgb_to_string (CRRgb const *a_this) ; ++ ++void cr_rgb_dump (CRRgb const *a_this, FILE *a_fp) ; ++ ++void cr_rgb_destroy (CRRgb *a_this) ; ++ ++G_END_DECLS ++ ++#endif /*__CR_RGB_H__*/ +diff --git a/src/st/croco/cr-selector.c b/src/st/croco/cr-selector.c +new file mode 100644 +index 000000000..8902e1c0f +--- /dev/null ++++ b/src/st/croco/cr-selector.c +@@ -0,0 +1,306 @@ ++/* -*- Mode: C; indent-tabs-mode: nil; c-basic-offset: 8 -*- */ ++ ++/* ++ * This file is part of The Croco Library ++ * ++ * 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 ++ * ++ * See COPYRIGHTS file for copyright information. ++ */ ++ ++#include ++#include "cr-selector.h" ++#include "cr-parser.h" ++ ++/** ++ * cr_selector_new: ++ * ++ *@a_simple_sel: the initial simple selector list ++ *of the current instance of #CRSelector. ++ * ++ *Creates a new instance of #CRSelector. ++ * ++ *Returns the newly built instance of #CRSelector, or ++ *NULL in case of failure. ++ */ ++CRSelector * ++cr_selector_new (CRSimpleSel * a_simple_sel) ++{ ++ CRSelector *result = NULL; ++ ++ result = g_try_malloc (sizeof (CRSelector)); ++ if (!result) { ++ cr_utils_trace_info ("Out of memory"); ++ return NULL; ++ } ++ memset (result, 0, sizeof (CRSelector)); ++ result->simple_sel = a_simple_sel; ++ return result; ++} ++ ++CRSelector * ++cr_selector_parse_from_buf (const guchar * a_char_buf, enum CREncoding a_enc) ++{ ++ CRParser *parser = NULL; ++ ++ g_return_val_if_fail (a_char_buf, NULL); ++ ++ parser = cr_parser_new_from_buf ((guchar*)a_char_buf, strlen ((const char *) a_char_buf), ++ a_enc, FALSE); ++ g_return_val_if_fail (parser, NULL); ++ ++ return NULL; ++} ++ ++/** ++ * cr_selector_append: ++ * ++ *@a_this: the current instance of #CRSelector. ++ *@a_new: the instance of #CRSelector to be appended. ++ * ++ *Appends a new instance of #CRSelector to the current selector list. ++ * ++ *Returns the new list. ++ */ ++CRSelector * ++cr_selector_append (CRSelector * a_this, CRSelector * a_new) ++{ ++ CRSelector *cur = NULL; ++ ++ if (!a_this) { ++ return a_new; ++ } ++ ++ /*walk forward the list headed by a_this to get the list tail */ ++ for (cur = a_this; cur && cur->next; cur = cur->next) ; ++ ++ cur->next = a_new; ++ a_new->prev = cur; ++ ++ return a_this; ++} ++ ++/** ++ * cr_selector_prepend: ++ * ++ *@a_this: the current instance of #CRSelector list. ++ *@a_new: the instance of #CRSelector. ++ * ++ *Prepends an element to the #CRSelector list. ++ * ++ *Returns the new list. ++ */ ++CRSelector * ++cr_selector_prepend (CRSelector * a_this, CRSelector * a_new) ++{ ++ CRSelector *cur = NULL; ++ ++ a_new->next = a_this; ++ a_this->prev = a_new; ++ ++ for (cur = a_new; cur && cur->prev; cur = cur->prev) ; ++ ++ return cur; ++} ++ ++/** ++ * cr_selector_append_simple_sel: ++ * ++ *@a_this: the current instance of #CRSelector. ++ *@a_simple_sel: the simple selector to append. ++ * ++ *append a simple selector to the current #CRSelector list. ++ * ++ *Returns the new list or NULL in case of failure. ++ */ ++CRSelector * ++cr_selector_append_simple_sel (CRSelector * a_this, ++ CRSimpleSel * a_simple_sel) ++{ ++ CRSelector *selector = NULL; ++ ++ selector = cr_selector_new (a_simple_sel); ++ g_return_val_if_fail (selector, NULL); ++ ++ return cr_selector_append (a_this, selector); ++} ++ ++guchar * ++cr_selector_to_string (CRSelector const * a_this) ++{ ++ guchar *result = NULL; ++ GString *str_buf = NULL; ++ ++ str_buf = g_string_new (NULL); ++ g_return_val_if_fail (str_buf, NULL); ++ ++ if (a_this) { ++ CRSelector const *cur = NULL; ++ ++ for (cur = a_this; cur; cur = cur->next) { ++ if (cur->simple_sel) { ++ guchar *tmp_str = NULL; ++ ++ tmp_str = cr_simple_sel_to_string ++ (cur->simple_sel); ++ ++ if (tmp_str) { ++ if (cur->prev) ++ g_string_append (str_buf, ++ ", "); ++ ++ g_string_append (str_buf, (const gchar *) tmp_str); ++ ++ g_free (tmp_str); ++ tmp_str = NULL; ++ } ++ } ++ } ++ } ++ ++ if (str_buf) { ++ result = (guchar *) str_buf->str; ++ g_string_free (str_buf, FALSE); ++ str_buf = NULL; ++ } ++ ++ return result; ++} ++ ++/** ++ * cr_selector_dump: ++ * ++ *@a_this: the current instance of #CRSelector. ++ *@a_fp: the destination file. ++ * ++ *Serializes the current instance of #CRSelector to a file. ++ */ ++void ++cr_selector_dump (CRSelector const * a_this, FILE * a_fp) ++{ ++ guchar *tmp_buf = NULL; ++ ++ if (a_this) { ++ tmp_buf = cr_selector_to_string (a_this); ++ if (tmp_buf) { ++ fprintf (a_fp, "%s", tmp_buf); ++ g_free (tmp_buf); ++ tmp_buf = NULL; ++ } ++ } ++} ++ ++/** ++ * cr_selector_ref: ++ * ++ *@a_this: the current instance of #CRSelector. ++ * ++ *Increments the ref count of the current instance ++ *of #CRSelector. ++ */ ++void ++cr_selector_ref (CRSelector * a_this) ++{ ++ g_return_if_fail (a_this); ++ ++ a_this->ref_count++; ++} ++ ++/** ++ * cr_selector_unref: ++ * ++ *@a_this: the current instance of #CRSelector. ++ * ++ *Decrements the ref count of the current instance of ++ *#CRSelector. ++ *If the ref count reaches zero, the current instance of ++ *#CRSelector is destroyed. ++ * ++ *Returns TRUE if this function destroyed the current instance ++ *of #CRSelector, FALSE otherwise. ++ */ ++gboolean ++cr_selector_unref (CRSelector * a_this) ++{ ++ g_return_val_if_fail (a_this, FALSE); ++ ++ if (a_this->ref_count) { ++ a_this->ref_count--; ++ } ++ ++ if (a_this->ref_count == 0) { ++ cr_selector_destroy (a_this); ++ return TRUE; ++ } ++ ++ return FALSE; ++} ++ ++/** ++ * cr_selector_destroy: ++ * ++ *@a_this: the current instance of #CRSelector. ++ * ++ *Destroys the selector list. ++ */ ++void ++cr_selector_destroy (CRSelector * a_this) ++{ ++ CRSelector *cur = NULL; ++ ++ g_return_if_fail (a_this); ++ ++ /* ++ *go and get the list tail. In the same time, free ++ *all the simple selectors contained in the list. ++ */ ++ for (cur = a_this; cur && cur->next; cur = cur->next) { ++ if (cur->simple_sel) { ++ cr_simple_sel_destroy (cur->simple_sel); ++ cur->simple_sel = NULL; ++ } ++ } ++ ++ if (cur) { ++ if (cur->simple_sel) { ++ cr_simple_sel_destroy (cur->simple_sel); ++ cur->simple_sel = NULL; ++ } ++ } ++ ++ /*in case the list has only one element */ ++ if (cur && !cur->prev) { ++ g_free (cur); ++ return; ++ } ++ ++ /*walk backward the list and free each "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; ++ ++ if (cur->next) { ++ g_free (cur->next); ++ cur->next = NULL; ++ } ++ ++ g_free (cur); ++} +diff --git a/src/st/croco/cr-selector.h b/src/st/croco/cr-selector.h +new file mode 100644 +index 000000000..dd6a7f786 +--- /dev/null ++++ b/src/st/croco/cr-selector.h +@@ -0,0 +1,95 @@ ++/* -*- Mode: C; indent-tabs-mode: nil; c-basic-offset: 8 -*- */ ++ ++/* ++ * This file is part of The Croco Library ++ * ++ * 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 ++ * See COPYRIGHTS file for copyright information. ++ */ ++ ++#ifndef __CR_SELECTOR_H__ ++#define __CR_SELECTOR_H__ ++ ++#include ++#include "cr-utils.h" ++#include "cr-simple-sel.h" ++#include "cr-parsing-location.h" ++ ++/** ++ *@file ++ *The declaration file of the #CRSelector file. ++ */ ++ ++G_BEGIN_DECLS ++ ++typedef struct _CRSelector CRSelector ; ++ ++/** ++ *Abstracts a CSS2 selector as defined in the right part ++ *of the 'ruleset" production in the appendix D.1 of the ++ *css2 spec. ++ *It is actually the abstraction of a comma separated list ++ *of simple selectors list. ++ *In a css2 file, a selector is a list of simple selectors ++ *separated by a comma. ++ *e.g: sel0, sel1, sel2 ... ++ *Each seln is a simple selector ++ */ ++struct _CRSelector ++{ ++ /** ++ *A Selection expression. ++ *It is a list of basic selectors. ++ *Each basic selector can be either an element ++ *selector, an id selector, a class selector, an ++ *attribute selector, an universal selector etc ... ++ */ ++ CRSimpleSel *simple_sel ; ++ ++ /**The next selector list element*/ ++ CRSelector *next ; ++ CRSelector *prev ; ++ CRParsingLocation location ; ++ glong ref_count ; ++}; ++ ++CRSelector* cr_selector_new (CRSimpleSel *a_sel_expr) ; ++ ++CRSelector * cr_selector_parse_from_buf (const guchar * a_char_buf, ++ enum CREncoding a_enc) ; ++ ++CRSelector* cr_selector_append (CRSelector *a_this, CRSelector *a_new) ; ++ ++CRSelector* cr_selector_append_simple_sel (CRSelector *a_this, ++ CRSimpleSel *a_simple_sel) ; ++ ++CRSelector* cr_selector_prepend (CRSelector *a_this, CRSelector *a_new) ; ++ ++guchar * cr_selector_to_string (CRSelector const *a_this) ; ++ ++void cr_selector_dump (CRSelector const *a_this, FILE *a_fp) ; ++ ++void cr_selector_ref (CRSelector *a_this) ; ++ ++gboolean cr_selector_unref (CRSelector *a_this) ; ++ ++void cr_selector_destroy (CRSelector *a_this) ; ++ ++G_END_DECLS ++ ++#endif /*__CR_SELECTOR_H__*/ +diff --git a/src/st/croco/cr-simple-sel.c b/src/st/croco/cr-simple-sel.c +new file mode 100644 +index 000000000..ac906858d +--- /dev/null ++++ b/src/st/croco/cr-simple-sel.c +@@ -0,0 +1,325 @@ ++/* -*- Mode: C; indent-tabs-mode:nil; c-basic-offset: 8-*- */ ++ ++/* ++ * This file is part of The Croco Library ++ * ++ * 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 ++ * See COPYRIGHTS file for copyright information. ++ */ ++ ++#include ++#include ++#include "cr-simple-sel.h" ++ ++/** ++ * cr_simple_sel_new: ++ * ++ *The constructor of #CRSimpleSel. ++ * ++ *Returns the new instance of #CRSimpleSel. ++ */ ++CRSimpleSel * ++cr_simple_sel_new (void) ++{ ++ CRSimpleSel *result = NULL; ++ ++ result = g_try_malloc (sizeof (CRSimpleSel)); ++ if (!result) { ++ cr_utils_trace_info ("Out of memory"); ++ return NULL; ++ } ++ memset (result, 0, sizeof (CRSimpleSel)); ++ ++ return result; ++} ++ ++/** ++ * cr_simple_sel_append_simple_sel: ++ * ++ *Appends a simpe selector to the current list of simple selector. ++ * ++ *@a_this: the this pointer of the current instance of #CRSimpleSel. ++ *@a_sel: the simple selector to append. ++ * ++ *Returns: the new list upon successfull completion, an error code otherwise. ++ */ ++CRSimpleSel * ++cr_simple_sel_append_simple_sel (CRSimpleSel * a_this, CRSimpleSel * a_sel) ++{ ++ CRSimpleSel *cur = NULL; ++ ++ g_return_val_if_fail (a_sel, NULL); ++ ++ if (a_this == NULL) ++ return a_sel; ++ ++ for (cur = a_this; cur->next; cur = cur->next) ; ++ ++ cur->next = a_sel; ++ a_sel->prev = cur; ++ ++ return a_this; ++} ++ ++/** ++ * cr_simple_sel_prepend_simple_sel: ++ * ++ *@a_this: the this pointer of the current instance of #CRSimpleSel. ++ *@a_sel: the simple selector to prepend. ++ * ++ *Prepends a simple selector to the current list of simple selectors. ++ * ++ *Returns the new list upon successfull completion, an error code otherwise. ++ */ ++CRSimpleSel * ++cr_simple_sel_prepend_simple_sel (CRSimpleSel * a_this, CRSimpleSel * a_sel) ++{ ++ g_return_val_if_fail (a_sel, NULL); ++ ++ if (a_this == NULL) ++ return a_sel; ++ ++ a_sel->next = a_this; ++ a_this->prev = a_sel; ++ ++ return a_sel; ++} ++ ++guchar * ++cr_simple_sel_to_string (CRSimpleSel const * a_this) ++{ ++ GString *str_buf = NULL; ++ guchar *result = NULL; ++ ++ CRSimpleSel const *cur = NULL; ++ ++ g_return_val_if_fail (a_this, NULL); ++ ++ str_buf = g_string_new (NULL); ++ for (cur = a_this; cur; cur = cur->next) { ++ if (cur->name) { ++ guchar *str = (guchar *) g_strndup (cur->name->stryng->str, ++ cur->name->stryng->len); ++ ++ if (str) { ++ switch (cur->combinator) { ++ case COMB_WS: ++ g_string_append (str_buf, " "); ++ break; ++ ++ case COMB_PLUS: ++ g_string_append (str_buf, "+"); ++ break; ++ ++ case COMB_GT: ++ g_string_append (str_buf, ">"); ++ break; ++ ++ default: ++ break; ++ } ++ ++ g_string_append (str_buf, (const gchar *) str); ++ g_free (str); ++ str = NULL; ++ } ++ } ++ ++ if (cur->add_sel) { ++ guchar *tmp_str = NULL; ++ ++ tmp_str = cr_additional_sel_to_string (cur->add_sel); ++ if (tmp_str) { ++ g_string_append (str_buf, (const gchar *) tmp_str); ++ g_free (tmp_str); ++ tmp_str = NULL; ++ } ++ } ++ } ++ ++ if (str_buf) { ++ result = (guchar *) str_buf->str; ++ g_string_free (str_buf, FALSE); ++ str_buf = NULL; ++ } ++ ++ return result; ++} ++ ++ ++guchar * ++cr_simple_sel_one_to_string (CRSimpleSel const * a_this) ++{ ++ GString *str_buf = NULL; ++ guchar *result = NULL; ++ ++ g_return_val_if_fail (a_this, NULL); ++ ++ str_buf = g_string_new (NULL); ++ if (a_this->name) { ++ guchar *str = (guchar *) g_strndup (a_this->name->stryng->str, ++ a_this->name->stryng->len); ++ ++ if (str) { ++ g_string_append_printf (str_buf, "%s", str); ++ g_free (str); ++ str = NULL; ++ } ++ } ++ ++ if (a_this->add_sel) { ++ guchar *tmp_str = NULL; ++ ++ tmp_str = cr_additional_sel_to_string (a_this->add_sel); ++ if (tmp_str) { ++ g_string_append_printf ++ (str_buf, "%s", tmp_str); ++ g_free (tmp_str); ++ tmp_str = NULL; ++ } ++ } ++ ++ if (str_buf) { ++ result = (guchar *) str_buf->str; ++ g_string_free (str_buf, FALSE); ++ str_buf = NULL; ++ } ++ ++ return result; ++} ++ ++/** ++ * cr_simple_sel_dump: ++ *@a_this: the current instance of #CRSimpleSel. ++ *@a_fp: the destination file pointer. ++ * ++ *Dumps the selector to a file. ++ *TODO: add the support of unicode in the dump. ++ * ++ *Returns CR_OK upon successfull completion, an error code ++ *otherwise. ++ */ ++enum CRStatus ++cr_simple_sel_dump (CRSimpleSel const * a_this, FILE * a_fp) ++{ ++ guchar *tmp_str = NULL; ++ ++ g_return_val_if_fail (a_fp, CR_BAD_PARAM_ERROR); ++ ++ if (a_this) { ++ tmp_str = cr_simple_sel_to_string (a_this); ++ if (tmp_str) { ++ fprintf (a_fp, "%s", tmp_str); ++ g_free (tmp_str); ++ tmp_str = NULL; ++ } ++ } ++ ++ return CR_OK; ++} ++ ++/** ++ * cr_simple_sel_compute_specificity: ++ * ++ *@a_this: the current instance of #CRSimpleSel ++ * ++ *Computes the selector (combinator separated list of simple selectors) ++ *as defined in the css2 spec in chapter 6.4.3 ++ * ++ *Returns CR_OK upon successfull completion, an error code otherwise. ++ */ ++enum CRStatus ++cr_simple_sel_compute_specificity (CRSimpleSel * a_this) ++{ ++ CRAdditionalSel const *cur_add_sel = NULL; ++ CRSimpleSel const *cur_sel = NULL; ++ gulong a = 0, ++ b = 0, ++ c = 0; ++ ++ g_return_val_if_fail (a_this, CR_BAD_PARAM_ERROR); ++ ++ for (cur_sel = a_this; cur_sel; cur_sel = cur_sel->next) { ++ if (cur_sel->type_mask & TYPE_SELECTOR) { ++ c++; /*hmmh, is this a new language ? */ ++ } else if (!cur_sel->name ++ || !cur_sel->name->stryng ++ || !cur_sel->name->stryng->str) { ++ if (cur_sel->add_sel->type == ++ PSEUDO_CLASS_ADD_SELECTOR) { ++ /* ++ *this is a pseudo element, and ++ *the spec says, "ignore pseudo elements". ++ */ ++ continue; ++ } ++ } ++ ++ for (cur_add_sel = cur_sel->add_sel; ++ cur_add_sel; cur_add_sel = cur_add_sel->next) { ++ switch (cur_add_sel->type) { ++ case ID_ADD_SELECTOR: ++ a++; ++ break; ++ ++ case NO_ADD_SELECTOR: ++ continue; ++ ++ default: ++ b++; ++ break; ++ } ++ } ++ } ++ ++ /*we suppose a, b and c have 1 to 3 digits */ ++ a_this->specificity = a * 1000000 + b * 1000 + c; ++ ++ return CR_OK; ++} ++ ++/** ++ * cr_simple_sel_destroy: ++ * ++ *@a_this: the this pointer of the current instance of #CRSimpleSel. ++ * ++ *The destructor of the current instance of ++ *#CRSimpleSel. ++ */ ++void ++cr_simple_sel_destroy (CRSimpleSel * a_this) ++{ ++ g_return_if_fail (a_this); ++ ++ if (a_this->name) { ++ cr_string_destroy (a_this->name); ++ a_this->name = NULL; ++ } ++ ++ if (a_this->add_sel) { ++ cr_additional_sel_destroy (a_this->add_sel); ++ a_this->add_sel = NULL; ++ } ++ ++ if (a_this->next) { ++ cr_simple_sel_destroy (a_this->next); ++ } ++ ++ if (a_this) { ++ g_free (a_this); ++ } ++} +diff --git a/src/st/croco/cr-simple-sel.h b/src/st/croco/cr-simple-sel.h +new file mode 100644 +index 000000000..d8edc0025 +--- /dev/null ++++ b/src/st/croco/cr-simple-sel.h +@@ -0,0 +1,130 @@ ++/* -*- Mode: C; indent-tabs-mode:nil; c-basic-offset: 8-*- */ ++ ++/* ++ * This file is part of The Croco Library ++ * ++ * 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 ++ * See COPYRIGHTS file for copyright information. ++ */ ++ ++ ++#ifndef __CR_SEL_H__ ++#define __CR_SEL_H__ ++ ++#include ++#include ++#include "cr-additional-sel.h" ++#include "cr-parsing-location.h" ++ ++G_BEGIN_DECLS ++ ++/** ++ *@file ++ *the declaration of the #CRSimpleSel class. ++ * ++ */ ++enum Combinator ++{ ++ NO_COMBINATOR, ++ COMB_WS,/*whitespace: descendent*/ ++ COMB_PLUS,/*'+': preceded by*/ ++ COMB_GT/*greater than ('>'): child*/ ++} ; ++ ++enum SimpleSelectorType ++{ ++ NO_SELECTOR_TYPE = 0, ++ UNIVERSAL_SELECTOR = 1, ++ TYPE_SELECTOR = 1 << 1 ++} ; ++ ++typedef struct _CRSimpleSel CRSimpleSel ; ++ ++/** ++ *The abstraction of a css2 simple selection list ++ *as defined by the right part of the "selector" production in the ++ *appendix D.1 of the css2 spec. ++ *It is basically a list of simple selector, each ++ *simple selector being separated by a combinator. ++ * ++ *In the libcroco's implementation, each simple selector ++ *is made of at most two parts: ++ * ++ *1/An element name or 'type selector' (which can hold a '*' and ++ *then been called 'universal selector') ++ * ++ *2/An additional selector that "specializes" the preceding type or ++ *universal selector. The additionnal selector can be either ++ *an id selector, or a class selector, or an attribute selector. ++ */ ++struct _CRSimpleSel ++{ ++ enum SimpleSelectorType type_mask ; ++ gboolean is_case_sentive ; ++ CRString * name ; ++ /** ++ *The combinator that separates ++ *this simple selector from the previous ++ *one. ++ */ ++ enum Combinator combinator ; ++ ++ /** ++ *The additional selector list of the ++ *current simple selector. ++ *An additional selector may ++ *be a class selector, an id selector, ++ *or an attribute selector. ++ *Note that this field is a linked list. ++ */ ++ CRAdditionalSel *add_sel ; ++ ++ /* ++ *the specificity as specified by ++ *chapter 6.4.3 of the spec. ++ */ ++ gulong specificity ; ++ ++ CRSimpleSel *next ; ++ CRSimpleSel *prev ; ++ CRParsingLocation location ; ++} ; ++ ++CRSimpleSel * cr_simple_sel_new (void) ; ++ ++CRSimpleSel * cr_simple_sel_append_simple_sel (CRSimpleSel *a_this, ++ CRSimpleSel *a_sel) ; ++ ++CRSimpleSel * cr_simple_sel_prepend_simple_sel (CRSimpleSel *a_this, ++ CRSimpleSel *a_sel) ; ++ ++guchar * cr_simple_sel_to_string (CRSimpleSel const *a_this) ; ++ ++guchar * cr_simple_sel_one_to_string (CRSimpleSel const * a_this) ; ++ ++enum CRStatus cr_simple_sel_dump (CRSimpleSel const *a_this, FILE *a_fp) ; ++ ++enum CRStatus cr_simple_sel_dump_attr_sel_list (CRSimpleSel const *a_this) ; ++ ++enum CRStatus cr_simple_sel_compute_specificity (CRSimpleSel *a_this) ; ++ ++void cr_simple_sel_destroy (CRSimpleSel *a_this) ; ++ ++G_END_DECLS ++ ++ ++#endif /*__CR_SIMPLE_SEL_H__*/ +diff --git a/src/st/croco/cr-statement.c b/src/st/croco/cr-statement.c +new file mode 100644 +index 000000000..241fa5f3b +--- /dev/null ++++ b/src/st/croco/cr-statement.c +@@ -0,0 +1,2794 @@ ++/* -*- Mode: C; indent-tabs-mode: nil; c-basic-offset: 8 -*- */ ++ ++/* ++ * This file is part of The Croco Library ++ * ++ * 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. ++ * See COPYRIGHTS files for copyrights information. ++ */ ++ ++#include ++#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; ++} +diff --git a/src/st/croco/cr-statement.h b/src/st/croco/cr-statement.h +new file mode 100644 +index 000000000..74a233055 +--- /dev/null ++++ b/src/st/croco/cr-statement.h +@@ -0,0 +1,440 @@ ++/* -*- Mode: C; indent-tabs-mode: nil; c-basic-offset: 8 -*- */ ++ ++/* ++ * This file is part of The Croco Library ++ * ++ * 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 ++ * See COPYRIGHTS file for copyright information. ++ */ ++ ++#include ++#include "cr-utils.h" ++#include "cr-term.h" ++#include "cr-selector.h" ++#include "cr-declaration.h" ++ ++#ifndef __CR_STATEMENT_H__ ++#define __CR_STATEMENT_H__ ++ ++G_BEGIN_DECLS ++ ++/** ++ *@file ++ *Declaration of the #CRStatement class. ++ */ ++ ++/* ++ *forward declaration of CRStyleSheet which is defined in ++ *cr-stylesheet.h ++ */ ++ ++struct _CRStatement ; ++ ++/* ++ *typedef struct _CRStatement CRStatement ; ++ *this is forward declared in ++ *cr-declaration.h already. ++ */ ++ ++struct _CRAtMediaRule ; ++typedef struct _CRAtMediaRule CRAtMediaRule ; ++ ++typedef struct _CRRuleSet CRRuleSet ; ++ ++/** ++ *The abstraction of a css ruleset. ++ *A ruleset is made of a list of selectors, ++ *followed by a list of declarations. ++ */ ++struct _CRRuleSet ++{ ++ /**A list of instances of #CRSimpeSel*/ ++ CRSelector *sel_list ; ++ ++ /**A list of instances of #CRDeclaration*/ ++ CRDeclaration *decl_list ; ++ ++ /** ++ *The parent media rule, or NULL if ++ *no parent media rule exists. ++ */ ++ CRStatement *parent_media_rule ; ++} ; ++ ++/* ++ *a forward declaration of CRStylesheet. ++ *CRStylesheet is actually declared in ++ *cr-stylesheet.h ++ */ ++struct _CRStyleSheet ; ++typedef struct _CRStyleSheet CRStyleSheet; ++ ++ ++/**The \@import rule abstraction.*/ ++typedef struct _CRAtImportRule CRAtImportRule ; ++struct _CRAtImportRule ++{ ++ /**the url of the import rule*/ ++ CRString *url ; ++ ++ GList *media_list ; ++ ++ /** ++ *the stylesheet fetched from the url, if any. ++ *this is not "owned" by #CRAtImportRule which means ++ *it is not destroyed by the destructor of #CRAtImportRule. ++ */ ++ CRStyleSheet * sheet; ++}; ++ ++ ++/**abstraction of an \@media rule*/ ++struct _CRAtMediaRule ++{ ++ GList *media_list ; ++ CRStatement *rulesets ; ++} ; ++ ++ ++typedef struct _CRAtPageRule CRAtPageRule ; ++/**The \@page rule abstraction*/ ++struct _CRAtPageRule ++{ ++ /**a list of instances of #CRDeclaration*/ ++ CRDeclaration *decl_list ; ++ ++ /**page selector. Is a pseudo selector*/ ++ CRString *name ; ++ CRString *pseudo ; ++} ; ++ ++/**The \@charset rule abstraction*/ ++typedef struct _CRAtCharsetRule CRAtCharsetRule ; ++struct _CRAtCharsetRule ++{ ++ CRString * charset ; ++}; ++ ++/**The abstaction of the \@font-face rule.*/ ++typedef struct _CRAtFontFaceRule CRAtFontFaceRule ; ++struct _CRAtFontFaceRule ++{ ++ /*a list of instanaces of #CRDeclaration*/ ++ CRDeclaration *decl_list ; ++} ; ++ ++ ++/** ++ *The possible types of css2 statements. ++ */ ++enum CRStatementType ++{ ++ /** ++ *A generic css at-rule ++ *each unknown at-rule will ++ *be of this type. ++ */ ++ ++ /**A css at-rule*/ ++ AT_RULE_STMT = 0, ++ ++ /*A css ruleset*/ ++ RULESET_STMT, ++ ++ /**A css2 import rule*/ ++ AT_IMPORT_RULE_STMT, ++ ++ /**A css2 media rule*/ ++ AT_MEDIA_RULE_STMT, ++ ++ /**A css2 page rule*/ ++ AT_PAGE_RULE_STMT, ++ ++ /**A css2 charset rule*/ ++ AT_CHARSET_RULE_STMT, ++ ++ /**A css2 font face rule*/ ++ AT_FONT_FACE_RULE_STMT ++} ; ++ ++ ++/** ++ *The abstraction of css statement as defined ++ *in the chapter 4 and appendix D.1 of the css2 spec. ++ *A statement is actually a double chained list of ++ *statements.A statement can be a ruleset, an \@import ++ *rule, an \@page rule etc ... ++ */ ++struct _CRStatement ++{ ++ /** ++ *The type of the statement. ++ */ ++ enum CRStatementType type ; ++ ++ union ++ { ++ CRRuleSet *ruleset ; ++ CRAtImportRule *import_rule ; ++ CRAtMediaRule *media_rule ; ++ CRAtPageRule *page_rule ; ++ CRAtCharsetRule *charset_rule ; ++ CRAtFontFaceRule *font_face_rule ; ++ } kind ; ++ ++ /* ++ *the specificity of the selector ++ *that matched this statement. ++ *This is only used by the cascading ++ *order determination algorithm. ++ */ ++ gulong specificity ; ++ ++ /* ++ *the style sheet that contains ++ *this css statement. ++ */ ++ CRStyleSheet *parent_sheet ; ++ CRStatement *next ; ++ CRStatement *prev ; ++ ++ CRParsingLocation location ; ++ ++ /** ++ *a custom pointer useable by ++ *applications that use libcroco. ++ *libcroco itself will never modify ++ *this pointer. ++ */ ++ gpointer app_data ; ++ ++ /** ++ *a custom pointer used ++ *by the upper layers of libcroco. ++ *application should never use this ++ *pointer. ++ */ ++ gpointer croco_data ; ++ ++} ; ++ ++ ++gboolean ++cr_statement_does_buf_parses_against_core (const guchar *a_buf, ++ enum CREncoding a_encoding) ; ++CRStatement * ++cr_statement_parse_from_buf (const guchar *a_buf, ++ enum CREncoding a_encoding) ; ++CRStatement* ++cr_statement_new_ruleset (CRStyleSheet *a_sheet, ++ CRSelector *a_sel_list, ++ CRDeclaration *a_decl_list, ++ CRStatement *a_media_rule) ; ++CRStatement * ++cr_statement_ruleset_parse_from_buf (const guchar * a_buf, ++ enum CREncoding a_enc) ; ++ ++CRStatement* ++cr_statement_new_at_import_rule (CRStyleSheet *a_container_sheet, ++ CRString *a_url, ++ GList *a_media_list, ++ CRStyleSheet *a_imported_sheet) ; ++ ++CRStatement * ++cr_statement_at_import_rule_parse_from_buf (const guchar * a_buf, ++ enum CREncoding a_encoding) ; ++ ++CRStatement * ++cr_statement_new_at_media_rule (CRStyleSheet *a_sheet, ++ CRStatement *a_ruleset, ++ GList *a_media) ; ++CRStatement * ++cr_statement_at_media_rule_parse_from_buf (const guchar *a_buf, ++ enum CREncoding a_enc) ; ++ ++CRStatement * ++cr_statement_new_at_charset_rule (CRStyleSheet *a_sheet, ++ CRString *a_charset) ; ++CRStatement * ++cr_statement_at_charset_rule_parse_from_buf (const guchar *a_buf, ++ enum CREncoding a_encoding); ++ ++ ++CRStatement * ++cr_statement_new_at_font_face_rule (CRStyleSheet *a_sheet, ++ CRDeclaration *a_font_decls) ; ++CRStatement * ++cr_statement_font_face_rule_parse_from_buf (const guchar *a_buf, ++ enum CREncoding a_encoding) ; ++ ++CRStatement * ++cr_statement_new_at_page_rule (CRStyleSheet *a_sheet, ++ CRDeclaration *a_decl_list, ++ CRString *a_name, ++ CRString *a_pseudo) ; ++CRStatement * ++cr_statement_at_page_rule_parse_from_buf (const guchar *a_buf, ++ enum CREncoding a_encoding) ; ++ ++enum CRStatus ++cr_statement_set_parent_sheet (CRStatement *a_this, ++ CRStyleSheet *a_sheet) ; ++ ++enum CRStatus ++cr_statement_get_parent_sheet (CRStatement *a_this, ++ CRStyleSheet **a_sheet) ; ++ ++CRStatement * ++cr_statement_append (CRStatement *a_this, ++ CRStatement *a_new) ; ++ ++CRStatement* ++cr_statement_prepend (CRStatement *a_this, ++ CRStatement *a_new) ; ++ ++CRStatement * ++cr_statement_unlink (CRStatement *a_stmt) ; ++ ++enum CRStatus ++cr_statement_ruleset_set_sel_list (CRStatement *a_this, ++ CRSelector *a_sel_list) ; ++ ++enum CRStatus ++cr_statement_ruleset_get_sel_list (CRStatement const *a_this, ++ CRSelector **a_list) ; ++ ++enum CRStatus ++cr_statement_ruleset_set_decl_list (CRStatement *a_this, ++ CRDeclaration *a_list) ; ++ ++enum CRStatus ++cr_statement_ruleset_get_declarations (CRStatement *a_this, ++ CRDeclaration **a_decl_list) ; ++ ++enum CRStatus ++cr_statement_ruleset_append_decl2 (CRStatement *a_this, ++ CRString *a_prop, CRTerm *a_value) ; ++ ++enum CRStatus ++cr_statement_ruleset_append_decl (CRStatement *a_this, ++ CRDeclaration *a_decl) ; ++ ++enum CRStatus ++cr_statement_at_import_rule_set_imported_sheet (CRStatement *a_this, ++ CRStyleSheet *a_sheet) ; ++ ++enum CRStatus ++cr_statement_at_import_rule_get_imported_sheet (CRStatement *a_this, ++ CRStyleSheet **a_sheet) ; ++ ++enum CRStatus ++cr_statement_at_import_rule_set_url (CRStatement *a_this, ++ CRString *a_url) ; ++ ++enum CRStatus ++cr_statement_at_import_rule_get_url (CRStatement const *a_this, ++ CRString **a_url) ; ++ ++gint ++cr_statement_at_media_nr_rules (CRStatement const *a_this) ; ++ ++CRStatement * ++cr_statement_at_media_get_from_list (CRStatement *a_this, int itemnr) ; ++ ++enum CRStatus ++cr_statement_at_page_rule_set_sel (CRStatement *a_this, ++ CRSelector *a_sel) ; ++ ++enum CRStatus ++cr_statement_at_page_rule_get_sel (CRStatement const *a_this, ++ CRSelector **a_sel) ; ++ ++enum CRStatus ++cr_statement_at_page_rule_set_declarations (CRStatement *a_this, ++ CRDeclaration *a_decl_list) ; ++ ++enum CRStatus ++cr_statement_at_page_rule_get_declarations (CRStatement *a_this, ++ CRDeclaration **a_decl_list) ; ++ ++enum CRStatus ++cr_statement_at_charset_rule_set_charset (CRStatement *a_this, ++ CRString *a_charset) ; ++ ++enum CRStatus ++cr_statement_at_charset_rule_get_charset (CRStatement const *a_this, ++ CRString **a_charset) ; ++ ++enum CRStatus ++cr_statement_at_font_face_rule_set_decls (CRStatement *a_this, ++ CRDeclaration *a_decls) ; ++ ++enum CRStatus ++cr_statement_at_font_face_rule_get_decls (CRStatement *a_this, ++ CRDeclaration **a_decls) ; ++ ++enum CRStatus ++cr_statement_at_font_face_rule_add_decl (CRStatement *a_this, ++ CRString *a_prop, ++ CRTerm *a_value) ; ++ ++gchar * ++cr_statement_to_string (CRStatement const * a_this, gulong a_indent) ; ++ ++gchar* ++cr_statement_list_to_string (CRStatement const *a_this, gulong a_indent) ; ++ ++void ++cr_statement_dump (CRStatement const *a_this, FILE *a_fp, gulong a_indent) ; ++ ++void ++cr_statement_dump_ruleset (CRStatement const * a_this, FILE * a_fp, ++ glong a_indent) ; ++ ++void ++cr_statement_dump_font_face_rule (CRStatement const * a_this, ++ FILE * a_fp, ++ glong a_indent) ; ++ ++void ++cr_statement_dump_page (CRStatement const * a_this, FILE * a_fp, ++ gulong a_indent) ; ++ ++ ++void ++cr_statement_dump_media_rule (CRStatement const * a_this, ++ FILE * a_fp, ++ gulong a_indent) ; ++ ++void ++cr_statement_dump_import_rule (CRStatement const * a_this, FILE * a_fp, ++ gulong a_indent) ; ++void ++cr_statement_dump_charset (CRStatement const * a_this, FILE * a_fp, ++ gulong a_indent) ; ++gint ++cr_statement_nr_rules (CRStatement const *a_this) ; ++ ++CRStatement * ++cr_statement_get_from_list (CRStatement *a_this, int itemnr) ; ++ ++void ++cr_statement_destroy (CRStatement *a_this) ; ++ ++G_END_DECLS ++ ++#endif /*__CR_STATEMENT_H__*/ +diff --git a/src/st/croco/cr-string.c b/src/st/croco/cr-string.c +new file mode 100644 +index 000000000..1b10bb2ab +--- /dev/null ++++ b/src/st/croco/cr-string.c +@@ -0,0 +1,168 @@ ++/* -*- Mode: C; indent-tabs-mode:nil; c-basic-offset: 8-*- */ ++ ++/* ++ * This file is part of The Croco Library ++ * ++ * 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. ++ * See COPYRIGHTS file for copyright information. ++ */ ++ ++#include ++#include "cr-string.h" ++ ++/** ++ *Instanciates a #CRString ++ *@return the newly instanciated #CRString ++ *Must be freed with cr_string_destroy(). ++ */ ++CRString * ++cr_string_new (void) ++{ ++ CRString *result = NULL ; ++ ++ result = g_try_malloc (sizeof (CRString)) ; ++ if (!result) { ++ cr_utils_trace_info ("Out of memory") ; ++ return NULL ; ++ } ++ memset (result, 0, sizeof (CRString)) ; ++ result->stryng = g_string_new (NULL) ; ++ return result ; ++} ++ ++/** ++ *Instanciate a string and initialise it to ++ *a_string. ++ *@param a_string the initial string ++ *@return the newly instanciated string. ++ */ ++CRString * ++cr_string_new_from_string (const gchar * a_string) ++{ ++ CRString *result = NULL ; ++ ++ result = cr_string_new () ; ++ if (!result) { ++ cr_utils_trace_info ("Out of memory") ; ++ return NULL ; ++ } ++ if (a_string) ++ g_string_append (result->stryng, a_string) ; ++ return result ; ++} ++ ++/** ++ *Instanciates a #CRString from an instance of GString. ++ *@param a_string the input string that will be copied into ++ *the newly instanciated #CRString ++ *@return the newly instanciated #CRString. ++ */ ++CRString * ++cr_string_new_from_gstring (GString const *a_string) ++{ ++ CRString *result = NULL ; ++ ++ result = cr_string_new () ; ++ if (!result) { ++ cr_utils_trace_info ("Out of memory") ; ++ return NULL ; ++ } ++ if (a_string) { ++ g_string_append_len (result->stryng, ++ a_string->str, ++ a_string->len); ++ ++ } ++ return result ; ++} ++ ++CRString * ++cr_string_dup (CRString const *a_this) ++{ ++ CRString *result = NULL ; ++ g_return_val_if_fail (a_this, NULL) ; ++ ++ result = cr_string_new_from_gstring (a_this->stryng) ; ++ if (!result) { ++ cr_utils_trace_info ("Out of memory") ; ++ return NULL ; ++ } ++ cr_parsing_location_copy (&result->location, ++ &a_this->location) ; ++ return result ; ++} ++ ++gchar * ++cr_string_dup2 (CRString const *a_this) ++{ ++ gchar *result = NULL ; ++ ++ g_return_val_if_fail (a_this, NULL) ; ++ ++ if (a_this ++ && a_this->stryng ++ && a_this->stryng->str) { ++ result = g_strndup (a_this->stryng->str, ++ a_this->stryng->len) ; ++ } ++ return result ; ++} ++ ++/** ++ *Returns a pointer to the internal raw NULL terminated string ++ *of the current instance of #CRString. ++ *@param a_this the current instance of #CRString ++ */ ++const gchar * ++cr_string_peek_raw_str (CRString const *a_this) ++{ ++ g_return_val_if_fail (a_this, NULL) ; ++ ++ if (a_this->stryng && a_this->stryng->str) ++ return a_this->stryng->str ; ++ return NULL ; ++} ++ ++/** ++ *Returns the length of the internal raw NULL terminated ++ *string of the current instance of #CRString. ++ *@param a_this the current instance of #CRString. ++ *@return the len of the internal raw NULL termninated string, ++ *of -1 if no length can be returned. ++ */ ++gint ++cr_string_peek_raw_str_len (CRString const *a_this) ++{ ++ g_return_val_if_fail (a_this && a_this->stryng, ++ -1) ; ++ return a_this->stryng->len ; ++} ++ ++/** ++ *@param a_this the #CRString to destroy. ++ */ ++void ++cr_string_destroy (CRString *a_this) ++{ ++ g_return_if_fail (a_this) ; ++ ++ if (a_this->stryng) { ++ g_string_free (a_this->stryng, TRUE) ; ++ a_this->stryng = NULL ; ++ } ++ g_free (a_this) ; ++} +diff --git a/src/st/croco/cr-string.h b/src/st/croco/cr-string.h +new file mode 100644 +index 000000000..2700f0e2e +--- /dev/null ++++ b/src/st/croco/cr-string.h +@@ -0,0 +1,76 @@ ++/* -*- Mode: C; indent-tabs-mode:nil; c-basic-offset: 8-*- */ ++ ++/* ++ * This file is part of The Croco Library ++ * ++ * 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 ++ * ++ * See COPYRIGHTS file for copyright information. ++ */ ++ ++/** ++ *@file ++ *Declaration file of the #CRString class. ++ */ ++ ++#ifndef __CR_STRING_H__ ++#define __CR_STRING_H__ ++ ++#include ++#include "cr-utils.h" ++#include "cr-parsing-location.h" ++ ++G_BEGIN_DECLS ++ ++typedef struct _CRString CRString ; ++ ++/** ++ *This is a ship implementation of string based on GString. ++ *Actually, the aim of CRString is to store the parsing location ++ *(line,column,byte offset) at which a given string has been parsed ++ *in the input CSS. ++ *So this class has a gstring field of type GString that users can ++ *freely manipulate, and also a CRParginLocation type where the ++ *parsing location is store. If you don't want to deal with parsing ++ *location stuffs, then use GString instead. If we were in C++ for example, ++ *CRString would just inherit GString and just add accessors to ++ *the CRParsingLocation data ... but we are not and we still have ++ *to provide the parsing location information. ++ */ ++struct _CRString { ++ /** ++ *The GString where all the string ++ *operation happen. ++ */ ++ GString *stryng ; ++ /** ++ *The parsing location storage area. ++ */ ++ CRParsingLocation location ; ++} ; ++ ++CRString * cr_string_new (void) ; ++ ++CRString *cr_string_new_from_string (const gchar * a_string) ; ++CRString * cr_string_new_from_gstring (GString const *a_string) ; ++CRString *cr_string_dup (CRString const *a_this) ; ++gchar *cr_string_dup2 (CRString const *a_this) ; ++const gchar *cr_string_peek_raw_str (CRString const *a_this) ; ++gint cr_string_peek_raw_str_len (CRString const *a_this) ; ++void cr_string_destroy (CRString *a_this) ; ++ ++G_END_DECLS ++ ++#endif +diff --git a/src/st/croco/cr-stylesheet.c b/src/st/croco/cr-stylesheet.c +new file mode 100644 +index 000000000..69909da24 +--- /dev/null ++++ b/src/st/croco/cr-stylesheet.c +@@ -0,0 +1,178 @@ ++/* -*- Mode: C; indent-tabs-mode: nil; c-basic-offset: 8 -*- */ ++ ++/* ++ * This file is part of The Croco Library ++ * ++ * Copyright (C) 2002-2004 Dodji Seketeli ++ * ++ * 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 ++ */ ++ ++#include "string.h" ++#include "cr-stylesheet.h" ++ ++/** ++ *@file ++ *The definition of the #CRStyleSheet class ++ */ ++ ++/** ++ *Constructor of the #CRStyleSheet class. ++ *@param the initial list of css statements. ++ *@return the newly built css2 stylesheet, or NULL in case of error. ++ */ ++CRStyleSheet * ++cr_stylesheet_new (CRStatement * a_stmts) ++{ ++ CRStyleSheet *result; ++ ++ result = g_try_malloc (sizeof (CRStyleSheet)); ++ if (!result) { ++ cr_utils_trace_info ("Out of memory"); ++ return NULL; ++ } ++ ++ memset (result, 0, sizeof (CRStyleSheet)); ++ ++ if (a_stmts) ++ result->statements = a_stmts; ++ ++ return result; ++} ++ ++/** ++ *@param a_this the current instance of #CRStyleSheet ++ *@return the serialized stylesheet. ++ */ ++gchar * ++cr_stylesheet_to_string (CRStyleSheet const *a_this) ++{ ++ gchar *str = NULL; ++ GString *stringue = NULL; ++ CRStatement const *cur_stmt = NULL; ++ ++ g_return_val_if_fail (a_this, NULL); ++ ++ if (a_this->statements) { ++ stringue = g_string_new (NULL) ; ++ g_return_val_if_fail (stringue, NULL) ; ++ } ++ for (cur_stmt = a_this->statements; ++ cur_stmt; cur_stmt = cur_stmt->next) { ++ if (cur_stmt->prev) { ++ g_string_append (stringue, "\n\n") ; ++ } ++ str = cr_statement_to_string (cur_stmt, 0) ; ++ if (str) { ++ g_string_append (stringue, str) ; ++ g_free (str) ; ++ str = NULL ; ++ } ++ } ++ if (stringue) { ++ str = stringue->str ; ++ g_string_free (stringue, FALSE) ; ++ stringue = NULL ; ++ } ++ return str ; ++} ++ ++/** ++ *Dumps the current css2 stylesheet to a file. ++ *@param a_this the current instance of #CRStyleSheet. ++ *@param a_fp the destination file ++ */ ++void ++cr_stylesheet_dump (CRStyleSheet const * a_this, FILE * a_fp) ++{ ++ gchar *str = NULL ; ++ ++ g_return_if_fail (a_this); ++ ++ str = cr_stylesheet_to_string (a_this) ; ++ if (str) { ++ fprintf (a_fp, "%s", str) ; ++ g_free (str) ; ++ str = NULL ; ++ } ++} ++ ++/** ++ *Return the number of rules in the stylesheet. ++ *@param a_this the current instance of #CRStyleSheet. ++ *@return number of rules in the stylesheet. ++ */ ++gint ++cr_stylesheet_nr_rules (CRStyleSheet const * a_this) ++{ ++ g_return_val_if_fail (a_this, -1); ++ ++ return cr_statement_nr_rules (a_this->statements); ++} ++ ++/** ++ *Use an index to get a CRStatement from the rules in a given stylesheet. ++ *@param a_this the current instance of #CRStatement. ++ *@param itemnr the index into the rules. ++ *@return CRStatement at position itemnr, if itemnr > number of rules - 1, ++ *it will return NULL. ++ */ ++CRStatement * ++cr_stylesheet_statement_get_from_list (CRStyleSheet * a_this, int itemnr) ++{ ++ g_return_val_if_fail (a_this, NULL); ++ ++ return cr_statement_get_from_list (a_this->statements, itemnr); ++} ++ ++void ++cr_stylesheet_ref (CRStyleSheet * a_this) ++{ ++ g_return_if_fail (a_this); ++ ++ a_this->ref_count++; ++} ++ ++gboolean ++cr_stylesheet_unref (CRStyleSheet * a_this) ++{ ++ g_return_val_if_fail (a_this, FALSE); ++ ++ if (a_this->ref_count) ++ a_this->ref_count--; ++ ++ if (!a_this->ref_count) { ++ cr_stylesheet_destroy (a_this); ++ return TRUE; ++ } ++ ++ return FALSE; ++} ++ ++/** ++ *Destructor of the #CRStyleSheet class. ++ *@param a_this the current instance of the #CRStyleSheet class. ++ */ ++void ++cr_stylesheet_destroy (CRStyleSheet * a_this) ++{ ++ g_return_if_fail (a_this); ++ ++ if (a_this->statements) { ++ cr_statement_destroy (a_this->statements); ++ a_this->statements = NULL; ++ } ++ g_free (a_this); ++} +diff --git a/src/st/croco/cr-stylesheet.h b/src/st/croco/cr-stylesheet.h +new file mode 100644 +index 000000000..f35c94e37 +--- /dev/null ++++ b/src/st/croco/cr-stylesheet.h +@@ -0,0 +1,102 @@ ++/* -*- Mode: C; indent-tabs-mode: nil; c-basic-offset: 8 -*- */ ++ ++/* ++ * This file is part of The Croco Library ++ * ++ * 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 ++ * ++ * see COPYRIGHTS file for copyright information. ++ */ ++ ++ ++#ifndef __CR_STYLESHEET_H__ ++#define __CR_STYLESHEET_H__ ++ ++#include "cr-utils.h" ++#include "cr-statement.h" ++ ++G_BEGIN_DECLS ++ ++/** ++ *@file ++ *The declaration of the #CRStyleSheet class. ++ */ ++ ++ ++enum CRStyleOrigin ++{ ++ /*Please don't change the order of ++ *the values enumerated here ... ++ *New values should be added at the end, ++ *just before ORIGIN_END. ++ */ ++ ORIGIN_UA = 0, ++ ORIGIN_USER, ++ ORIGIN_AUTHOR, ++ ++ /*must always be the last one*/ ++ NB_ORIGINS ++} ; ++ ++/** ++ *An abstraction of a css stylesheet as defined ++ *by the css2 spec in chapter 4. ++ */ ++struct _CRStyleSheet ++{ ++ /**The css statements list*/ ++ CRStatement *statements ; ++ ++ enum CRStyleOrigin origin ; ++ ++ /*the parent import rule, if any.*/ ++ CRStatement *parent_import_rule ; ++ ++ /**custom data used by libcroco*/ ++ gpointer croco_data ; ++ ++ /** ++ *custom application data pointer ++ *Can be used by applications. ++ */ ++ gpointer app_data ; ++ ++ /** ++ *the reference count of this insance ++ *Please, don't never ever modify it ++ *directly. Use cr_stylesheet_ref() ++ *and cr_stylesheet_unref() instead. ++ */ ++ gulong ref_count ; ++} ; ++ ++CRStyleSheet * cr_stylesheet_new (CRStatement *a_stmts) ; ++ ++gchar * cr_stylesheet_to_string (CRStyleSheet const *a_this) ; ++void cr_stylesheet_dump (CRStyleSheet const *a_this, FILE *a_fp) ; ++ ++gint cr_stylesheet_nr_rules (CRStyleSheet const *a_this) ; ++ ++CRStatement * cr_stylesheet_statement_get_from_list (CRStyleSheet *a_this, int itemnr) ; ++ ++void cr_stylesheet_ref (CRStyleSheet *a_this) ; ++ ++gboolean cr_stylesheet_unref (CRStyleSheet *a_this) ; ++ ++void cr_stylesheet_destroy (CRStyleSheet *a_this) ; ++ ++G_END_DECLS ++ ++#endif /*__CR_STYLESHEET_H__*/ +diff --git a/src/st/croco/cr-term.c b/src/st/croco/cr-term.c +new file mode 100644 +index 000000000..9ffe6727b +--- /dev/null ++++ b/src/st/croco/cr-term.c +@@ -0,0 +1,790 @@ ++/* -*- Mode: C; indent-tabs-mode:nil; c-basic-offset: 8-*- */ ++ ++/* ++ * This file is part of The Croco Library ++ * ++ * 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 ++ * See COPYRIGHTS file for copyright information. ++ */ ++ ++#include ++#include ++#include "cr-term.h" ++#include "cr-num.h" ++#include "cr-parser.h" ++ ++/** ++ *@file ++ *Definition of the #CRTem class. ++ */ ++ ++static void ++cr_term_clear (CRTerm * a_this) ++{ ++ g_return_if_fail (a_this); ++ ++ switch (a_this->type) { ++ case TERM_NUMBER: ++ if (a_this->content.num) { ++ cr_num_destroy (a_this->content.num); ++ a_this->content.num = NULL; ++ } ++ break; ++ ++ case TERM_FUNCTION: ++ if (a_this->ext_content.func_param) { ++ cr_term_destroy (a_this->ext_content.func_param); ++ a_this->ext_content.func_param = NULL; ++ } ++ case TERM_STRING: ++ case TERM_IDENT: ++ case TERM_URI: ++ case TERM_HASH: ++ if (a_this->content.str) { ++ cr_string_destroy (a_this->content.str); ++ a_this->content.str = NULL; ++ } ++ break; ++ ++ case TERM_RGB: ++ if (a_this->content.rgb) { ++ cr_rgb_destroy (a_this->content.rgb); ++ a_this->content.rgb = NULL; ++ } ++ break; ++ ++ case TERM_UNICODERANGE: ++ case TERM_NO_TYPE: ++ default: ++ break; ++ } ++ ++ a_this->type = TERM_NO_TYPE; ++} ++ ++/** ++ *Instanciate a #CRTerm. ++ *@return the newly build instance ++ *of #CRTerm. ++ */ ++CRTerm * ++cr_term_new (void) ++{ ++ CRTerm *result = NULL; ++ ++ result = g_try_malloc (sizeof (CRTerm)); ++ if (!result) { ++ cr_utils_trace_info ("Out of memory"); ++ return NULL; ++ } ++ memset (result, 0, sizeof (CRTerm)); ++ return result; ++} ++ ++/** ++ *Parses an expresion as defined by the css2 spec ++ *and builds the expression as a list of terms. ++ *@param a_buf the buffer to parse. ++ *@return a pointer to the first term of the expression or ++ *NULL if parsing failed. ++ */ ++CRTerm * ++cr_term_parse_expression_from_buf (const guchar * a_buf, ++ enum CREncoding a_encoding) ++{ ++ CRParser *parser = NULL; ++ CRTerm *result = NULL; ++ enum CRStatus status = CR_OK; ++ ++ 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); ++ g_return_val_if_fail (parser, NULL); ++ ++ status = cr_parser_try_to_skip_spaces_and_comments (parser); ++ if (status != CR_OK) { ++ goto cleanup; ++ } ++ status = cr_parser_parse_expr (parser, &result); ++ if (status != CR_OK) { ++ if (result) { ++ cr_term_destroy (result); ++ result = NULL; ++ } ++ } ++ ++ cleanup: ++ if (parser) { ++ cr_parser_destroy (parser); ++ parser = NULL; ++ } ++ ++ return result; ++} ++ ++enum CRStatus ++cr_term_set_number (CRTerm * a_this, CRNum * a_num) ++{ ++ g_return_val_if_fail (a_this, CR_BAD_PARAM_ERROR); ++ ++ cr_term_clear (a_this); ++ ++ a_this->type = TERM_NUMBER; ++ a_this->content.num = a_num; ++ return CR_OK; ++} ++ ++enum CRStatus ++cr_term_set_function (CRTerm * a_this, CRString * a_func_name, ++ CRTerm * a_func_param) ++{ ++ g_return_val_if_fail (a_this, CR_BAD_PARAM_ERROR); ++ ++ cr_term_clear (a_this); ++ ++ a_this->type = TERM_FUNCTION; ++ a_this->content.str = a_func_name; ++ a_this->ext_content.func_param = a_func_param; ++ return CR_OK; ++} ++ ++enum CRStatus ++cr_term_set_string (CRTerm * a_this, CRString * a_str) ++{ ++ g_return_val_if_fail (a_this, CR_BAD_PARAM_ERROR); ++ ++ cr_term_clear (a_this); ++ ++ a_this->type = TERM_STRING; ++ a_this->content.str = a_str; ++ return CR_OK; ++} ++ ++enum CRStatus ++cr_term_set_ident (CRTerm * a_this, CRString * a_str) ++{ ++ g_return_val_if_fail (a_this, CR_BAD_PARAM_ERROR); ++ ++ cr_term_clear (a_this); ++ ++ a_this->type = TERM_IDENT; ++ a_this->content.str = a_str; ++ return CR_OK; ++} ++ ++enum CRStatus ++cr_term_set_uri (CRTerm * a_this, CRString * a_str) ++{ ++ g_return_val_if_fail (a_this, CR_BAD_PARAM_ERROR); ++ ++ cr_term_clear (a_this); ++ ++ a_this->type = TERM_URI; ++ a_this->content.str = a_str; ++ return CR_OK; ++} ++ ++enum CRStatus ++cr_term_set_rgb (CRTerm * a_this, CRRgb * a_rgb) ++{ ++ g_return_val_if_fail (a_this, CR_BAD_PARAM_ERROR); ++ ++ cr_term_clear (a_this); ++ ++ a_this->type = TERM_RGB; ++ a_this->content.rgb = a_rgb; ++ return CR_OK; ++} ++ ++enum CRStatus ++cr_term_set_hash (CRTerm * a_this, CRString * a_str) ++{ ++ g_return_val_if_fail (a_this, CR_BAD_PARAM_ERROR); ++ ++ cr_term_clear (a_this); ++ ++ a_this->type = TERM_HASH; ++ a_this->content.str = a_str; ++ return CR_OK; ++} ++ ++/** ++ *Appends a new term to the current list of #CRTerm. ++ * ++ *@param a_this the "this pointer" of the current instance ++ *of #CRTerm . ++ *@param a_new_term the term to append. ++ *@return the list of terms with the a_new_term appended to it. ++ */ ++CRTerm * ++cr_term_append_term (CRTerm * a_this, CRTerm * a_new_term) ++{ ++ CRTerm *cur = NULL; ++ ++ g_return_val_if_fail (a_new_term, NULL); ++ ++ if (a_this == NULL) ++ return a_new_term; ++ ++ for (cur = a_this; cur->next; cur = cur->next) ; ++ ++ cur->next = a_new_term; ++ a_new_term->prev = cur; ++ ++ return a_this; ++} ++ ++/** ++ *Prepends a term to the list of terms represented by a_this. ++ * ++ *@param a_this the "this pointer" of the current instance of ++ *#CRTerm . ++ *@param a_new_term the term to prepend. ++ *@return the head of the new list. ++ */ ++CRTerm * ++cr_term_prepend_term (CRTerm * a_this, CRTerm * a_new_term) ++{ ++ g_return_val_if_fail (a_this && a_new_term, NULL); ++ ++ a_new_term->next = a_this; ++ a_this->prev = a_new_term; ++ ++ return a_new_term; ++} ++ ++/** ++ *Serializes the expression represented by ++ *the chained instances of #CRterm. ++ *@param a_this the current instance of #CRTerm ++ *@return the zero terminated string containing the serialized ++ *form of #CRTerm. MUST BE FREED BY THE CALLER using g_free(). ++ */ ++guchar * ++cr_term_to_string (CRTerm const * a_this) ++{ ++ GString *str_buf = NULL; ++ CRTerm const *cur = NULL; ++ guchar *result = NULL, ++ *content = NULL; ++ ++ g_return_val_if_fail (a_this, NULL); ++ ++ str_buf = g_string_new (NULL); ++ g_return_val_if_fail (str_buf, NULL); ++ ++ for (cur = a_this; cur; cur = cur->next) { ++ if ((cur->content.str == NULL) ++ && (cur->content.num == NULL) ++ && (cur->content.str == NULL) ++ && (cur->content.rgb == NULL)) ++ continue; ++ ++ switch (cur->the_operator) { ++ case DIVIDE: ++ g_string_append (str_buf, " / "); ++ break; ++ ++ case COMMA: ++ g_string_append (str_buf, ", "); ++ break; ++ ++ case NO_OP: ++ if (cur->prev) { ++ g_string_append (str_buf, " "); ++ } ++ break; ++ default: ++ ++ break; ++ } ++ ++ switch (cur->unary_op) { ++ case PLUS_UOP: ++ g_string_append (str_buf, "+"); ++ break; ++ ++ case MINUS_UOP: ++ g_string_append (str_buf, "-"); ++ break; ++ ++ default: ++ break; ++ } ++ ++ switch (cur->type) { ++ case TERM_NUMBER: ++ if (cur->content.num) { ++ content = cr_num_to_string (cur->content.num); ++ } ++ ++ if (content) { ++ g_string_append (str_buf, (const gchar *) content); ++ g_free (content); ++ content = NULL; ++ } ++ ++ break; ++ ++ case TERM_FUNCTION: ++ if (cur->content.str) { ++ content = (guchar *) g_strndup ++ (cur->content.str->stryng->str, ++ cur->content.str->stryng->len); ++ } ++ ++ if (content) { ++ g_string_append_printf (str_buf, "%s(", ++ content); ++ ++ if (cur->ext_content.func_param) { ++ guchar *tmp_str = NULL; ++ ++ tmp_str = cr_term_to_string ++ (cur-> ++ ext_content.func_param); ++ ++ if (tmp_str) { ++ g_string_append (str_buf, ++ (const gchar *) tmp_str); ++ g_free (tmp_str); ++ tmp_str = NULL; ++ } ++ } ++ g_string_append (str_buf, ")"); ++ g_free (content); ++ content = NULL; ++ } ++ ++ break; ++ ++ case TERM_STRING: ++ if (cur->content.str) { ++ content = (guchar *) g_strndup ++ (cur->content.str->stryng->str, ++ cur->content.str->stryng->len); ++ } ++ ++ if (content) { ++ g_string_append_printf (str_buf, ++ "\"%s\"", content); ++ g_free (content); ++ content = NULL; ++ } ++ break; ++ ++ case TERM_IDENT: ++ if (cur->content.str) { ++ content = (guchar *) g_strndup ++ (cur->content.str->stryng->str, ++ cur->content.str->stryng->len); ++ } ++ ++ if (content) { ++ g_string_append (str_buf, (const gchar *) content); ++ g_free (content); ++ content = NULL; ++ } ++ break; ++ ++ case TERM_URI: ++ if (cur->content.str) { ++ content = (guchar *) g_strndup ++ (cur->content.str->stryng->str, ++ cur->content.str->stryng->len); ++ } ++ ++ if (content) { ++ g_string_append_printf ++ (str_buf, "url(%s)", content); ++ g_free (content); ++ content = NULL; ++ } ++ break; ++ ++ case TERM_RGB: ++ if (cur->content.rgb) { ++ guchar *tmp_str = NULL; ++ ++ g_string_append (str_buf, "rgb("); ++ tmp_str = cr_rgb_to_string (cur->content.rgb); ++ ++ if (tmp_str) { ++ g_string_append (str_buf, (const gchar *) tmp_str); ++ g_free (tmp_str); ++ tmp_str = NULL; ++ } ++ g_string_append (str_buf, ")"); ++ } ++ ++ break; ++ ++ case TERM_UNICODERANGE: ++ g_string_append ++ (str_buf, ++ "?found unicoderange: dump not supported yet?"); ++ break; ++ ++ case TERM_HASH: ++ if (cur->content.str) { ++ content = (guchar *) g_strndup ++ (cur->content.str->stryng->str, ++ cur->content.str->stryng->len); ++ } ++ ++ if (content) { ++ g_string_append_printf (str_buf, ++ "#%s", content); ++ g_free (content); ++ content = NULL; ++ } ++ break; ++ ++ default: ++ g_string_append (str_buf, ++ "Unrecognized Term type"); ++ break; ++ } ++ } ++ ++ if (str_buf) { ++ result =(guchar *) str_buf->str; ++ g_string_free (str_buf, FALSE); ++ str_buf = NULL; ++ } ++ ++ return result; ++} ++ ++guchar * ++cr_term_one_to_string (CRTerm const * a_this) ++{ ++ GString *str_buf = NULL; ++ guchar *result = NULL, ++ *content = NULL; ++ ++ g_return_val_if_fail (a_this, NULL); ++ ++ str_buf = g_string_new (NULL); ++ g_return_val_if_fail (str_buf, NULL); ++ ++ if ((a_this->content.str == NULL) ++ && (a_this->content.num == NULL) ++ && (a_this->content.str == NULL) ++ && (a_this->content.rgb == NULL)) ++ return NULL ; ++ ++ switch (a_this->the_operator) { ++ case DIVIDE: ++ g_string_append_printf (str_buf, " / "); ++ break; ++ ++ case COMMA: ++ g_string_append_printf (str_buf, ", "); ++ break; ++ ++ case NO_OP: ++ if (a_this->prev) { ++ g_string_append_printf (str_buf, " "); ++ } ++ break; ++ default: ++ ++ break; ++ } ++ ++ switch (a_this->unary_op) { ++ case PLUS_UOP: ++ g_string_append_printf (str_buf, "+"); ++ break; ++ ++ case MINUS_UOP: ++ g_string_append_printf (str_buf, "-"); ++ break; ++ ++ default: ++ break; ++ } ++ ++ switch (a_this->type) { ++ case TERM_NUMBER: ++ if (a_this->content.num) { ++ content = cr_num_to_string (a_this->content.num); ++ } ++ ++ if (content) { ++ g_string_append (str_buf, (const gchar *) content); ++ g_free (content); ++ content = NULL; ++ } ++ ++ break; ++ ++ case TERM_FUNCTION: ++ if (a_this->content.str) { ++ content = (guchar *) g_strndup ++ (a_this->content.str->stryng->str, ++ a_this->content.str->stryng->len); ++ } ++ ++ if (content) { ++ g_string_append_printf (str_buf, "%s(", ++ content); ++ ++ if (a_this->ext_content.func_param) { ++ guchar *tmp_str = NULL; ++ ++ tmp_str = cr_term_to_string ++ (a_this-> ++ ext_content.func_param); ++ ++ if (tmp_str) { ++ g_string_append_printf ++ (str_buf, ++ "%s", tmp_str); ++ g_free (tmp_str); ++ tmp_str = NULL; ++ } ++ ++ g_string_append_printf (str_buf, ")"); ++ g_free (content); ++ content = NULL; ++ } ++ } ++ ++ break; ++ ++ case TERM_STRING: ++ if (a_this->content.str) { ++ content = (guchar *) g_strndup ++ (a_this->content.str->stryng->str, ++ a_this->content.str->stryng->len); ++ } ++ ++ if (content) { ++ g_string_append_printf (str_buf, ++ "\"%s\"", content); ++ g_free (content); ++ content = NULL; ++ } ++ break; ++ ++ case TERM_IDENT: ++ if (a_this->content.str) { ++ content = (guchar *) g_strndup ++ (a_this->content.str->stryng->str, ++ a_this->content.str->stryng->len); ++ } ++ ++ if (content) { ++ g_string_append (str_buf, (const gchar *) content); ++ g_free (content); ++ content = NULL; ++ } ++ break; ++ ++ case TERM_URI: ++ if (a_this->content.str) { ++ content = (guchar *) g_strndup ++ (a_this->content.str->stryng->str, ++ a_this->content.str->stryng->len); ++ } ++ ++ if (content) { ++ g_string_append_printf ++ (str_buf, "url(%s)", content); ++ g_free (content); ++ content = NULL; ++ } ++ break; ++ ++ case TERM_RGB: ++ if (a_this->content.rgb) { ++ guchar *tmp_str = NULL; ++ ++ g_string_append_printf (str_buf, "rgb("); ++ tmp_str = cr_rgb_to_string (a_this->content.rgb); ++ ++ if (tmp_str) { ++ g_string_append (str_buf, (const gchar *) tmp_str); ++ g_free (tmp_str); ++ tmp_str = NULL; ++ } ++ g_string_append_printf (str_buf, ")"); ++ } ++ ++ break; ++ ++ case TERM_UNICODERANGE: ++ g_string_append_printf ++ (str_buf, ++ "?found unicoderange: dump not supported yet?"); ++ break; ++ ++ case TERM_HASH: ++ if (a_this->content.str) { ++ content = (guchar *) g_strndup ++ (a_this->content.str->stryng->str, ++ a_this->content.str->stryng->len); ++ } ++ ++ if (content) { ++ g_string_append_printf (str_buf, ++ "#%s", content); ++ g_free (content); ++ content = NULL; ++ } ++ break; ++ ++ default: ++ g_string_append_printf (str_buf, ++ "%s", ++ "Unrecognized Term type"); ++ break; ++ } ++ ++ if (str_buf) { ++ result = (guchar *) str_buf->str; ++ g_string_free (str_buf, FALSE); ++ str_buf = NULL; ++ } ++ ++ return result; ++} ++ ++/** ++ *Dumps the expression (a list of terms connected by operators) ++ *to a file. ++ *TODO: finish the dump. The dump of some type of terms have not yet been ++ *implemented. ++ *@param a_this the current instance of #CRTerm. ++ *@param a_fp the destination file pointer. ++ */ ++void ++cr_term_dump (CRTerm const * a_this, FILE * a_fp) ++{ ++ guchar *content = NULL; ++ ++ g_return_if_fail (a_this); ++ ++ content = cr_term_to_string (a_this); ++ ++ if (content) { ++ fprintf (a_fp, "%s", content); ++ g_free (content); ++ } ++} ++ ++/** ++ *Return the number of terms in the expression. ++ *@param a_this the current instance of #CRTerm. ++ *@return number of terms in the expression. ++ */ ++int ++cr_term_nr_values (CRTerm const *a_this) ++{ ++ CRTerm 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; ++} ++ ++/** ++ *Use an index to get a CRTerm from the expression. ++ *@param a_this the current instance of #CRTerm. ++ *@param itemnr the index into the expression. ++ *@return CRTerm at position itemnr, if itemnr > number of terms - 1, ++ *it will return NULL. ++ */ ++CRTerm * ++cr_term_get_from_list (CRTerm *a_this, int itemnr) ++{ ++ CRTerm *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; ++} ++ ++/** ++ *Increments the reference counter of the current instance ++ *of #CRTerm.* ++ *@param a_this the current instance of #CRTerm. ++ */ ++void ++cr_term_ref (CRTerm * a_this) ++{ ++ g_return_if_fail (a_this); ++ ++ a_this->ref_count++; ++} ++ ++/** ++ *Decrements the ref count of the current instance of ++ *#CRTerm. If the ref count reaches zero, the instance is ++ *destroyed. ++ *@param a_this the current instance of #CRTerm. ++ *@return TRUE if the current instance has been destroyed, FALSE otherwise. ++ */ ++gboolean ++cr_term_unref (CRTerm * a_this) ++{ ++ g_return_val_if_fail (a_this, FALSE); ++ ++ if (a_this->ref_count) { ++ a_this->ref_count--; ++ } ++ ++ if (a_this->ref_count == 0) { ++ cr_term_destroy (a_this); ++ return TRUE; ++ } ++ ++ return FALSE; ++} ++ ++/** ++ *The destructor of the the #CRTerm class. ++ *@param a_this the "this pointer" of the current instance ++ *of #CRTerm. ++ */ ++void ++cr_term_destroy (CRTerm * a_this) ++{ ++ g_return_if_fail (a_this); ++ ++ cr_term_clear (a_this); ++ ++ if (a_this->next) { ++ cr_term_destroy (a_this->next); ++ a_this->next = NULL; ++ } ++ ++ if (a_this) { ++ g_free (a_this); ++ } ++ ++} +diff --git a/src/st/croco/cr-term.h b/src/st/croco/cr-term.h +new file mode 100644 +index 000000000..0f22dda75 +--- /dev/null ++++ b/src/st/croco/cr-term.h +@@ -0,0 +1,190 @@ ++/* -*- Mode: C; indent-tabs-mode:nil; c-basic-offset: 8-*- */ ++ ++/* ++ * This file is part of The Croco Library ++ * ++ * 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 ++ * See COPYRIGHTS file for copyright information. ++ */ ++ ++#include ++#include ++#include "cr-utils.h" ++#include "cr-rgb.h" ++#include "cr-num.h" ++#include "cr-string.h" ++ ++#ifndef __CR_TERM_H__ ++#define __CR_TERM_H__ ++ ++G_BEGIN_DECLS ++ ++/** ++ *@file ++ *Declaration of the #CRTem class. ++ */ ++ ++enum CRTermType ++{ ++ TERM_NO_TYPE = 0, ++ TERM_NUMBER, ++ TERM_FUNCTION, ++ TERM_STRING, ++ TERM_IDENT, ++ TERM_URI, ++ TERM_RGB, ++ TERM_UNICODERANGE, ++ TERM_HASH ++} ; ++ ++ ++enum UnaryOperator ++{ ++ NO_UNARY_UOP = 0, ++ PLUS_UOP, ++ MINUS_UOP, ++ EMPTY_UNARY_UOP ++} ; ++ ++enum Operator ++{ ++ NO_OP = 0, ++ DIVIDE, ++ COMMA ++} ; ++ ++struct _CRTerm ; ++typedef struct _CRTerm CRTerm ; ++ ++/** ++ *An abstraction of a css2 term as ++ *defined in the CSS2 spec in appendix D.1: ++ *term ::= ++ *[ NUMBER S* | PERCENTAGE S* | LENGTH S* | EMS S* | EXS S* ++ *| ANGLE S* | TIME S* | FREQ S* | function ] ++ * | STRING S* | IDENT S* | URI S* | RGB S* ++ *| UNICODERANGE S* | hexcolor ++ */ ++struct _CRTerm ++{ ++ /** ++ *The type of the term. ++ */ ++ enum CRTermType type ; ++ ++ /** ++ *The unary operator associated to ++ *the current term. ++ */ ++ enum UnaryOperator unary_op ; ++ ++ /** ++ *The operator associated to the current term. ++ */ ++ enum Operator the_operator ; ++ ++ ++ /** ++ *The content of the term. ++ *Depending of the type of the term, ++ *this holds either a number, a percentage ... ++ */ ++ union ++ { ++ CRNum *num ; ++ CRString * str ; ++ CRRgb * rgb ; ++ } content ; ++ ++ /** ++ *If the term is of type UNICODERANGE, ++ *this field holds the upper bound of the range. ++ *if the term is of type FUNCTION, this holds ++ *an instance of CRTerm that represents ++ * the expression which is the argument of the function. ++ */ ++ union ++ { ++ CRTerm *func_param ; ++ } ext_content ; ++ ++ /** ++ *A spare pointer, just in case. ++ *Can be used by the application. ++ */ ++ gpointer app_data ; ++ ++ glong ref_count ; ++ ++ /** ++ *A pointer to the next term, ++ *just in case this term is part of ++ *an expression. ++ */ ++ CRTerm *next ; ++ ++ /** ++ *A pointer to the previous ++ *term. ++ */ ++ CRTerm *prev ; ++ CRParsingLocation location ; ++} ; ++ ++CRTerm * cr_term_parse_expression_from_buf (const guchar *a_buf, ++ enum CREncoding a_encoding) ; ++CRTerm * cr_term_new (void) ; ++ ++enum CRStatus cr_term_set_number (CRTerm *a_this, CRNum *a_num) ; ++ ++enum CRStatus cr_term_set_function (CRTerm *a_this, ++ CRString *a_func_name, ++ CRTerm *a_func_param) ; ++ ++enum CRStatus cr_term_set_string (CRTerm *a_this, CRString *a_str) ; ++ ++enum CRStatus cr_term_set_ident (CRTerm *a_this, CRString *a_str) ; ++ ++enum CRStatus cr_term_set_uri (CRTerm *a_this, CRString *a_str) ; ++ ++enum CRStatus cr_term_set_rgb (CRTerm *a_this, CRRgb *a_rgb) ; ++ ++enum CRStatus cr_term_set_hash (CRTerm *a_this, CRString *a_str) ; ++ ++CRTerm * cr_term_append_term (CRTerm *a_this, CRTerm *a_new_term) ; ++ ++CRTerm * cr_term_prepend_term (CRTerm *a_this, CRTerm *a_new_term) ; ++ ++guchar * cr_term_to_string (CRTerm const *a_this) ; ++ ++guchar * cr_term_one_to_string (CRTerm const * a_this) ; ++ ++void cr_term_dump (CRTerm const *a_this, FILE *a_fp) ; ++ ++int cr_term_nr_values (CRTerm const *a_this) ; ++ ++CRTerm * cr_term_get_from_list (CRTerm *a_this, int itemnr) ; ++ ++void cr_term_ref (CRTerm *a_this) ; ++ ++gboolean cr_term_unref (CRTerm *a_this) ; ++ ++void cr_term_destroy (CRTerm * a_term) ; ++ ++G_END_DECLS ++ ++#endif /*__CR_TERM_H__*/ +diff --git a/src/st/croco/cr-tknzr.c b/src/st/croco/cr-tknzr.c +new file mode 100644 +index 000000000..1548c35c6 +--- /dev/null ++++ b/src/st/croco/cr-tknzr.c +@@ -0,0 +1,2762 @@ ++/* -*- Mode: C; indent-tabs-mode:nil; c-basic-offset: 8-*- */ ++ ++/* ++ * This file is part of The Croco Library ++ * ++ * 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 ++ * See the COPYRIGHTS file for copyrights information. ++ */ ++ ++/** ++ *@file ++ *The definition of the #CRTknzr (tokenizer) ++ *class. ++ */ ++ ++#include "string.h" ++#include "cr-tknzr.h" ++#include "cr-doc-handler.h" ++ ++struct _CRTknzrPriv { ++ /**The parser input stream of bytes*/ ++ CRInput *input; ++ ++ /** ++ *A cache where tknzr_unget_token() ++ *puts back the token. tknzr_get_next_token() ++ *first look in this cache, and if and ++ *only if it's empty, fetches the next token ++ *from the input stream. ++ */ ++ CRToken *token_cache; ++ ++ /** ++ *The position of the end of the previous token ++ *or char fetched. ++ */ ++ CRInputPos prev_pos; ++ ++ CRDocHandler *sac_handler; ++ ++ /** ++ *The reference count of the current instance ++ *of #CRTknzr. Is manipulated by cr_tknzr_ref() ++ *and cr_tknzr_unref(). ++ */ ++ glong ref_count; ++}; ++ ++#define PRIVATE(obj) ((obj)->priv) ++ ++/** ++ *return TRUE if the character is a number ([0-9]), FALSE otherwise ++ *@param a_char the char to test. ++ */ ++#define IS_NUM(a_char) (((a_char) >= '0' && (a_char) <= '9')?TRUE:FALSE) ++ ++/** ++ *Checks if 'status' equals CR_OK. If not, goto the 'error' label. ++ * ++ *@param status the status (of type enum CRStatus) to test. ++ *@param is_exception if set to FALSE, the final status returned the ++ *current function will be CR_PARSING_ERROR. If set to TRUE, the ++ *current status will be the current value of the 'status' variable. ++ * ++ */ ++#define CHECK_PARSING_STATUS(status, is_exception) \ ++if ((status) != CR_OK) \ ++{ \ ++ if (is_exception == FALSE) \ ++ { \ ++ status = CR_PARSING_ERROR ; \ ++ } \ ++ goto error ; \ ++} ++ ++/** ++ *Peeks the next char from the input stream of the current tokenizer. ++ *invokes CHECK_PARSING_STATUS on the status returned by ++ *cr_tknzr_input_peek_char(). ++ * ++ *@param the current instance of #CRTkzr. ++ *@param to_char a pointer to the char where to store the ++ *char peeked. ++ */ ++#define PEEK_NEXT_CHAR(a_tknzr, a_to_char) \ ++{\ ++status = cr_tknzr_peek_char (a_tknzr, a_to_char) ; \ ++CHECK_PARSING_STATUS (status, TRUE) \ ++} ++ ++/** ++ *Reads the next char from the input stream of the current parser. ++ *In case of error, jumps to the "error:" label located in the ++ *function where this macro is called. ++ *@param parser the curent instance of #CRTknzr ++ *@param to_char a pointer to the guint32 char where to store ++ *the character read. ++ */ ++#define READ_NEXT_CHAR(a_tknzr, to_char) \ ++status = cr_tknzr_read_char (a_tknzr, to_char) ;\ ++CHECK_PARSING_STATUS (status, TRUE) ++ ++/** ++ *Gets information about the current position in ++ *the input of the parser. ++ *In case of failure, this macro returns from the ++ *calling function and ++ *returns a status code of type enum #CRStatus. ++ *@param parser the current instance of #CRTknzr. ++ *@param pos out parameter. A pointer to the position ++ *inside the current parser input. Must ++ */ ++#define RECORD_INITIAL_POS(a_tknzr, a_pos) \ ++status = cr_input_get_cur_pos (PRIVATE \ ++(a_tknzr)->input, a_pos) ; \ ++g_return_val_if_fail (status == CR_OK, status) ++ ++/** ++ *Gets the address of the current byte inside the ++ *parser input. ++ *@param parser the current instance of #CRTknzr. ++ *@param addr out parameter a pointer (guchar*) ++ *to where the address must be put. ++ */ ++#define RECORD_CUR_BYTE_ADDR(a_tknzr, a_addr) \ ++status = cr_input_get_cur_byte_addr \ ++ (PRIVATE (a_tknzr)->input, a_addr) ; \ ++CHECK_PARSING_STATUS (status, TRUE) ++ ++/** ++ *Peeks a byte from the topmost parser input at ++ *a given offset from the current position. ++ *If it fails, goto the "error:" label. ++ * ++ *@param a_parser the current instance of #CRTknzr. ++ *@param a_offset the offset of the byte to peek, the ++ *current byte having the offset '0'. ++ *@param a_byte_ptr out parameter a pointer (guchar*) to ++ *where the peeked char is to be stored. ++ */ ++#define PEEK_BYTE(a_tknzr, a_offset, a_byte_ptr) \ ++status = cr_tknzr_peek_byte (a_tknzr, \ ++ a_offset, \ ++ a_byte_ptr) ; \ ++CHECK_PARSING_STATUS (status, TRUE) ; ++ ++#define BYTE(a_input, a_n, a_eof) \ ++cr_input_peek_byte2 (a_input, a_n, a_eof) ++ ++/** ++ *Reads a byte from the topmost parser input ++ *steam. ++ *If it fails, goto the "error" label. ++ *@param a_parser the current instance of #CRTknzr. ++ *@param a_byte_ptr the guchar * where to put the read char. ++ */ ++#define READ_NEXT_BYTE(a_tknzr, a_byte_ptr) \ ++status = \ ++cr_input_read_byte (PRIVATE (a_tknzr)->input, a_byte_ptr) ;\ ++CHECK_PARSING_STATUS (status, TRUE) ; ++ ++/** ++ *Skips a given number of byte in the topmost ++ *parser input. Don't update line and column number. ++ *In case of error, jumps to the "error:" label ++ *of the surrounding function. ++ *@param a_parser the current instance of #CRTknzr. ++ *@param a_nb_bytes the number of bytes to skip. ++ */ ++#define SKIP_BYTES(a_tknzr, a_nb_bytes) \ ++status = cr_input_seek_index (PRIVATE (a_tknzr)->input, \ ++ CR_SEEK_CUR, a_nb_bytes) ; \ ++CHECK_PARSING_STATUS (status, TRUE) ; ++ ++/** ++ *Skip utf8 encoded characters. ++ *Updates line and column numbers. ++ *@param a_parser the current instance of #CRTknzr. ++ *@param a_nb_chars the number of chars to skip. Must be of ++ *type glong. ++ */ ++#define SKIP_CHARS(a_tknzr, a_nb_chars) \ ++{ \ ++gulong nb_chars = a_nb_chars ; \ ++status = cr_input_consume_chars \ ++ (PRIVATE (a_tknzr)->input,0, &nb_chars) ; \ ++CHECK_PARSING_STATUS (status, TRUE) ; \ ++} ++ ++/** ++ *Tests the condition and if it is false, sets ++ *status to "CR_PARSING_ERROR" and goto the 'error' ++ *label. ++ *@param condition the condition to test. ++ */ ++#define ENSURE_PARSING_COND(condition) \ ++if (! (condition)) {status = CR_PARSING_ERROR; goto error ;} ++ ++static enum CRStatus cr_tknzr_parse_nl (CRTknzr * a_this, ++ guchar ** a_start, ++ guchar ** a_end, ++ CRParsingLocation *a_location); ++ ++static enum CRStatus cr_tknzr_parse_w (CRTknzr * a_this, ++ guchar ** a_start, ++ guchar ** a_end, ++ CRParsingLocation *a_location) ; ++ ++static enum CRStatus cr_tknzr_parse_unicode_escape (CRTknzr * a_this, ++ guint32 * a_unicode, ++ CRParsingLocation *a_location) ; ++ ++static enum CRStatus cr_tknzr_parse_escape (CRTknzr * a_this, ++ guint32 * a_esc_code, ++ CRParsingLocation *a_location); ++ ++static enum CRStatus cr_tknzr_parse_string (CRTknzr * a_this, ++ CRString ** a_str); ++ ++static enum CRStatus cr_tknzr_parse_comment (CRTknzr * a_this, ++ CRString ** a_comment); ++ ++static enum CRStatus cr_tknzr_parse_nmstart (CRTknzr * a_this, ++ guint32 * a_char, ++ CRParsingLocation *a_location); ++ ++static enum CRStatus cr_tknzr_parse_num (CRTknzr * a_this, ++ CRNum ** a_num); ++ ++/********************************** ++ *PRIVATE methods ++ **********************************/ ++ ++/** ++ *Parses a "w" as defined by the css spec at [4.1.1]: ++ * w ::= [ \t\r\n\f]* ++ * ++ *@param a_this the current instance of #CRTknzr. ++ *@param a_start out param. Upon successfull completion, points ++ *to the beginning of the parsed white space, points to NULL otherwise. ++ *Can also point to NULL is there is no white space actually. ++ *@param a_end out param. Upon successfull completion, points ++ *to the end of the parsed white space, points to NULL otherwise. ++ *Can also point to NULL is there is no white space actually. ++ */ ++static enum CRStatus ++cr_tknzr_parse_w (CRTknzr * a_this, ++ guchar ** a_start, ++ guchar ** a_end, ++ CRParsingLocation *a_location) ++{ ++ guint32 cur_char = 0; ++ CRInputPos init_pos; ++ enum CRStatus status = CR_OK; ++ ++ g_return_val_if_fail (a_this && PRIVATE (a_this) ++ && PRIVATE (a_this)->input ++ && a_start && a_end, ++ CR_BAD_PARAM_ERROR); ++ ++ RECORD_INITIAL_POS (a_this, &init_pos); ++ ++ *a_start = NULL; ++ *a_end = NULL; ++ ++ READ_NEXT_CHAR (a_this, &cur_char); ++ ++ if (cr_utils_is_white_space (cur_char) == FALSE) { ++ status = CR_PARSING_ERROR; ++ goto error; ++ } ++ if (a_location) { ++ cr_tknzr_get_parsing_location (a_this, ++ a_location) ; ++ } ++ RECORD_CUR_BYTE_ADDR (a_this, a_start); ++ *a_end = *a_start; ++ ++ for (;;) { ++ gboolean is_eof = FALSE; ++ ++ cr_input_get_end_of_file (PRIVATE (a_this)->input, &is_eof); ++ if (is_eof) ++ break; ++ ++ status = cr_tknzr_peek_char (a_this, &cur_char); ++ if (status == CR_END_OF_INPUT_ERROR) { ++ break; ++ } else if (status != CR_OK) { ++ goto error; ++ } ++ ++ if (cr_utils_is_white_space (cur_char) == TRUE) { ++ READ_NEXT_CHAR (a_this, &cur_char); ++ RECORD_CUR_BYTE_ADDR (a_this, a_end); ++ } else { ++ break; ++ } ++ } ++ ++ return CR_OK; ++ ++ error: ++ cr_tknzr_set_cur_pos (a_this, &init_pos); ++ ++ return status; ++} ++ ++/** ++ *Parses a newline as defined in the css2 spec: ++ * nl ::= \n|\r\n|\r|\f ++ * ++ *@param a_this the "this pointer" of the current instance of #CRTknzr. ++ *@param a_start a pointer to the first character of the successfully ++ *parsed string. ++ *@param a_end a pointer to the last character of the successfully parsed ++ *string. ++ *@result CR_OK uppon successfull completion, an error code otherwise. ++ */ ++static enum CRStatus ++cr_tknzr_parse_nl (CRTknzr * a_this, ++ guchar ** a_start, ++ guchar ** a_end, ++ CRParsingLocation *a_location) ++{ ++ CRInputPos init_pos; ++ guchar next_chars[2] = { 0 }; ++ enum CRStatus status = CR_PARSING_ERROR; ++ ++ g_return_val_if_fail (a_this && PRIVATE (a_this) ++ && a_start && a_end, CR_BAD_PARAM_ERROR); ++ ++ RECORD_INITIAL_POS (a_this, &init_pos); ++ ++ PEEK_BYTE (a_this, 1, &next_chars[0]); ++ PEEK_BYTE (a_this, 2, &next_chars[1]); ++ ++ if ((next_chars[0] == '\r' && next_chars[1] == '\n')) { ++ SKIP_BYTES (a_this, 1); ++ if (a_location) { ++ cr_tknzr_get_parsing_location ++ (a_this, a_location) ; ++ } ++ SKIP_CHARS (a_this, 1); ++ ++ RECORD_CUR_BYTE_ADDR (a_this, a_end); ++ ++ status = CR_OK; ++ } else if (next_chars[0] == '\n' ++ || next_chars[0] == '\r' || next_chars[0] == '\f') { ++ SKIP_CHARS (a_this, 1); ++ if (a_location) { ++ cr_tknzr_get_parsing_location ++ (a_this, a_location) ; ++ } ++ RECORD_CUR_BYTE_ADDR (a_this, a_start); ++ *a_end = *a_start; ++ status = CR_OK; ++ } else { ++ status = CR_PARSING_ERROR; ++ goto error; ++ } ++ return CR_OK ; ++ ++ error: ++ cr_tknzr_set_cur_pos (a_this, &init_pos) ; ++ return status; ++} ++ ++/** ++ *Go ahead in the parser input, skipping all the spaces. ++ *If the next char if not a white space, this function does nothing. ++ *In any cases, it stops when it encounters a non white space character. ++ * ++ *@param a_this the current instance of #CRTknzr. ++ *@return CR_OK upon successfull completion, an error code otherwise. ++ */ ++static enum CRStatus ++cr_tknzr_try_to_skip_spaces (CRTknzr * a_this) ++{ ++ enum CRStatus status = CR_ERROR; ++ guint32 cur_char = 0; ++ ++ g_return_val_if_fail (a_this && PRIVATE (a_this) ++ && PRIVATE (a_this)->input, CR_BAD_PARAM_ERROR); ++ ++ status = cr_input_peek_char (PRIVATE (a_this)->input, &cur_char); ++ ++ if (status != CR_OK) { ++ if (status == CR_END_OF_INPUT_ERROR) ++ return CR_OK; ++ return status; ++ } ++ ++ if (cr_utils_is_white_space (cur_char) == TRUE) { ++ gulong nb_chars = -1; /*consume all spaces */ ++ ++ status = cr_input_consume_white_spaces ++ (PRIVATE (a_this)->input, &nb_chars); ++ } ++ ++ return status; ++} ++ ++/** ++ *Parses a "comment" as defined in the css spec at [4.1.1]: ++ *COMMENT ::= \/\*[^*]*\*+([^/][^*]*\*+)*\/ . ++ *This complex regexp is just to say that comments start ++ *with the two chars '/''*' and ends with the two chars '*''/'. ++ *It also means that comments cannot be nested. ++ *So based on that, I've just tried to implement the parsing function ++ *simply and in a straight forward manner. ++ */ ++static enum CRStatus ++cr_tknzr_parse_comment (CRTknzr * a_this, ++ CRString ** a_comment) ++{ ++ enum CRStatus status = CR_OK; ++ CRInputPos init_pos; ++ guint32 cur_char = 0, next_char= 0; ++ CRString *comment = NULL; ++ CRParsingLocation loc = {0} ; ++ ++ g_return_val_if_fail (a_this && PRIVATE (a_this) ++ && PRIVATE (a_this)->input, ++ CR_BAD_PARAM_ERROR); ++ ++ RECORD_INITIAL_POS (a_this, &init_pos); ++ READ_NEXT_CHAR (a_this, &cur_char) ; ++ ENSURE_PARSING_COND (cur_char == '/'); ++ cr_tknzr_get_parsing_location (a_this, &loc) ; ++ ++ READ_NEXT_CHAR (a_this, &cur_char); ++ ENSURE_PARSING_COND (cur_char == '*'); ++ comment = cr_string_new (); ++ for (;;) { /* [^*]* */ ++ PEEK_NEXT_CHAR (a_this, &next_char); ++ if (next_char == '*') ++ break; ++ READ_NEXT_CHAR (a_this, &cur_char); ++ g_string_append_unichar (comment->stryng, cur_char); ++ } ++ /* Stop condition: next_char == '*' */ ++ for (;;) { /* \*+ */ ++ READ_NEXT_CHAR(a_this, &cur_char); ++ ENSURE_PARSING_COND (cur_char == '*'); ++ g_string_append_unichar (comment->stryng, cur_char); ++ PEEK_NEXT_CHAR (a_this, &next_char); ++ if (next_char != '*') ++ break; ++ } ++ /* Stop condition: next_char != '*' */ ++ for (;;) { /* ([^/][^*]*\*+)* */ ++ if (next_char == '/') ++ break; ++ READ_NEXT_CHAR(a_this, &cur_char); ++ g_string_append_unichar (comment->stryng, cur_char); ++ for (;;) { /* [^*]* */ ++ PEEK_NEXT_CHAR (a_this, &next_char); ++ if (next_char == '*') ++ break; ++ READ_NEXT_CHAR (a_this, &cur_char); ++ g_string_append_unichar (comment->stryng, cur_char); ++ } ++ /* Stop condition: next_char = '*', no need to verify, because peek and read exit to error anyway */ ++ for (;;) { /* \*+ */ ++ READ_NEXT_CHAR(a_this, &cur_char); ++ ENSURE_PARSING_COND (cur_char == '*'); ++ g_string_append_unichar (comment->stryng, cur_char); ++ PEEK_NEXT_CHAR (a_this, &next_char); ++ if (next_char != '*') ++ break; ++ } ++ /* Continue condition: next_char != '*' */ ++ } ++ /* Stop condition: next_char == '\/' */ ++ READ_NEXT_CHAR(a_this, &cur_char); ++ g_string_append_unichar (comment->stryng, cur_char); ++ ++ if (status == CR_OK) { ++ cr_parsing_location_copy (&comment->location, ++ &loc) ; ++ *a_comment = comment; ++ return CR_OK; ++ } ++ error: ++ ++ if (comment) { ++ cr_string_destroy (comment); ++ comment = NULL; ++ } ++ ++ cr_tknzr_set_cur_pos (a_this, &init_pos); ++ ++ return status; ++} ++ ++/** ++ *Parses an 'unicode' escape sequence defined ++ *in css spec at chap 4.1.1: ++ *unicode ::= \\[0-9a-f]{1,6}[ \n\r\t\f]? ++ *@param a_this the current instance of #CRTknzr. ++ *@param a_start out parameter. A pointer to the start ++ *of the unicode escape sequence. Must *NOT* be deleted by ++ *the caller. ++ *@param a_end out parameter. A pointer to the last character ++ *of the unicode escape sequence. Must *NOT* be deleted by the caller. ++ *@return CR_OK if parsing succeded, an error code otherwise. ++ *Error code can be either CR_PARSING_ERROR if the string ++ *parsed just doesn't ++ *respect the production or another error if a ++ *lower level error occurred. ++ */ ++static enum CRStatus ++cr_tknzr_parse_unicode_escape (CRTknzr * a_this, ++ guint32 * a_unicode, ++ CRParsingLocation *a_location) ++{ ++ guint32 cur_char; ++ CRInputPos init_pos; ++ glong occur = 0; ++ guint32 unicode = 0; ++ guchar *tmp_char_ptr1 = NULL, ++ *tmp_char_ptr2 = NULL; ++ enum CRStatus status = CR_OK; ++ ++ g_return_val_if_fail (a_this && PRIVATE (a_this) ++ && a_unicode, CR_BAD_PARAM_ERROR); ++ ++ /*first, let's backup the current position pointer */ ++ RECORD_INITIAL_POS (a_this, &init_pos); ++ ++ READ_NEXT_CHAR (a_this, &cur_char); ++ ++ if (cur_char != '\\') { ++ status = CR_PARSING_ERROR; ++ goto error; ++ } ++ if (a_location) { ++ cr_tknzr_get_parsing_location ++ (a_this, a_location) ; ++ } ++ PEEK_NEXT_CHAR (a_this, &cur_char); ++ ++ for (occur = 0, unicode = 0; ((cur_char >= '0' && cur_char <= '9') ++ || (cur_char >= 'a' && cur_char <= 'f') ++ || (cur_char >= 'A' && cur_char <= 'F')) ++ && occur < 6; occur++) { ++ gint cur_char_val = 0; ++ ++ READ_NEXT_CHAR (a_this, &cur_char); ++ ++ if ((cur_char >= '0' && cur_char <= '9')) { ++ cur_char_val = (cur_char - '0'); ++ } else if ((cur_char >= 'a' && cur_char <= 'f')) { ++ cur_char_val = 10 + (cur_char - 'a'); ++ } else if ((cur_char >= 'A' && cur_char <= 'F')) { ++ cur_char_val = 10 + (cur_char - 'A'); ++ } ++ ++ unicode = unicode * 16 + cur_char_val; ++ ++ PEEK_NEXT_CHAR (a_this, &cur_char); ++ } ++ ++ /* Eat a whitespace if possible. */ ++ cr_tknzr_parse_w (a_this, &tmp_char_ptr1, ++ &tmp_char_ptr2, NULL); ++ *a_unicode = unicode; ++ return CR_OK; ++ ++ error: ++ /* ++ *restore the initial position pointer backuped at ++ *the beginning of this function. ++ */ ++ cr_tknzr_set_cur_pos (a_this, &init_pos); ++ ++ return status; ++} ++ ++/** ++ *parses an escape sequence as defined by the css spec: ++ *escape ::= {unicode}|\\[ -~\200-\4177777] ++ *@param a_this the current instance of #CRTknzr . ++ */ ++static enum CRStatus ++cr_tknzr_parse_escape (CRTknzr * a_this, guint32 * a_esc_code, ++ CRParsingLocation *a_location) ++{ ++ enum CRStatus status = CR_OK; ++ guint32 cur_char = 0; ++ CRInputPos init_pos; ++ guchar next_chars[2]; ++ ++ g_return_val_if_fail (a_this && PRIVATE (a_this) ++ && a_esc_code, CR_BAD_PARAM_ERROR); ++ ++ RECORD_INITIAL_POS (a_this, &init_pos); ++ ++ PEEK_BYTE (a_this, 1, &next_chars[0]); ++ PEEK_BYTE (a_this, 2, &next_chars[1]); ++ ++ if (next_chars[0] != '\\') { ++ status = CR_PARSING_ERROR; ++ goto error; ++ } ++ ++ if ((next_chars[1] >= '0' && next_chars[1] <= '9') ++ || (next_chars[1] >= 'a' && next_chars[1] <= 'f') ++ || (next_chars[1] >= 'A' && next_chars[1] <= 'F')) { ++ status = cr_tknzr_parse_unicode_escape (a_this, a_esc_code, ++ a_location); ++ } else { ++ /*consume the '\' char */ ++ READ_NEXT_CHAR (a_this, &cur_char); ++ if (a_location) { ++ cr_tknzr_get_parsing_location (a_this, ++ a_location) ; ++ } ++ /*then read the char after the '\' */ ++ READ_NEXT_CHAR (a_this, &cur_char); ++ ++ if (cur_char != ' ' && (cur_char < 200 || cur_char > 4177777)) { ++ status = CR_PARSING_ERROR; ++ goto error; ++ } ++ *a_esc_code = cur_char; ++ ++ } ++ if (status == CR_OK) { ++ return CR_OK; ++ } ++ error: ++ cr_tknzr_set_cur_pos (a_this, &init_pos); ++ return status; ++} ++ ++/** ++ *Parses a string type as defined in css spec [4.1.1]: ++ * ++ *string ::= {string1}|{string2} ++ *string1 ::= \"([\t !#$%&(-~]|\\{nl}|\'|{nonascii}|{escape})*\" ++ *string2 ::= \'([\t !#$%&(-~]|\\{nl}|\"|{nonascii}|{escape})*\' ++ * ++ *@param a_this the current instance of #CRTknzr. ++ *@param a_start out parameter. Upon successfull completion, ++ *points to the beginning of the string, points to an undefined value ++ *otherwise. ++ *@param a_end out parameter. Upon successfull completion, points to ++ *the beginning of the string, points to an undefined value otherwise. ++ *@return CR_OK upon successfull completion, an error code otherwise. ++ */ ++static enum CRStatus ++cr_tknzr_parse_string (CRTknzr * a_this, CRString ** a_str) ++{ ++ guint32 cur_char = 0, ++ delim = 0; ++ CRInputPos init_pos; ++ enum CRStatus status = CR_OK; ++ CRString *str = NULL; ++ ++ g_return_val_if_fail (a_this && PRIVATE (a_this) ++ && PRIVATE (a_this)->input ++ && a_str, CR_BAD_PARAM_ERROR); ++ ++ RECORD_INITIAL_POS (a_this, &init_pos); ++ READ_NEXT_CHAR (a_this, &cur_char); ++ ++ if (cur_char == '"') ++ delim = '"'; ++ else if (cur_char == '\'') ++ delim = '\''; ++ else { ++ status = CR_PARSING_ERROR; ++ goto error; ++ } ++ str = cr_string_new (); ++ if (str) { ++ cr_tknzr_get_parsing_location ++ (a_this, &str->location) ; ++ } ++ for (;;) { ++ guchar next_chars[2] = { 0 }; ++ ++ PEEK_BYTE (a_this, 1, &next_chars[0]); ++ PEEK_BYTE (a_this, 2, &next_chars[1]); ++ ++ if (next_chars[0] == '\\') { ++ guchar *tmp_char_ptr1 = NULL, ++ *tmp_char_ptr2 = NULL; ++ guint32 esc_code = 0; ++ ++ if (next_chars[1] == '\'' || next_chars[1] == '"') { ++ g_string_append_unichar (str->stryng, ++ next_chars[1]); ++ SKIP_BYTES (a_this, 2); ++ status = CR_OK; ++ } else { ++ status = cr_tknzr_parse_escape ++ (a_this, &esc_code, NULL); ++ ++ if (status == CR_OK) { ++ g_string_append_unichar ++ (str->stryng, ++ esc_code); ++ } ++ } ++ ++ if (status != CR_OK) { ++ /* ++ *consume the '\' char, and try to parse ++ *a newline. ++ */ ++ READ_NEXT_CHAR (a_this, &cur_char); ++ ++ status = cr_tknzr_parse_nl ++ (a_this, &tmp_char_ptr1, ++ &tmp_char_ptr2, NULL); ++ } ++ ++ CHECK_PARSING_STATUS (status, FALSE); ++ } else if (strchr ("\t !#$%&", next_chars[0]) ++ || (next_chars[0] >= '(' && next_chars[0] <= '~')) { ++ READ_NEXT_CHAR (a_this, &cur_char); ++ g_string_append_unichar (str->stryng, ++ cur_char); ++ status = CR_OK; ++ } ++ ++ else if (cr_utils_is_nonascii (next_chars[0])) { ++ READ_NEXT_CHAR (a_this, &cur_char); ++ g_string_append_unichar (str->stryng, cur_char); ++ } else if (next_chars[0] == delim) { ++ READ_NEXT_CHAR (a_this, &cur_char); ++ break; ++ } else { ++ status = CR_PARSING_ERROR; ++ goto error; ++ } ++ } ++ ++ if (status == CR_OK) { ++ if (*a_str == NULL) { ++ *a_str = str; ++ str = NULL; ++ } else { ++ (*a_str)->stryng = g_string_append_len ++ ((*a_str)->stryng, ++ str->stryng->str, ++ str->stryng->len); ++ cr_string_destroy (str); ++ } ++ return CR_OK; ++ } ++ ++ error: ++ ++ if (str) { ++ cr_string_destroy (str) ; ++ str = NULL; ++ } ++ cr_tknzr_set_cur_pos (a_this, &init_pos); ++ return status; ++} ++ ++/** ++ *Parses the an nmstart as defined by the css2 spec [4.1.1]: ++ * nmstart [a-zA-Z]|{nonascii}|{escape} ++ * ++ *@param a_this the current instance of #CRTknzr. ++ *@param a_start out param. A pointer to the starting point of ++ *the token. ++ *@param a_end out param. A pointer to the ending point of the ++ *token. ++ *@param a_char out param. The actual parsed nmchar. ++ *@return CR_OK upon successfull completion, ++ *an error code otherwise. ++ */ ++static enum CRStatus ++cr_tknzr_parse_nmstart (CRTknzr * a_this, ++ guint32 * a_char, ++ CRParsingLocation *a_location) ++{ ++ CRInputPos init_pos; ++ enum CRStatus status = CR_OK; ++ guint32 cur_char = 0, ++ next_char = 0; ++ ++ g_return_val_if_fail (a_this && PRIVATE (a_this) ++ && PRIVATE (a_this)->input ++ && a_char, CR_BAD_PARAM_ERROR); ++ ++ RECORD_INITIAL_POS (a_this, &init_pos); ++ ++ PEEK_NEXT_CHAR (a_this, &next_char); ++ ++ if (next_char == '\\') { ++ status = cr_tknzr_parse_escape (a_this, a_char, ++ a_location); ++ ++ if (status != CR_OK) ++ goto error; ++ ++ } else if (cr_utils_is_nonascii (next_char) == TRUE ++ || ((next_char >= 'a') && (next_char <= 'z')) ++ || ((next_char >= 'A') && (next_char <= 'Z')) ++ ) { ++ READ_NEXT_CHAR (a_this, &cur_char); ++ if (a_location) { ++ cr_tknzr_get_parsing_location (a_this, ++ a_location) ; ++ } ++ *a_char = cur_char; ++ status = CR_OK; ++ } else { ++ status = CR_PARSING_ERROR; ++ goto error; ++ } ++ ++ return CR_OK; ++ ++ error: ++ cr_tknzr_set_cur_pos (a_this, &init_pos); ++ ++ return status; ++ ++} ++ ++/** ++ *Parses an nmchar as described in the css spec at ++ *chap 4.1.1: ++ *nmchar ::= [a-z0-9-]|{nonascii}|{escape} ++ * ++ *Humm, I have added the possibility for nmchar to ++ *contain upper case letters. ++ * ++ *@param a_this the current instance of #CRTknzr. ++ *@param a_start out param. A pointer to the starting point of ++ *the token. ++ *@param a_end out param. A pointer to the ending point of the ++ *token. ++ *@param a_char out param. The actual parsed nmchar. ++ *@return CR_OK upon successfull completion, ++ *an error code otherwise. ++ */ ++static enum CRStatus ++cr_tknzr_parse_nmchar (CRTknzr * a_this, guint32 * a_char, ++ CRParsingLocation *a_location) ++{ ++ guint32 cur_char = 0, ++ next_char = 0; ++ enum CRStatus status = CR_OK; ++ CRInputPos init_pos; ++ ++ g_return_val_if_fail (a_this && PRIVATE (a_this) && a_char, ++ CR_BAD_PARAM_ERROR); ++ ++ RECORD_INITIAL_POS (a_this, &init_pos); ++ ++ status = cr_input_peek_char (PRIVATE (a_this)->input, ++ &next_char) ; ++ if (status != CR_OK) ++ goto error; ++ ++ if (next_char == '\\') { ++ status = cr_tknzr_parse_escape (a_this, a_char, ++ a_location); ++ ++ if (status != CR_OK) ++ goto error; ++ ++ } else if (cr_utils_is_nonascii (next_char) == TRUE ++ || ((next_char >= 'a') && (next_char <= 'z')) ++ || ((next_char >= 'A') && (next_char <= 'Z')) ++ || ((next_char >= '0') && (next_char <= '9')) ++ || (next_char == '-') ++ || (next_char == '_') /*'_' not allowed by the spec. */ ++ ) { ++ READ_NEXT_CHAR (a_this, &cur_char); ++ *a_char = cur_char; ++ status = CR_OK; ++ if (a_location) { ++ cr_tknzr_get_parsing_location ++ (a_this, a_location) ; ++ } ++ } else { ++ status = CR_PARSING_ERROR; ++ goto error; ++ } ++ return CR_OK; ++ ++ error: ++ cr_tknzr_set_cur_pos (a_this, &init_pos); ++ return status; ++} ++ ++/** ++ *Parses an "ident" as defined in css spec [4.1.1]: ++ *ident ::= {nmstart}{nmchar}* ++ * ++ *Actually parses it using the css3 grammar: ++ *ident ::= -?{nmstart}{nmchar}* ++ *@param a_this the currens instance of #CRTknzr. ++ * ++ *@param a_str a pointer to parsed ident. If *a_str is NULL, ++ *this function allocates a new instance of CRString. If not, ++ *the function just appends the parsed string to the one passed. ++ *In both cases it is up to the caller to free *a_str. ++ * ++ *@return CR_OK upon successfull completion, an error code ++ *otherwise. ++ */ ++static enum CRStatus ++cr_tknzr_parse_ident (CRTknzr * a_this, CRString ** a_str) ++{ ++ guint32 tmp_char = 0; ++ CRString *stringue = NULL ; ++ CRInputPos init_pos; ++ enum CRStatus status = CR_OK; ++ gboolean location_is_set = FALSE ; ++ ++ g_return_val_if_fail (a_this && PRIVATE (a_this) ++ && PRIVATE (a_this)->input ++ && a_str, CR_BAD_PARAM_ERROR); ++ ++ RECORD_INITIAL_POS (a_this, &init_pos); ++ PEEK_NEXT_CHAR (a_this, &tmp_char) ; ++ stringue = cr_string_new () ; ++ g_return_val_if_fail (stringue, ++ CR_OUT_OF_MEMORY_ERROR) ; ++ ++ if (tmp_char == '-') { ++ READ_NEXT_CHAR (a_this, &tmp_char) ; ++ cr_tknzr_get_parsing_location ++ (a_this, &stringue->location) ; ++ location_is_set = TRUE ; ++ g_string_append_unichar (stringue->stryng, ++ tmp_char) ; ++ } ++ status = cr_tknzr_parse_nmstart (a_this, &tmp_char, NULL); ++ if (status != CR_OK) { ++ status = CR_PARSING_ERROR; ++ goto end ; ++ } ++ if (location_is_set == FALSE) { ++ cr_tknzr_get_parsing_location ++ (a_this, &stringue->location) ; ++ location_is_set = TRUE ; ++ } ++ g_string_append_unichar (stringue->stryng, tmp_char); ++ for (;;) { ++ status = cr_tknzr_parse_nmchar (a_this, ++ &tmp_char, ++ NULL); ++ if (status != CR_OK) { ++ status = CR_OK ; ++ break; ++ } ++ g_string_append_unichar (stringue->stryng, tmp_char); ++ } ++ if (status == CR_OK) { ++ if (!*a_str) { ++ *a_str = stringue ; ++ ++ } else { ++ g_string_append_len ((*a_str)->stryng, ++ stringue->stryng->str, ++ stringue->stryng->len) ; ++ cr_string_destroy (stringue) ; ++ } ++ stringue = NULL ; ++ } ++ ++ error: ++ end: ++ if (stringue) { ++ cr_string_destroy (stringue) ; ++ stringue = NULL ; ++ } ++ if (status != CR_OK ) { ++ cr_tknzr_set_cur_pos (a_this, &init_pos) ; ++ } ++ return status ; ++} ++ ++ ++/** ++ *Parses a "name" as defined by css spec [4.1.1]: ++ *name ::= {nmchar}+ ++ * ++ *@param a_this the current instance of #CRTknzr. ++ * ++ *@param a_str out parameter. A pointer to the successfully parsed ++ *name. If *a_str is set to NULL, this function allocates a new instance ++ *of CRString. If not, it just appends the parsed name to the passed *a_str. ++ *In both cases, it is up to the caller to free *a_str. ++ * ++ *@return CR_OK upon successfull completion, an error code otherwise. ++ */ ++static enum CRStatus ++cr_tknzr_parse_name (CRTknzr * a_this, ++ CRString ** a_str) ++{ ++ guint32 tmp_char = 0; ++ CRInputPos init_pos; ++ enum CRStatus status = CR_OK; ++ gboolean str_needs_free = FALSE, ++ is_first_nmchar=TRUE ; ++ glong i = 0; ++ CRParsingLocation loc = {0} ; ++ ++ g_return_val_if_fail (a_this && PRIVATE (a_this) ++ && PRIVATE (a_this)->input ++ && a_str, ++ CR_BAD_PARAM_ERROR) ; ++ ++ RECORD_INITIAL_POS (a_this, &init_pos); ++ ++ if (*a_str == NULL) { ++ *a_str = cr_string_new (); ++ str_needs_free = TRUE; ++ } ++ for (i = 0;; i++) { ++ if (is_first_nmchar == TRUE) { ++ status = cr_tknzr_parse_nmchar ++ (a_this, &tmp_char, ++ &loc) ; ++ is_first_nmchar = FALSE ; ++ } else { ++ status = cr_tknzr_parse_nmchar ++ (a_this, &tmp_char, NULL) ; ++ } ++ if (status != CR_OK) ++ break; ++ g_string_append_unichar ((*a_str)->stryng, ++ tmp_char); ++ } ++ if (i > 0) { ++ cr_parsing_location_copy ++ (&(*a_str)->location, &loc) ; ++ return CR_OK; ++ } ++ if (str_needs_free == TRUE && *a_str) { ++ cr_string_destroy (*a_str); ++ *a_str = NULL; ++ } ++ cr_tknzr_set_cur_pos (a_this, &init_pos); ++ return CR_PARSING_ERROR; ++} ++ ++/** ++ *Parses a "hash" as defined by the css spec in [4.1.1]: ++ *HASH ::= #{name} ++ */ ++static enum CRStatus ++cr_tknzr_parse_hash (CRTknzr * a_this, CRString ** a_str) ++{ ++ guint32 cur_char = 0; ++ CRInputPos init_pos; ++ enum CRStatus status = CR_OK; ++ gboolean str_needs_free = FALSE; ++ CRParsingLocation loc = {0} ; ++ ++ g_return_val_if_fail (a_this && PRIVATE (a_this) ++ && PRIVATE (a_this)->input, ++ CR_BAD_PARAM_ERROR); ++ ++ RECORD_INITIAL_POS (a_this, &init_pos); ++ READ_NEXT_CHAR (a_this, &cur_char); ++ if (cur_char != '#') { ++ status = CR_PARSING_ERROR; ++ goto error; ++ } ++ if (*a_str == NULL) { ++ *a_str = cr_string_new (); ++ str_needs_free = TRUE; ++ } ++ cr_tknzr_get_parsing_location (a_this, ++ &loc) ; ++ status = cr_tknzr_parse_name (a_this, a_str); ++ cr_parsing_location_copy (&(*a_str)->location, &loc) ; ++ if (status != CR_OK) { ++ goto error; ++ } ++ return CR_OK; ++ ++ error: ++ if (str_needs_free == TRUE && *a_str) { ++ cr_string_destroy (*a_str); ++ *a_str = NULL; ++ } ++ ++ cr_tknzr_set_cur_pos (a_this, &init_pos); ++ return status; ++} ++ ++/** ++ *Parses an uri as defined by the css spec [4.1.1]: ++ * URI ::= url\({w}{string}{w}\) ++ * |url\({w}([!#$%&*-~]|{nonascii}|{escape})*{w}\) ++ * ++ *@param a_this the current instance of #CRTknzr. ++ *@param a_str the successfully parsed url. ++ *@return CR_OK upon successfull completion, an error code otherwise. ++ */ ++static enum CRStatus ++cr_tknzr_parse_uri (CRTknzr * a_this, ++ CRString ** a_str) ++{ ++ guint32 cur_char = 0; ++ CRInputPos init_pos; ++ enum CRStatus status = CR_PARSING_ERROR; ++ guchar tab[4] = { 0 }, *tmp_ptr1 = NULL, *tmp_ptr2 = NULL; ++ CRString *str = NULL; ++ CRParsingLocation location = {0} ; ++ ++ g_return_val_if_fail (a_this ++ && PRIVATE (a_this) ++ && PRIVATE (a_this)->input ++ && a_str, ++ CR_BAD_PARAM_ERROR); ++ ++ RECORD_INITIAL_POS (a_this, &init_pos); ++ ++ PEEK_BYTE (a_this, 1, &tab[0]); ++ PEEK_BYTE (a_this, 2, &tab[1]); ++ PEEK_BYTE (a_this, 3, &tab[2]); ++ PEEK_BYTE (a_this, 4, &tab[3]); ++ ++ if (tab[0] != 'u' || tab[1] != 'r' || tab[2] != 'l' || tab[3] != '(') { ++ status = CR_PARSING_ERROR; ++ goto error; ++ } ++ /* ++ *Here, we want to skip 4 bytes ('u''r''l''('). ++ *But we also need to keep track of the parsing location ++ *of the 'u'. So, we skip 1 byte, we record the parsing ++ *location, then we skip the 3 remaining bytes. ++ */ ++ SKIP_CHARS (a_this, 1); ++ cr_tknzr_get_parsing_location (a_this, &location) ; ++ SKIP_CHARS (a_this, 3); ++ cr_tknzr_try_to_skip_spaces (a_this); ++ status = cr_tknzr_parse_string (a_this, a_str); ++ ++ if (status == CR_OK) { ++ guint32 next_char = 0; ++ status = cr_tknzr_parse_w (a_this, &tmp_ptr1, ++ &tmp_ptr2, NULL); ++ cr_tknzr_try_to_skip_spaces (a_this); ++ PEEK_NEXT_CHAR (a_this, &next_char); ++ if (next_char == ')') { ++ READ_NEXT_CHAR (a_this, &cur_char); ++ status = CR_OK; ++ } else { ++ status = CR_PARSING_ERROR; ++ } ++ } ++ if (status != CR_OK) { ++ str = cr_string_new (); ++ for (;;) { ++ guint32 next_char = 0; ++ PEEK_NEXT_CHAR (a_this, &next_char); ++ if (strchr ("!#$%&", next_char) ++ || (next_char >= '*' && next_char <= '~') ++ || (cr_utils_is_nonascii (next_char) == TRUE)) { ++ READ_NEXT_CHAR (a_this, &cur_char); ++ g_string_append_unichar ++ (str->stryng, cur_char); ++ status = CR_OK; ++ } else { ++ guint32 esc_code = 0; ++ status = cr_tknzr_parse_escape ++ (a_this, &esc_code, NULL); ++ if (status == CR_OK) { ++ g_string_append_unichar ++ (str->stryng, ++ esc_code); ++ } else { ++ status = CR_OK; ++ break; ++ } ++ } ++ } ++ cr_tknzr_try_to_skip_spaces (a_this); ++ READ_NEXT_CHAR (a_this, &cur_char); ++ if (cur_char == ')') { ++ status = CR_OK; ++ } else { ++ status = CR_PARSING_ERROR; ++ goto error; ++ } ++ if (str) { ++ if (*a_str == NULL) { ++ *a_str = str; ++ str = NULL; ++ } else { ++ g_string_append_len ++ ((*a_str)->stryng, ++ str->stryng->str, ++ str->stryng->len); ++ cr_string_destroy (str); ++ } ++ } ++ } ++ ++ cr_parsing_location_copy ++ (&(*a_str)->location, ++ &location) ; ++ return CR_OK ; ++ error: ++ if (str) { ++ cr_string_destroy (str); ++ str = NULL; ++ } ++ cr_tknzr_set_cur_pos (a_this, &init_pos); ++ return status; ++} ++ ++/** ++ *parses an RGB as defined in the css2 spec. ++ *rgb: rgb '('S*{num}%?S* ',' {num}#?S*,S*{num}#?S*')' ++ * ++ *@param a_this the "this pointer" of the current instance of ++ *@param a_rgb out parameter the parsed rgb. ++ *@return CR_OK upon successfull completion, an error code otherwise. ++ */ ++static enum CRStatus ++cr_tknzr_parse_rgb (CRTknzr * a_this, CRRgb ** a_rgb) ++{ ++ enum CRStatus status = CR_OK; ++ CRInputPos init_pos; ++ CRNum *num = NULL; ++ guchar next_bytes[3] = { 0 }, cur_byte = 0; ++ glong red = 0, ++ green = 0, ++ blue = 0, ++ i = 0; ++ gboolean is_percentage = FALSE; ++ CRParsingLocation location = {0} ; ++ ++ g_return_val_if_fail (a_this && PRIVATE (a_this), CR_BAD_PARAM_ERROR); ++ ++ RECORD_INITIAL_POS (a_this, &init_pos); ++ ++ PEEK_BYTE (a_this, 1, &next_bytes[0]); ++ PEEK_BYTE (a_this, 2, &next_bytes[1]); ++ PEEK_BYTE (a_this, 3, &next_bytes[2]); ++ ++ if (((next_bytes[0] == 'r') || (next_bytes[0] == 'R')) ++ && ((next_bytes[1] == 'g') || (next_bytes[1] == 'G')) ++ && ((next_bytes[2] == 'b') || (next_bytes[2] == 'B'))) { ++ SKIP_CHARS (a_this, 1); ++ cr_tknzr_get_parsing_location (a_this, &location) ; ++ SKIP_CHARS (a_this, 2); ++ } else { ++ status = CR_PARSING_ERROR; ++ goto error; ++ } ++ READ_NEXT_BYTE (a_this, &cur_byte); ++ ENSURE_PARSING_COND (cur_byte == '('); ++ ++ cr_tknzr_try_to_skip_spaces (a_this); ++ status = cr_tknzr_parse_num (a_this, &num); ++ ENSURE_PARSING_COND ((status == CR_OK) && (num != NULL)); ++ ++ if (num->val > G_MAXLONG) { ++ status = CR_PARSING_ERROR; ++ goto error; ++ } ++ ++ red = num->val; ++ cr_num_destroy (num); ++ num = NULL; ++ ++ PEEK_BYTE (a_this, 1, &next_bytes[0]); ++ if (next_bytes[0] == '%') { ++ SKIP_CHARS (a_this, 1); ++ is_percentage = TRUE; ++ } ++ cr_tknzr_try_to_skip_spaces (a_this); ++ ++ for (i = 0; i < 2; i++) { ++ READ_NEXT_BYTE (a_this, &cur_byte); ++ ENSURE_PARSING_COND (cur_byte == ','); ++ ++ cr_tknzr_try_to_skip_spaces (a_this); ++ status = cr_tknzr_parse_num (a_this, &num); ++ ENSURE_PARSING_COND ((status == CR_OK) && (num != NULL)); ++ ++ if (num->val > G_MAXLONG) { ++ status = CR_PARSING_ERROR; ++ goto error; ++ } ++ ++ PEEK_BYTE (a_this, 1, &next_bytes[0]); ++ if (next_bytes[0] == '%') { ++ SKIP_CHARS (a_this, 1); ++ is_percentage = 1; ++ } ++ ++ if (i == 0) { ++ green = num->val; ++ } else if (i == 1) { ++ blue = num->val; ++ } ++ ++ if (num) { ++ cr_num_destroy (num); ++ num = NULL; ++ } ++ cr_tknzr_try_to_skip_spaces (a_this); ++ } ++ ++ READ_NEXT_BYTE (a_this, &cur_byte); ++ if (*a_rgb == NULL) { ++ *a_rgb = cr_rgb_new_with_vals (red, green, blue, ++ is_percentage); ++ ++ if (*a_rgb == NULL) { ++ status = CR_ERROR; ++ goto error; ++ } ++ status = CR_OK; ++ } else { ++ (*a_rgb)->red = red; ++ (*a_rgb)->green = green; ++ (*a_rgb)->blue = blue; ++ (*a_rgb)->is_percentage = is_percentage; ++ ++ status = CR_OK; ++ } ++ ++ if (status == CR_OK) { ++ if (a_rgb && *a_rgb) { ++ cr_parsing_location_copy ++ (&(*a_rgb)->location, ++ &location) ; ++ } ++ return CR_OK; ++ } ++ ++ error: ++ if (num) { ++ cr_num_destroy (num); ++ num = NULL; ++ } ++ ++ cr_tknzr_set_cur_pos (a_this, &init_pos); ++ return CR_OK; ++} ++ ++/** ++ *Parses a atkeyword as defined by the css spec in [4.1.1]: ++ *ATKEYWORD ::= @{ident} ++ * ++ *@param a_this the "this pointer" of the current instance of ++ *#CRTknzr. ++ * ++ *@param a_str out parameter. The parsed atkeyword. If *a_str is ++ *set to NULL this function allocates a new instance of CRString and ++ *sets it to the parsed atkeyword. If not, this function just appends ++ *the parsed atkeyword to the end of *a_str. In both cases it is up to ++ *the caller to free *a_str. ++ * ++ *@return CR_OK upon successfull completion, an error code otherwise. ++ */ ++static enum CRStatus ++cr_tknzr_parse_atkeyword (CRTknzr * a_this, ++ CRString ** a_str) ++{ ++ guint32 cur_char = 0; ++ CRInputPos init_pos; ++ gboolean str_needs_free = FALSE; ++ enum CRStatus status = CR_OK; ++ ++ g_return_val_if_fail (a_this && PRIVATE (a_this) ++ && PRIVATE (a_this)->input ++ && a_str, CR_BAD_PARAM_ERROR); ++ ++ RECORD_INITIAL_POS (a_this, &init_pos); ++ ++ READ_NEXT_CHAR (a_this, &cur_char); ++ ++ if (cur_char != '@') { ++ status = CR_PARSING_ERROR; ++ goto error; ++ } ++ ++ if (*a_str == NULL) { ++ *a_str = cr_string_new (); ++ str_needs_free = TRUE; ++ } ++ status = cr_tknzr_parse_ident (a_this, a_str); ++ if (status != CR_OK) { ++ goto error; ++ } ++ return CR_OK; ++ error: ++ ++ if (str_needs_free == TRUE && *a_str) { ++ cr_string_destroy (*a_str); ++ *a_str = NULL; ++ } ++ cr_tknzr_set_cur_pos (a_this, &init_pos); ++ return status; ++} ++ ++static enum CRStatus ++cr_tknzr_parse_important (CRTknzr * a_this, ++ CRParsingLocation *a_location) ++{ ++ guint32 cur_char = 0; ++ CRInputPos init_pos; ++ enum CRStatus status = CR_OK; ++ ++ g_return_val_if_fail (a_this && PRIVATE (a_this) ++ && PRIVATE (a_this)->input, ++ CR_BAD_PARAM_ERROR); ++ ++ RECORD_INITIAL_POS (a_this, &init_pos); ++ READ_NEXT_CHAR (a_this, &cur_char); ++ ENSURE_PARSING_COND (cur_char == '!'); ++ if (a_location) { ++ cr_tknzr_get_parsing_location (a_this, ++ a_location) ; ++ } ++ cr_tknzr_try_to_skip_spaces (a_this); ++ ++ if (BYTE (PRIVATE (a_this)->input, 1, NULL) == 'i' ++ && BYTE (PRIVATE (a_this)->input, 2, NULL) == 'm' ++ && BYTE (PRIVATE (a_this)->input, 3, NULL) == 'p' ++ && BYTE (PRIVATE (a_this)->input, 4, NULL) == 'o' ++ && BYTE (PRIVATE (a_this)->input, 5, NULL) == 'r' ++ && BYTE (PRIVATE (a_this)->input, 6, NULL) == 't' ++ && BYTE (PRIVATE (a_this)->input, 7, NULL) == 'a' ++ && BYTE (PRIVATE (a_this)->input, 8, NULL) == 'n' ++ && BYTE (PRIVATE (a_this)->input, 9, NULL) == 't') { ++ SKIP_BYTES (a_this, 9); ++ if (a_location) { ++ cr_tknzr_get_parsing_location (a_this, ++ a_location) ; ++ } ++ return CR_OK; ++ } else { ++ status = CR_PARSING_ERROR; ++ } ++ ++ error: ++ cr_tknzr_set_cur_pos (a_this, &init_pos); ++ ++ return status; ++} ++ ++/** ++ *Parses a num as defined in the css spec [4.1.1]: ++ *[0-9]+|[0-9]*\.[0-9]+ ++ *@param a_this the current instance of #CRTknzr. ++ *@param a_num out parameter. The parsed number. ++ *@return CR_OK upon successfull completion, ++ *an error code otherwise. ++ * ++ *The CSS specification says that numbers may be ++ *preceeded by '+' or '-' to indicate the sign. ++ *Technically, the "num" construction as defined ++ *by the tokenizer doesn't allow this, but we parse ++ *it here for simplicity. ++ */ ++static enum CRStatus ++cr_tknzr_parse_num (CRTknzr * a_this, ++ CRNum ** a_num) ++{ ++ enum CRStatus status = CR_PARSING_ERROR; ++ enum CRNumType val_type = NUM_GENERIC; ++ gboolean parsing_dec, /* true iff seen decimal point. */ ++ parsed; /* true iff the substring seen so far is a valid CSS ++ number, i.e. `[0-9]+|[0-9]*\.[0-9]+'. */ ++ guint32 cur_char = 0, ++ next_char = 0; ++ gdouble numerator, denominator = 1; ++ CRInputPos init_pos; ++ CRParsingLocation location = {0} ; ++ int sign = 1; ++ ++ g_return_val_if_fail (a_this && PRIVATE (a_this) ++ && PRIVATE (a_this)->input, ++ CR_BAD_PARAM_ERROR); ++ ++ RECORD_INITIAL_POS (a_this, &init_pos); ++ READ_NEXT_CHAR (a_this, &cur_char); ++ ++ if (cur_char == '+' || cur_char == '-') { ++ if (cur_char == '-') { ++ sign = -1; ++ } ++ READ_NEXT_CHAR (a_this, &cur_char); ++ } ++ ++ if (IS_NUM (cur_char)) { ++ numerator = (cur_char - '0'); ++ parsing_dec = FALSE; ++ parsed = TRUE; ++ } else if (cur_char == '.') { ++ numerator = 0; ++ parsing_dec = TRUE; ++ parsed = FALSE; ++ } else { ++ status = CR_PARSING_ERROR; ++ goto error; ++ } ++ cr_tknzr_get_parsing_location (a_this, &location) ; ++ ++ for (;;) { ++ status = cr_tknzr_peek_char (a_this, &next_char); ++ if (status != CR_OK) { ++ if (status == CR_END_OF_INPUT_ERROR) ++ status = CR_OK; ++ break; ++ } ++ if (next_char == '.') { ++ if (parsing_dec) { ++ status = CR_PARSING_ERROR; ++ goto error; ++ } ++ ++ READ_NEXT_CHAR (a_this, &cur_char); ++ parsing_dec = TRUE; ++ parsed = FALSE; /* In CSS, there must be at least ++ one digit after `.'. */ ++ } else if (IS_NUM (next_char)) { ++ READ_NEXT_CHAR (a_this, &cur_char); ++ parsed = TRUE; ++ ++ numerator = numerator * 10 + (cur_char - '0'); ++ if (parsing_dec) { ++ denominator *= 10; ++ } ++ } else { ++ break; ++ } ++ } ++ ++ if (!parsed) { ++ status = CR_PARSING_ERROR; ++ } ++ ++ /* ++ *Now, set the output param values. ++ */ ++ if (status == CR_OK) { ++ gdouble val = (numerator / denominator) * sign; ++ if (*a_num == NULL) { ++ *a_num = cr_num_new_with_val (val, val_type); ++ ++ if (*a_num == NULL) { ++ status = CR_ERROR; ++ goto error; ++ } ++ } else { ++ (*a_num)->val = val; ++ (*a_num)->type = val_type; ++ } ++ cr_parsing_location_copy (&(*a_num)->location, ++ &location) ; ++ return CR_OK; ++ } ++ ++ error: ++ ++ cr_tknzr_set_cur_pos (a_this, &init_pos); ++ ++ return status; ++} ++ ++/********************************************* ++ *PUBLIC methods ++ ********************************************/ ++ ++CRTknzr * ++cr_tknzr_new (CRInput * a_input) ++{ ++ CRTknzr *result = NULL; ++ ++ result = g_try_malloc (sizeof (CRTknzr)); ++ ++ if (result == NULL) { ++ cr_utils_trace_info ("Out of memory"); ++ return NULL; ++ } ++ ++ memset (result, 0, sizeof (CRTknzr)); ++ ++ result->priv = g_try_malloc (sizeof (CRTknzrPriv)); ++ ++ if (result->priv == NULL) { ++ cr_utils_trace_info ("Out of memory"); ++ ++ if (result) { ++ g_free (result); ++ result = NULL; ++ } ++ ++ return NULL; ++ } ++ memset (result->priv, 0, sizeof (CRTknzrPriv)); ++ if (a_input) ++ cr_tknzr_set_input (result, a_input); ++ return result; ++} ++ ++CRTknzr * ++cr_tknzr_new_from_buf (guchar * a_buf, gulong a_len, ++ enum CREncoding a_enc, ++ gboolean a_free_at_destroy) ++{ ++ CRTknzr *result = NULL; ++ CRInput *input = NULL; ++ ++ input = cr_input_new_from_buf (a_buf, a_len, a_enc, ++ a_free_at_destroy); ++ ++ g_return_val_if_fail (input != NULL, NULL); ++ ++ result = cr_tknzr_new (input); ++ ++ return result; ++} ++ ++CRTknzr * ++cr_tknzr_new_from_uri (const guchar * a_file_uri, ++ enum CREncoding a_enc) ++{ ++ CRTknzr *result = NULL; ++ CRInput *input = NULL; ++ ++ input = cr_input_new_from_uri ((const gchar *) a_file_uri, a_enc); ++ g_return_val_if_fail (input != NULL, NULL); ++ ++ result = cr_tknzr_new (input); ++ ++ return result; ++} ++ ++void ++cr_tknzr_ref (CRTknzr * a_this) ++{ ++ g_return_if_fail (a_this && PRIVATE (a_this)); ++ ++ PRIVATE (a_this)->ref_count++; ++} ++ ++gboolean ++cr_tknzr_unref (CRTknzr * a_this) ++{ ++ g_return_val_if_fail (a_this && PRIVATE (a_this), FALSE); ++ ++ if (PRIVATE (a_this)->ref_count > 0) { ++ PRIVATE (a_this)->ref_count--; ++ } ++ ++ if (PRIVATE (a_this)->ref_count == 0) { ++ cr_tknzr_destroy (a_this); ++ return TRUE; ++ } ++ ++ return FALSE; ++} ++ ++enum CRStatus ++cr_tknzr_set_input (CRTknzr * a_this, CRInput * a_input) ++{ ++ g_return_val_if_fail (a_this && PRIVATE (a_this), CR_BAD_PARAM_ERROR); ++ ++ if (PRIVATE (a_this)->input) { ++ cr_input_unref (PRIVATE (a_this)->input); ++ } ++ ++ PRIVATE (a_this)->input = a_input; ++ ++ cr_input_ref (PRIVATE (a_this)->input); ++ ++ return CR_OK; ++} ++ ++enum CRStatus ++cr_tknzr_get_input (CRTknzr * a_this, CRInput ** a_input) ++{ ++ g_return_val_if_fail (a_this && PRIVATE (a_this), CR_BAD_PARAM_ERROR); ++ ++ *a_input = PRIVATE (a_this)->input; ++ ++ return CR_OK; ++} ++ ++/********************************* ++ *Tokenizer input handling routines ++ *********************************/ ++ ++/** ++ *Reads the next byte from the parser input stream. ++ *@param a_this the "this pointer" of the current instance of ++ *#CRParser. ++ *@param a_byte out parameter the place where to store the byte ++ *read. ++ *@return CR_OK upon successfull completion, an error ++ *code otherwise. ++ */ ++enum CRStatus ++cr_tknzr_read_byte (CRTknzr * a_this, guchar * a_byte) ++{ ++ g_return_val_if_fail (a_this && PRIVATE (a_this), CR_BAD_PARAM_ERROR); ++ ++ return cr_input_read_byte (PRIVATE (a_this)->input, a_byte); ++ ++} ++ ++/** ++ *Reads the next char from the parser input stream. ++ *@param a_this the current instance of #CRTknzr. ++ *@param a_char out parameter. The read char. ++ *@return CR_OK upon successfull completion, an error code ++ *otherwise. ++ */ ++enum CRStatus ++cr_tknzr_read_char (CRTknzr * a_this, guint32 * a_char) ++{ ++ g_return_val_if_fail (a_this && PRIVATE (a_this) ++ && PRIVATE (a_this)->input ++ && a_char, CR_BAD_PARAM_ERROR); ++ ++ if (PRIVATE (a_this)->token_cache) { ++ cr_input_set_cur_pos (PRIVATE (a_this)->input, ++ &PRIVATE (a_this)->prev_pos); ++ cr_token_destroy (PRIVATE (a_this)->token_cache); ++ PRIVATE (a_this)->token_cache = NULL; ++ } ++ ++ return cr_input_read_char (PRIVATE (a_this)->input, a_char); ++} ++ ++/** ++ *Peeks a char from the parser input stream. ++ *To "peek a char" means reads the next char without consuming it. ++ *Subsequent calls to this function return the same char. ++ *@param a_this the current instance of #CRTknzr. ++ *@param a_char out parameter. The peeked char uppon successfull completion. ++ *@return CR_OK upon successfull completion, an error code otherwise. ++ */ ++enum CRStatus ++cr_tknzr_peek_char (CRTknzr * a_this, guint32 * a_char) ++{ ++ g_return_val_if_fail (a_this && PRIVATE (a_this) ++ && PRIVATE (a_this)->input ++ && a_char, CR_BAD_PARAM_ERROR); ++ ++ if (PRIVATE (a_this)->token_cache) { ++ cr_input_set_cur_pos (PRIVATE (a_this)->input, ++ &PRIVATE (a_this)->prev_pos); ++ cr_token_destroy (PRIVATE (a_this)->token_cache); ++ PRIVATE (a_this)->token_cache = NULL; ++ } ++ ++ return cr_input_peek_char (PRIVATE (a_this)->input, a_char); ++} ++ ++/** ++ *Peeks a byte ahead at a given postion in the parser input stream. ++ *@param a_this the current instance of #CRTknzr. ++ *@param a_offset the offset of the peeked byte starting from the current ++ *byte in the parser input stream. ++ *@param a_byte out parameter. The peeked byte upon ++ *successfull completion. ++ *@return CR_OK upon successfull completion, an error code otherwise. ++ */ ++enum CRStatus ++cr_tknzr_peek_byte (CRTknzr * a_this, gulong a_offset, guchar * a_byte) ++{ ++ g_return_val_if_fail (a_this && PRIVATE (a_this) ++ && PRIVATE (a_this)->input && a_byte, ++ CR_BAD_PARAM_ERROR); ++ ++ if (PRIVATE (a_this)->token_cache) { ++ cr_input_set_cur_pos (PRIVATE (a_this)->input, ++ &PRIVATE (a_this)->prev_pos); ++ cr_token_destroy (PRIVATE (a_this)->token_cache); ++ PRIVATE (a_this)->token_cache = NULL; ++ } ++ ++ return cr_input_peek_byte (PRIVATE (a_this)->input, ++ CR_SEEK_CUR, a_offset, a_byte); ++} ++ ++/** ++ *Same as cr_tknzr_peek_byte() but this api returns the byte peeked. ++ *@param a_this the current instance of #CRTknzr. ++ *@param a_offset the offset of the peeked byte starting from the current ++ *byte in the parser input stream. ++ *@param a_eof out parameter. If not NULL, is set to TRUE if we reached end of ++ *file, FALE otherwise. If the caller sets it to NULL, this parameter ++ *is just ignored. ++ *@return the peeked byte. ++ */ ++guchar ++cr_tknzr_peek_byte2 (CRTknzr * a_this, gulong a_offset, gboolean * a_eof) ++{ ++ g_return_val_if_fail (a_this && PRIVATE (a_this) ++ && PRIVATE (a_this)->input, 0); ++ ++ return cr_input_peek_byte2 (PRIVATE (a_this)->input, a_offset, a_eof); ++} ++ ++/** ++ *Gets the number of bytes left in the topmost input stream ++ *associated to this parser. ++ *@param a_this the current instance of #CRTknzr ++ *@return the number of bytes left or -1 in case of error. ++ */ ++glong ++cr_tknzr_get_nb_bytes_left (CRTknzr * a_this) ++{ ++ g_return_val_if_fail (a_this && PRIVATE (a_this) ++ && PRIVATE (a_this)->input, CR_BAD_PARAM_ERROR); ++ ++ if (PRIVATE (a_this)->token_cache) { ++ cr_input_set_cur_pos (PRIVATE (a_this)->input, ++ &PRIVATE (a_this)->prev_pos); ++ cr_token_destroy (PRIVATE (a_this)->token_cache); ++ PRIVATE (a_this)->token_cache = NULL; ++ } ++ ++ return cr_input_get_nb_bytes_left (PRIVATE (a_this)->input); ++} ++ ++enum CRStatus ++cr_tknzr_get_cur_pos (CRTknzr * a_this, CRInputPos * a_pos) ++{ ++ g_return_val_if_fail (a_this && PRIVATE (a_this) ++ && PRIVATE (a_this)->input ++ && a_pos, CR_BAD_PARAM_ERROR); ++ ++ if (PRIVATE (a_this)->token_cache) { ++ cr_input_set_cur_pos (PRIVATE (a_this)->input, ++ &PRIVATE (a_this)->prev_pos); ++ cr_token_destroy (PRIVATE (a_this)->token_cache); ++ PRIVATE (a_this)->token_cache = NULL; ++ } ++ ++ return cr_input_get_cur_pos (PRIVATE (a_this)->input, a_pos); ++} ++ ++enum CRStatus ++cr_tknzr_get_parsing_location (CRTknzr *a_this, ++ CRParsingLocation *a_loc) ++{ ++ g_return_val_if_fail (a_this ++ && PRIVATE (a_this) ++ && a_loc, ++ CR_BAD_PARAM_ERROR) ; ++ ++ return cr_input_get_parsing_location ++ (PRIVATE (a_this)->input, a_loc) ; ++} ++ ++enum CRStatus ++cr_tknzr_get_cur_byte_addr (CRTknzr * a_this, guchar ** a_addr) ++{ ++ g_return_val_if_fail (a_this && PRIVATE (a_this) ++ && PRIVATE (a_this)->input, CR_BAD_PARAM_ERROR); ++ if (PRIVATE (a_this)->token_cache) { ++ cr_input_set_cur_pos (PRIVATE (a_this)->input, ++ &PRIVATE (a_this)->prev_pos); ++ cr_token_destroy (PRIVATE (a_this)->token_cache); ++ PRIVATE (a_this)->token_cache = NULL; ++ } ++ ++ return cr_input_get_cur_byte_addr (PRIVATE (a_this)->input, a_addr); ++} ++ ++enum CRStatus ++cr_tknzr_seek_index (CRTknzr * a_this, enum CRSeekPos a_origin, gint a_pos) ++{ ++ g_return_val_if_fail (a_this && PRIVATE (a_this) ++ && PRIVATE (a_this)->input, CR_BAD_PARAM_ERROR); ++ ++ if (PRIVATE (a_this)->token_cache) { ++ cr_input_set_cur_pos (PRIVATE (a_this)->input, ++ &PRIVATE (a_this)->prev_pos); ++ cr_token_destroy (PRIVATE (a_this)->token_cache); ++ PRIVATE (a_this)->token_cache = NULL; ++ } ++ ++ return cr_input_seek_index (PRIVATE (a_this)->input, a_origin, a_pos); ++} ++ ++enum CRStatus ++cr_tknzr_consume_chars (CRTknzr * a_this, guint32 a_char, glong * a_nb_char) ++{ ++ gulong consumed = *(gulong *) a_nb_char; ++ enum CRStatus status; ++ g_return_val_if_fail (a_this && PRIVATE (a_this) ++ && PRIVATE (a_this)->input, CR_BAD_PARAM_ERROR); ++ ++ if (PRIVATE (a_this)->token_cache) { ++ cr_input_set_cur_pos (PRIVATE (a_this)->input, ++ &PRIVATE (a_this)->prev_pos); ++ cr_token_destroy (PRIVATE (a_this)->token_cache); ++ PRIVATE (a_this)->token_cache = NULL; ++ } ++ ++ status = cr_input_consume_chars (PRIVATE (a_this)->input, ++ a_char, &consumed); ++ *a_nb_char = (glong) consumed; ++ return status; ++} ++ ++enum CRStatus ++cr_tknzr_set_cur_pos (CRTknzr * a_this, CRInputPos * a_pos) ++{ ++ g_return_val_if_fail (a_this && PRIVATE (a_this) ++ && PRIVATE (a_this)->input, CR_BAD_PARAM_ERROR); ++ ++ if (PRIVATE (a_this)->token_cache) { ++ cr_token_destroy (PRIVATE (a_this)->token_cache); ++ PRIVATE (a_this)->token_cache = NULL; ++ } ++ ++ return cr_input_set_cur_pos (PRIVATE (a_this)->input, a_pos); ++} ++ ++enum CRStatus ++cr_tknzr_unget_token (CRTknzr * a_this, CRToken * a_token) ++{ ++ g_return_val_if_fail (a_this && PRIVATE (a_this) ++ && PRIVATE (a_this)->token_cache == NULL, ++ CR_BAD_PARAM_ERROR); ++ ++ PRIVATE (a_this)->token_cache = a_token; ++ ++ return CR_OK; ++} ++ ++/** ++ *Returns the next token of the input stream. ++ *This method is really central. Each parsing ++ *method calls it. ++ *@param a_this the current tokenizer. ++ *@param a_tk out parameter. The returned token. ++ *for the sake of mem leak avoidance, *a_tk must ++ *be NULL. ++ *@param CR_OK upon successfull completion, an error code ++ *otherwise. ++ */ ++enum CRStatus ++cr_tknzr_get_next_token (CRTknzr * a_this, CRToken ** a_tk) ++{ ++ enum CRStatus status = CR_OK; ++ CRToken *token = NULL; ++ CRInputPos init_pos; ++ guint32 next_char = 0; ++ guchar next_bytes[4] = { 0 }; ++ gboolean reached_eof = FALSE; ++ CRInput *input = NULL; ++ CRString *str = NULL; ++ CRRgb *rgb = NULL; ++ CRParsingLocation location = {0} ; ++ ++ g_return_val_if_fail (a_this && PRIVATE (a_this) ++ && a_tk && *a_tk == NULL ++ && PRIVATE (a_this)->input, ++ CR_BAD_PARAM_ERROR); ++ ++ if (PRIVATE (a_this)->token_cache) { ++ *a_tk = PRIVATE (a_this)->token_cache; ++ PRIVATE (a_this)->token_cache = NULL; ++ return CR_OK; ++ } ++ ++ RECORD_INITIAL_POS (a_this, &init_pos); ++ ++ status = cr_input_get_end_of_file ++ (PRIVATE (a_this)->input, &reached_eof); ++ ENSURE_PARSING_COND (status == CR_OK); ++ ++ if (reached_eof == TRUE) { ++ status = CR_END_OF_INPUT_ERROR; ++ goto error; ++ } ++ ++ input = PRIVATE (a_this)->input; ++ ++ PEEK_NEXT_CHAR (a_this, &next_char); ++ token = cr_token_new (); ++ ENSURE_PARSING_COND (token); ++ ++ switch (next_char) { ++ case '@': ++ { ++ if (BYTE (input, 2, NULL) == 'f' ++ && BYTE (input, 3, NULL) == 'o' ++ && BYTE (input, 4, NULL) == 'n' ++ && BYTE (input, 5, NULL) == 't' ++ && BYTE (input, 6, NULL) == '-' ++ && BYTE (input, 7, NULL) == 'f' ++ && BYTE (input, 8, NULL) == 'a' ++ && BYTE (input, 9, NULL) == 'c' ++ && BYTE (input, 10, NULL) == 'e') { ++ SKIP_CHARS (a_this, 1); ++ cr_tknzr_get_parsing_location ++ (a_this, &location) ; ++ SKIP_CHARS (a_this, 9); ++ status = cr_token_set_font_face_sym (token); ++ CHECK_PARSING_STATUS (status, TRUE); ++ cr_parsing_location_copy (&token->location, ++ &location) ; ++ goto done; ++ } ++ ++ if (BYTE (input, 2, NULL) == 'c' ++ && BYTE (input, 3, NULL) == 'h' ++ && BYTE (input, 4, NULL) == 'a' ++ && BYTE (input, 5, NULL) == 'r' ++ && BYTE (input, 6, NULL) == 's' ++ && BYTE (input, 7, NULL) == 'e' ++ && BYTE (input, 8, NULL) == 't') { ++ SKIP_CHARS (a_this, 1); ++ cr_tknzr_get_parsing_location ++ (a_this, &location) ; ++ SKIP_CHARS (a_this, 7); ++ status = cr_token_set_charset_sym (token); ++ CHECK_PARSING_STATUS (status, TRUE); ++ cr_parsing_location_copy (&token->location, ++ &location) ; ++ goto done; ++ } ++ ++ if (BYTE (input, 2, NULL) == 'i' ++ && BYTE (input, 3, NULL) == 'm' ++ && BYTE (input, 4, NULL) == 'p' ++ && BYTE (input, 5, NULL) == 'o' ++ && BYTE (input, 6, NULL) == 'r' ++ && BYTE (input, 7, NULL) == 't') { ++ SKIP_CHARS (a_this, 1); ++ cr_tknzr_get_parsing_location ++ (a_this, &location) ; ++ SKIP_CHARS (a_this, 6); ++ status = cr_token_set_import_sym (token); ++ CHECK_PARSING_STATUS (status, TRUE); ++ cr_parsing_location_copy (&token->location, ++ &location) ; ++ goto done; ++ } ++ ++ if (BYTE (input, 2, NULL) == 'm' ++ && BYTE (input, 3, NULL) == 'e' ++ && BYTE (input, 4, NULL) == 'd' ++ && BYTE (input, 5, NULL) == 'i' ++ && BYTE (input, 6, NULL) == 'a') { ++ SKIP_CHARS (a_this, 1); ++ cr_tknzr_get_parsing_location (a_this, ++ &location) ; ++ SKIP_CHARS (a_this, 5); ++ status = cr_token_set_media_sym (token); ++ CHECK_PARSING_STATUS (status, TRUE); ++ cr_parsing_location_copy (&token->location, ++ &location) ; ++ goto done; ++ } ++ ++ if (BYTE (input, 2, NULL) == 'p' ++ && BYTE (input, 3, NULL) == 'a' ++ && BYTE (input, 4, NULL) == 'g' ++ && BYTE (input, 5, NULL) == 'e') { ++ SKIP_CHARS (a_this, 1); ++ cr_tknzr_get_parsing_location (a_this, ++ &location) ; ++ SKIP_CHARS (a_this, 4); ++ status = cr_token_set_page_sym (token); ++ CHECK_PARSING_STATUS (status, TRUE); ++ cr_parsing_location_copy (&token->location, ++ &location) ; ++ goto done; ++ } ++ status = cr_tknzr_parse_atkeyword (a_this, &str); ++ if (status == CR_OK) { ++ status = cr_token_set_atkeyword (token, str); ++ CHECK_PARSING_STATUS (status, TRUE); ++ if (str) { ++ cr_parsing_location_copy (&token->location, ++ &str->location) ; ++ } ++ goto done; ++ } ++ } ++ break; ++ ++ case 'u': ++ ++ if (BYTE (input, 2, NULL) == 'r' ++ && BYTE (input, 3, NULL) == 'l' ++ && BYTE (input, 4, NULL) == '(') { ++ CRString *str2 = NULL; ++ ++ status = cr_tknzr_parse_uri (a_this, &str2); ++ if (status == CR_OK) { ++ status = cr_token_set_uri (token, str2); ++ CHECK_PARSING_STATUS (status, TRUE); ++ if (str2) { ++ cr_parsing_location_copy (&token->location, ++ &str2->location) ; ++ } ++ goto done; ++ } ++ } ++ goto fallback; ++ break; ++ ++ case 'r': ++ if (BYTE (input, 2, NULL) == 'g' ++ && BYTE (input, 3, NULL) == 'b' ++ && BYTE (input, 4, NULL) == '(') { ++ status = cr_tknzr_parse_rgb (a_this, &rgb); ++ if (status == CR_OK && rgb) { ++ status = cr_token_set_rgb (token, rgb); ++ CHECK_PARSING_STATUS (status, TRUE); ++ if (rgb) { ++ cr_parsing_location_copy (&token->location, ++ &rgb->location) ; ++ } ++ rgb = NULL; ++ goto done; ++ } ++ ++ } ++ goto fallback; ++ break; ++ ++ case '<': ++ if (BYTE (input, 2, NULL) == '!' ++ && BYTE (input, 3, NULL) == '-' ++ && BYTE (input, 4, NULL) == '-') { ++ SKIP_CHARS (a_this, 1); ++ cr_tknzr_get_parsing_location (a_this, ++ &location) ; ++ SKIP_CHARS (a_this, 3); ++ status = cr_token_set_cdo (token); ++ CHECK_PARSING_STATUS (status, TRUE); ++ cr_parsing_location_copy (&token->location, ++ &location) ; ++ goto done; ++ } ++ break; ++ ++ case '-': ++ if (BYTE (input, 2, NULL) == '-' ++ && BYTE (input, 3, NULL) == '>') { ++ SKIP_CHARS (a_this, 1); ++ cr_tknzr_get_parsing_location (a_this, ++ &location) ; ++ SKIP_CHARS (a_this, 2); ++ status = cr_token_set_cdc (token); ++ CHECK_PARSING_STATUS (status, TRUE); ++ cr_parsing_location_copy (&token->location, ++ &location) ; ++ goto done; ++ } else { ++ status = cr_tknzr_parse_ident ++ (a_this, &str); ++ if (status == CR_OK) { ++ cr_token_set_ident ++ (token, str); ++ if (str) { ++ cr_parsing_location_copy (&token->location, ++ &str->location) ; ++ } ++ goto done; ++ } else { ++ goto parse_number; ++ } ++ } ++ break; ++ ++ case '~': ++ if (BYTE (input, 2, NULL) == '=') { ++ SKIP_CHARS (a_this, 1); ++ cr_tknzr_get_parsing_location (a_this, ++ &location) ; ++ SKIP_CHARS (a_this, 1); ++ status = cr_token_set_includes (token); ++ CHECK_PARSING_STATUS (status, TRUE); ++ cr_parsing_location_copy (&token->location, ++ &location) ; ++ goto done; ++ } ++ break; ++ ++ case '|': ++ if (BYTE (input, 2, NULL) == '=') { ++ SKIP_CHARS (a_this, 1); ++ cr_tknzr_get_parsing_location (a_this, ++ &location) ; ++ SKIP_CHARS (a_this, 1); ++ status = cr_token_set_dashmatch (token); ++ CHECK_PARSING_STATUS (status, TRUE); ++ cr_parsing_location_copy (&token->location, ++ &location) ; ++ goto done; ++ } ++ break; ++ ++ case '/': ++ if (BYTE (input, 2, NULL) == '*') { ++ status = cr_tknzr_parse_comment (a_this, &str); ++ ++ if (status == CR_OK) { ++ status = cr_token_set_comment (token, str); ++ str = NULL; ++ CHECK_PARSING_STATUS (status, TRUE); ++ if (str) { ++ cr_parsing_location_copy (&token->location, ++ &str->location) ; ++ } ++ goto done; ++ } ++ } ++ break ; ++ ++ case ';': ++ SKIP_CHARS (a_this, 1); ++ cr_tknzr_get_parsing_location (a_this, ++ &location) ; ++ status = cr_token_set_semicolon (token); ++ CHECK_PARSING_STATUS (status, TRUE); ++ cr_parsing_location_copy (&token->location, ++ &location) ; ++ goto done; ++ ++ case '{': ++ SKIP_CHARS (a_this, 1); ++ cr_tknzr_get_parsing_location (a_this, ++ &location) ; ++ status = cr_token_set_cbo (token); ++ CHECK_PARSING_STATUS (status, TRUE); ++ cr_tknzr_get_parsing_location (a_this, ++ &location) ; ++ goto done; ++ ++ case '}': ++ SKIP_CHARS (a_this, 1); ++ cr_tknzr_get_parsing_location (a_this, ++ &location) ; ++ status = cr_token_set_cbc (token); ++ CHECK_PARSING_STATUS (status, TRUE); ++ cr_parsing_location_copy (&token->location, ++ &location) ; ++ goto done; ++ ++ case '(': ++ SKIP_CHARS (a_this, 1); ++ cr_tknzr_get_parsing_location (a_this, ++ &location) ; ++ status = cr_token_set_po (token); ++ CHECK_PARSING_STATUS (status, TRUE); ++ cr_parsing_location_copy (&token->location, ++ &location) ; ++ goto done; ++ ++ case ')': ++ SKIP_CHARS (a_this, 1); ++ cr_tknzr_get_parsing_location (a_this, ++ &location) ; ++ status = cr_token_set_pc (token); ++ CHECK_PARSING_STATUS (status, TRUE); ++ cr_parsing_location_copy (&token->location, ++ &location) ; ++ goto done; ++ ++ case '[': ++ SKIP_CHARS (a_this, 1); ++ cr_tknzr_get_parsing_location (a_this, ++ &location) ; ++ status = cr_token_set_bo (token); ++ CHECK_PARSING_STATUS (status, TRUE); ++ cr_parsing_location_copy (&token->location, ++ &location) ; ++ goto done; ++ ++ case ']': ++ SKIP_CHARS (a_this, 1); ++ cr_tknzr_get_parsing_location (a_this, ++ &location) ; ++ status = cr_token_set_bc (token); ++ CHECK_PARSING_STATUS (status, TRUE); ++ cr_parsing_location_copy (&token->location, ++ &location) ; ++ goto done; ++ ++ case ' ': ++ case '\t': ++ case '\n': ++ case '\f': ++ case '\r': ++ { ++ guchar *start = NULL, ++ *end = NULL; ++ ++ status = cr_tknzr_parse_w (a_this, &start, ++ &end, &location); ++ if (status == CR_OK) { ++ status = cr_token_set_s (token); ++ CHECK_PARSING_STATUS (status, TRUE); ++ cr_tknzr_get_parsing_location (a_this, ++ &location) ; ++ goto done; ++ } ++ } ++ break; ++ ++ case '#': ++ { ++ status = cr_tknzr_parse_hash (a_this, &str); ++ if (status == CR_OK && str) { ++ status = cr_token_set_hash (token, str); ++ CHECK_PARSING_STATUS (status, TRUE); ++ if (str) { ++ cr_parsing_location_copy (&token->location, ++ &str->location) ; ++ } ++ str = NULL; ++ goto done; ++ } ++ } ++ break; ++ ++ case '\'': ++ case '"': ++ status = cr_tknzr_parse_string (a_this, &str); ++ if (status == CR_OK && str) { ++ status = cr_token_set_string (token, str); ++ CHECK_PARSING_STATUS (status, TRUE); ++ if (str) { ++ cr_parsing_location_copy (&token->location, ++ &str->location) ; ++ } ++ str = NULL; ++ goto done; ++ } ++ break; ++ ++ case '!': ++ status = cr_tknzr_parse_important (a_this, &location); ++ if (status == CR_OK) { ++ status = cr_token_set_important_sym (token); ++ CHECK_PARSING_STATUS (status, TRUE); ++ cr_parsing_location_copy (&token->location, ++ &location) ; ++ goto done; ++ } ++ break; ++ ++ case '0': ++ case '1': ++ case '2': ++ case '3': ++ case '4': ++ case '5': ++ case '6': ++ case '7': ++ case '8': ++ case '9': ++ case '.': ++ case '+': ++ /* '-' case is handled separately above for --> comments */ ++ parse_number: ++ { ++ CRNum *num = NULL; ++ ++ status = cr_tknzr_parse_num (a_this, &num); ++ if (status == CR_OK && num) { ++ next_bytes[0] = BYTE (input, 1, NULL); ++ next_bytes[1] = BYTE (input, 2, NULL); ++ next_bytes[2] = BYTE (input, 3, NULL); ++ next_bytes[3] = BYTE (input, 4, NULL); ++ ++ if (next_bytes[0] == 'e' ++ && next_bytes[1] == 'm') { ++ num->type = NUM_LENGTH_EM; ++ status = cr_token_set_ems (token, ++ num); ++ num = NULL; ++ SKIP_CHARS (a_this, 2); ++ } else if (next_bytes[0] == 'e' ++ && next_bytes[1] == 'x') { ++ num->type = NUM_LENGTH_EX; ++ status = cr_token_set_exs (token, ++ num); ++ num = NULL; ++ SKIP_CHARS (a_this, 2); ++ } else if (next_bytes[0] == 'p' ++ && next_bytes[1] == 'x') { ++ num->type = NUM_LENGTH_PX; ++ status = cr_token_set_length ++ (token, num, LENGTH_PX_ET); ++ num = NULL; ++ SKIP_CHARS (a_this, 2); ++ } else if (next_bytes[0] == 'c' ++ && next_bytes[1] == 'm') { ++ num->type = NUM_LENGTH_CM; ++ status = cr_token_set_length ++ (token, num, LENGTH_CM_ET); ++ num = NULL; ++ SKIP_CHARS (a_this, 2); ++ } else if (next_bytes[0] == 'm' ++ && next_bytes[1] == 'm') { ++ num->type = NUM_LENGTH_MM; ++ status = cr_token_set_length ++ (token, num, LENGTH_MM_ET); ++ num = NULL; ++ SKIP_CHARS (a_this, 2); ++ } else if (next_bytes[0] == 'i' ++ && next_bytes[1] == 'n') { ++ num->type = NUM_LENGTH_IN; ++ status = cr_token_set_length ++ (token, num, LENGTH_IN_ET); ++ num = NULL; ++ SKIP_CHARS (a_this, 2); ++ } else if (next_bytes[0] == 'p' ++ && next_bytes[1] == 't') { ++ num->type = NUM_LENGTH_PT; ++ status = cr_token_set_length ++ (token, num, LENGTH_PT_ET); ++ num = NULL; ++ SKIP_CHARS (a_this, 2); ++ } else if (next_bytes[0] == 'p' ++ && next_bytes[1] == 'c') { ++ num->type = NUM_LENGTH_PC; ++ status = cr_token_set_length ++ (token, num, LENGTH_PC_ET); ++ num = NULL; ++ SKIP_CHARS (a_this, 2); ++ } else if (next_bytes[0] == 'd' ++ && next_bytes[1] == 'e' ++ && next_bytes[2] == 'g') { ++ num->type = NUM_ANGLE_DEG; ++ status = cr_token_set_angle ++ (token, num, ANGLE_DEG_ET); ++ num = NULL; ++ SKIP_CHARS (a_this, 3); ++ } else if (next_bytes[0] == 'r' ++ && next_bytes[1] == 'a' ++ && next_bytes[2] == 'd') { ++ num->type = NUM_ANGLE_RAD; ++ status = cr_token_set_angle ++ (token, num, ANGLE_RAD_ET); ++ num = NULL; ++ SKIP_CHARS (a_this, 3); ++ } else if (next_bytes[0] == 'g' ++ && next_bytes[1] == 'r' ++ && next_bytes[2] == 'a' ++ && next_bytes[3] == 'd') { ++ num->type = NUM_ANGLE_GRAD; ++ status = cr_token_set_angle ++ (token, num, ANGLE_GRAD_ET); ++ num = NULL; ++ SKIP_CHARS (a_this, 4); ++ } else if (next_bytes[0] == 'm' ++ && next_bytes[1] == 's') { ++ num->type = NUM_TIME_MS; ++ status = cr_token_set_time ++ (token, num, TIME_MS_ET); ++ num = NULL; ++ SKIP_CHARS (a_this, 2); ++ } else if (next_bytes[0] == 's') { ++ num->type = NUM_TIME_S; ++ status = cr_token_set_time ++ (token, num, TIME_S_ET); ++ num = NULL; ++ SKIP_CHARS (a_this, 1); ++ } else if (next_bytes[0] == 'H' ++ && next_bytes[1] == 'z') { ++ num->type = NUM_FREQ_HZ; ++ status = cr_token_set_freq ++ (token, num, FREQ_HZ_ET); ++ num = NULL; ++ SKIP_CHARS (a_this, 2); ++ } else if (next_bytes[0] == 'k' ++ && next_bytes[1] == 'H' ++ && next_bytes[2] == 'z') { ++ num->type = NUM_FREQ_KHZ; ++ status = cr_token_set_freq ++ (token, num, FREQ_KHZ_ET); ++ num = NULL; ++ SKIP_CHARS (a_this, 3); ++ } else if (next_bytes[0] == '%') { ++ num->type = NUM_PERCENTAGE; ++ status = cr_token_set_percentage ++ (token, num); ++ num = NULL; ++ SKIP_CHARS (a_this, 1); ++ } else { ++ status = cr_tknzr_parse_ident (a_this, ++ &str); ++ if (status == CR_OK && str) { ++ num->type = NUM_UNKNOWN_TYPE; ++ status = cr_token_set_dimen ++ (token, num, str); ++ num = NULL; ++ CHECK_PARSING_STATUS (status, ++ TRUE); ++ str = NULL; ++ } else { ++ status = cr_token_set_number ++ (token, num); ++ num = NULL; ++ CHECK_PARSING_STATUS (status, CR_OK); ++ str = NULL; ++ } ++ } ++ if (token && token->u.num) { ++ cr_parsing_location_copy (&token->location, ++ &token->u.num->location) ; ++ } else { ++ status = CR_ERROR ; ++ } ++ goto done ; ++ } ++ } ++ break; ++ ++ default: ++ fallback: ++ /*process the fallback cases here */ ++ ++ if (next_char == '\\' ++ || (cr_utils_is_nonascii (next_bytes[0]) == TRUE) ++ || ((next_char >= 'a') && (next_char <= 'z')) ++ || ((next_char >= 'A') && (next_char <= 'Z'))) { ++ status = cr_tknzr_parse_ident (a_this, &str); ++ if (status == CR_OK && str) { ++ guint32 next_c = 0; ++ ++ status = cr_input_peek_char ++ (PRIVATE (a_this)->input, &next_c); ++ ++ if (status == CR_OK && next_c == '(') { ++ ++ SKIP_CHARS (a_this, 1); ++ status = cr_token_set_function ++ (token, str); ++ CHECK_PARSING_STATUS (status, TRUE); ++ /*ownership is transfered ++ *to token by cr_token_set_function. ++ */ ++ if (str) { ++ cr_parsing_location_copy (&token->location, ++ &str->location) ; ++ } ++ str = NULL; ++ } else { ++ status = cr_token_set_ident (token, ++ str); ++ CHECK_PARSING_STATUS (status, TRUE); ++ if (str) { ++ cr_parsing_location_copy (&token->location, ++ &str->location) ; ++ } ++ str = NULL; ++ } ++ goto done; ++ } else { ++ if (str) { ++ cr_string_destroy (str); ++ str = NULL; ++ } ++ } ++ } ++ break; ++ } ++ ++ READ_NEXT_CHAR (a_this, &next_char); ++ cr_tknzr_get_parsing_location (a_this, ++ &location) ; ++ status = cr_token_set_delim (token, next_char); ++ CHECK_PARSING_STATUS (status, TRUE); ++ cr_parsing_location_copy (&token->location, ++ &location) ; ++ done: ++ ++ if (status == CR_OK && token) { ++ *a_tk = token; ++ /* ++ *store the previous position input stream pos. ++ */ ++ memmove (&PRIVATE (a_this)->prev_pos, ++ &init_pos, sizeof (CRInputPos)); ++ return CR_OK; ++ } ++ ++ error: ++ if (token) { ++ cr_token_destroy (token); ++ token = NULL; ++ } ++ ++ if (str) { ++ cr_string_destroy (str); ++ str = NULL; ++ } ++ cr_tknzr_set_cur_pos (a_this, &init_pos); ++ return status; ++ ++} ++ ++enum CRStatus ++cr_tknzr_parse_token (CRTknzr * a_this, enum CRTokenType a_type, ++ enum CRTokenExtraType a_et, gpointer a_res, ++ gpointer a_extra_res) ++{ ++ enum CRStatus status = CR_OK; ++ CRToken *token = NULL; ++ ++ g_return_val_if_fail (a_this && PRIVATE (a_this) ++ && PRIVATE (a_this)->input ++ && a_res, CR_BAD_PARAM_ERROR); ++ ++ status = cr_tknzr_get_next_token (a_this, &token); ++ if (status != CR_OK) ++ return status; ++ if (token == NULL) ++ return CR_PARSING_ERROR; ++ ++ if (token->type == a_type) { ++ switch (a_type) { ++ case NO_TK: ++ case S_TK: ++ case CDO_TK: ++ case CDC_TK: ++ case INCLUDES_TK: ++ case DASHMATCH_TK: ++ case IMPORT_SYM_TK: ++ case PAGE_SYM_TK: ++ case MEDIA_SYM_TK: ++ case FONT_FACE_SYM_TK: ++ case CHARSET_SYM_TK: ++ case IMPORTANT_SYM_TK: ++ status = CR_OK; ++ break; ++ ++ case STRING_TK: ++ case IDENT_TK: ++ case HASH_TK: ++ case ATKEYWORD_TK: ++ case FUNCTION_TK: ++ case COMMENT_TK: ++ case URI_TK: ++ *((CRString **) a_res) = token->u.str; ++ token->u.str = NULL; ++ status = CR_OK; ++ break; ++ ++ case EMS_TK: ++ case EXS_TK: ++ case PERCENTAGE_TK: ++ case NUMBER_TK: ++ *((CRNum **) a_res) = token->u.num; ++ token->u.num = NULL; ++ status = CR_OK; ++ break; ++ ++ case LENGTH_TK: ++ case ANGLE_TK: ++ case TIME_TK: ++ case FREQ_TK: ++ if (token->extra_type == a_et) { ++ *((CRNum **) a_res) = token->u.num; ++ token->u.num = NULL; ++ status = CR_OK; ++ } ++ break; ++ ++ case DIMEN_TK: ++ *((CRNum **) a_res) = token->u.num; ++ if (a_extra_res == NULL) { ++ status = CR_BAD_PARAM_ERROR; ++ goto error; ++ } ++ ++ *((CRString **) a_extra_res) = token->dimen; ++ token->u.num = NULL; ++ token->dimen = NULL; ++ status = CR_OK; ++ break; ++ ++ case DELIM_TK: ++ *((guint32 *) a_res) = token->u.unichar; ++ status = CR_OK; ++ break; ++ ++ case UNICODERANGE_TK: ++ default: ++ status = CR_PARSING_ERROR; ++ break; ++ } ++ ++ cr_token_destroy (token); ++ token = NULL; ++ } else { ++ cr_tknzr_unget_token (a_this, token); ++ token = NULL; ++ status = CR_PARSING_ERROR; ++ } ++ ++ return status; ++ ++ error: ++ ++ if (token) { ++ cr_tknzr_unget_token (a_this, token); ++ token = NULL; ++ } ++ ++ return status; ++} ++ ++void ++cr_tknzr_destroy (CRTknzr * a_this) ++{ ++ g_return_if_fail (a_this); ++ ++ if (PRIVATE (a_this) && PRIVATE (a_this)->input) { ++ if (cr_input_unref (PRIVATE (a_this)->input) ++ == TRUE) { ++ PRIVATE (a_this)->input = NULL; ++ } ++ } ++ ++ if (PRIVATE (a_this)->token_cache) { ++ cr_token_destroy (PRIVATE (a_this)->token_cache); ++ PRIVATE (a_this)->token_cache = NULL; ++ } ++ ++ if (PRIVATE (a_this)) { ++ g_free (PRIVATE (a_this)); ++ PRIVATE (a_this) = NULL; ++ } ++ ++ g_free (a_this); ++} +diff --git a/src/st/croco/cr-tknzr.h b/src/st/croco/cr-tknzr.h +new file mode 100644 +index 000000000..13985b30e +--- /dev/null ++++ b/src/st/croco/cr-tknzr.h +@@ -0,0 +1,115 @@ ++/* -*- Mode: C; indent-tabs-mode:nil; c-basic-offset: 8-*- */ ++ ++/* ++ * This file is part of The Croco Library ++ * ++ * 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 ++ * See COPYRIGHTS file for coypyright information. ++ */ ++ ++/** ++ *@file ++ *The declaration of the #CRTknzr (tokenizer) ++ *class. ++ */ ++ ++#ifndef __CR_TKNZR_H__ ++#define __CR_TKNZR_H__ ++ ++#include "cr-utils.h" ++#include "cr-input.h" ++#include "cr-token.h" ++ ++G_BEGIN_DECLS ++ ++ ++typedef struct _CRTknzr CRTknzr ; ++typedef struct _CRTknzrPriv CRTknzrPriv ; ++ ++/** ++ *The tokenizer is the class that knows ++ *about all the css token. Its main job is ++ *to return the next token found in the character ++ *input stream. ++ */ ++struct _CRTknzr ++{ ++ /*the private data of the tokenizer.*/ ++ CRTknzrPriv *priv ; ++} ; ++ ++CRTknzr * cr_tknzr_new (CRInput *a_input) ; ++ ++CRTknzr * cr_tknzr_new_from_uri (const guchar *a_file_uri, ++ enum CREncoding a_enc) ; ++ ++CRTknzr * cr_tknzr_new_from_buf (guchar *a_buf, gulong a_len, ++ enum CREncoding a_enc, ++ gboolean a_free_at_destroy) ; ++ ++gboolean cr_tknzr_unref (CRTknzr *a_this) ; ++ ++void cr_tknzr_ref (CRTknzr *a_this) ; ++ ++enum CRStatus cr_tknzr_read_byte (CRTknzr *a_this, guchar *a_byte) ; ++ ++enum CRStatus cr_tknzr_read_char (CRTknzr *a_this, guint32 *a_char); ++ ++enum CRStatus cr_tknzr_peek_char (CRTknzr *a_this, guint32 *a_char) ; ++ ++enum CRStatus cr_tknzr_peek_byte (CRTknzr *a_this, gulong a_offset, ++ guchar *a_byte) ; ++ ++guchar cr_tknzr_peek_byte2 (CRTknzr *a_this, gulong a_offset, ++ gboolean *a_eof) ; ++ ++enum CRStatus cr_tknzr_set_cur_pos (CRTknzr *a_this, CRInputPos *a_pos) ; ++ ++glong cr_tknzr_get_nb_bytes_left (CRTknzr *a_this) ; ++ ++enum CRStatus cr_tknzr_get_cur_pos (CRTknzr *a_this, CRInputPos *a_pos) ; ++ ++enum CRStatus cr_tknzr_get_parsing_location (CRTknzr *a_this, ++ CRParsingLocation *a_loc) ; ++ ++enum CRStatus cr_tknzr_seek_index (CRTknzr *a_this, ++ enum CRSeekPos a_origin, ++ gint a_pos) ; ++ ++enum CRStatus cr_tknzr_get_cur_byte_addr (CRTknzr *a_this, guchar **a_addr) ; ++ ++ ++enum CRStatus cr_tknzr_consume_chars (CRTknzr *a_this, guint32 a_char, ++ glong *a_nb_char) ; ++ ++enum CRStatus cr_tknzr_get_next_token (CRTknzr *a_this, CRToken ** a_tk) ; ++ ++enum CRStatus cr_tknzr_unget_token (CRTknzr *a_this, CRToken *a_token) ; ++ ++ ++enum CRStatus cr_tknzr_parse_token (CRTknzr *a_this, enum CRTokenType a_type, ++ enum CRTokenExtraType a_et, gpointer a_res, ++ gpointer a_extra_res) ; ++enum CRStatus cr_tknzr_set_input (CRTknzr *a_this, CRInput *a_input) ; ++ ++enum CRStatus cr_tknzr_get_input (CRTknzr *a_this, CRInput **a_input) ; ++ ++void cr_tknzr_destroy (CRTknzr *a_this) ; ++ ++G_END_DECLS ++ ++#endif /*__CR_TKZNR_H__*/ +diff --git a/src/st/croco/cr-token.c b/src/st/croco/cr-token.c +new file mode 100644 +index 000000000..e240ab8f1 +--- /dev/null ++++ b/src/st/croco/cr-token.c +@@ -0,0 +1,636 @@ ++/* -*- Mode: C; indent-tabs-mode:nil; c-basic-offset: 8-*- */ ++ ++/* ++ * This file is part of The Croco Library ++ * ++ * 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 ++ * see COPYRIGHTS file for copyright information. ++ */ ++ ++/** ++ *@file ++ *The definition of the #CRToken class. ++ *Abstracts a css2 token. ++ */ ++#include ++#include "cr-token.h" ++ ++/* ++ *TODO: write a CRToken::to_string() method. ++ */ ++ ++/** ++ *Frees the attributes of the current instance ++ *of #CRtoken. ++ *@param a_this the current instance of #CRToken. ++ */ ++static void ++cr_token_clear (CRToken * a_this) ++{ ++ g_return_if_fail (a_this); ++ ++ switch (a_this->type) { ++ case S_TK: ++ case CDO_TK: ++ case CDC_TK: ++ case INCLUDES_TK: ++ case DASHMATCH_TK: ++ case PAGE_SYM_TK: ++ case MEDIA_SYM_TK: ++ case FONT_FACE_SYM_TK: ++ case CHARSET_SYM_TK: ++ case IMPORT_SYM_TK: ++ case IMPORTANT_SYM_TK: ++ case SEMICOLON_TK: ++ case NO_TK: ++ case DELIM_TK: ++ case CBO_TK: ++ case CBC_TK: ++ case BO_TK: ++ case BC_TK: ++ break; ++ ++ case STRING_TK: ++ case IDENT_TK: ++ case HASH_TK: ++ case URI_TK: ++ case FUNCTION_TK: ++ case COMMENT_TK: ++ case ATKEYWORD_TK: ++ if (a_this->u.str) { ++ cr_string_destroy (a_this->u.str); ++ a_this->u.str = NULL; ++ } ++ break; ++ ++ case EMS_TK: ++ case EXS_TK: ++ case LENGTH_TK: ++ case ANGLE_TK: ++ case TIME_TK: ++ case FREQ_TK: ++ case PERCENTAGE_TK: ++ case NUMBER_TK: ++ case PO_TK: ++ case PC_TK: ++ if (a_this->u.num) { ++ cr_num_destroy (a_this->u.num); ++ a_this->u.num = NULL; ++ } ++ break; ++ ++ case DIMEN_TK: ++ if (a_this->u.num) { ++ cr_num_destroy (a_this->u.num); ++ a_this->u.num = NULL; ++ } ++ ++ if (a_this->dimen) { ++ cr_string_destroy (a_this->dimen); ++ a_this->dimen = NULL; ++ } ++ ++ break; ++ ++ case RGB_TK: ++ if (a_this->u.rgb) { ++ cr_rgb_destroy (a_this->u.rgb) ; ++ a_this->u.rgb = NULL ; ++ } ++ break ; ++ ++ case UNICODERANGE_TK: ++ /*not supported yet. */ ++ break; ++ ++ default: ++ cr_utils_trace_info ("I don't know how to clear this token\n") ; ++ break; ++ } ++ ++ a_this->type = NO_TK; ++} ++ ++/** ++ *Default constructor of ++ *the #CRToken class. ++ *@return the newly built instance of #CRToken. ++ */ ++CRToken * ++cr_token_new (void) ++{ ++ CRToken *result = NULL; ++ ++ result = g_try_malloc (sizeof (CRToken)); ++ ++ if (result == NULL) { ++ cr_utils_trace_info ("Out of memory"); ++ return NULL; ++ } ++ ++ memset (result, 0, sizeof (CRToken)); ++ ++ return result; ++} ++ ++/** ++ *Sets the type of curren instance of ++ *#CRToken to 'S_TK' (S in the css2 spec) ++ *@param a_this the current instance of #CRToken. ++ *@return CR_OK upon successfull completion, an error ++ *code otherwise. ++ */ ++enum CRStatus ++cr_token_set_s (CRToken * a_this) ++{ ++ g_return_val_if_fail (a_this, CR_BAD_PARAM_ERROR); ++ ++ cr_token_clear (a_this); ++ ++ a_this->type = S_TK; ++ ++ return CR_OK; ++} ++ ++/** ++ *Sets the type of the current instance of ++ *#CRToken to 'CDO_TK' (CDO as said by the css2 spec) ++ *@param a_this the current instance of #CRToken. ++ *@return CR_OK upon successfull completion, an error ++ *code otherwise. ++ */ ++enum CRStatus ++cr_token_set_cdo (CRToken * a_this) ++{ ++ g_return_val_if_fail (a_this, CR_BAD_PARAM_ERROR); ++ ++ cr_token_clear (a_this); ++ ++ a_this->type = CDO_TK; ++ ++ return CR_OK; ++} ++ ++/** ++ *Sets the type of the current token to ++ *CDC_TK (CDC as said by the css2 spec). ++ *@param a_this the current instance of #CRToken. ++ *@return CR_OK upon successfull completion, an error ++ *code otherwise. ++ */ ++enum CRStatus ++cr_token_set_cdc (CRToken * a_this) ++{ ++ g_return_val_if_fail (a_this, CR_BAD_PARAM_ERROR); ++ ++ cr_token_clear (a_this); ++ ++ a_this->type = CDC_TK; ++ ++ return CR_OK; ++} ++ ++/** ++ *Sets the type of the current instance of ++ *#CRToken to INCLUDES_TK (INCLUDES as said by the css2 spec). ++ *@param a_this the current instance of #CRToken. ++ *@return CR_OK upon successfull completion, an error ++ *code otherwise. ++ */ ++enum CRStatus ++cr_token_set_includes (CRToken * a_this) ++{ ++ g_return_val_if_fail (a_this, CR_BAD_PARAM_ERROR); ++ ++ cr_token_clear (a_this); ++ ++ a_this->type = INCLUDES_TK; ++ ++ return CR_OK; ++} ++ ++/** ++ *Sets the type of the current instance of ++ *#CRToken to DASHMATCH_TK (DASHMATCH as said by the css2 spec). ++ *@param a_this the current instance of #CRToken. ++ *@return CR_OK upon successfull completion, an error ++ *code otherwise. ++ */ ++enum CRStatus ++cr_token_set_dashmatch (CRToken * a_this) ++{ ++ g_return_val_if_fail (a_this, CR_BAD_PARAM_ERROR); ++ ++ cr_token_clear (a_this); ++ ++ a_this->type = DASHMATCH_TK; ++ ++ return CR_OK; ++} ++ ++enum CRStatus ++cr_token_set_comment (CRToken * a_this, CRString * a_str) ++{ ++ g_return_val_if_fail (a_this, CR_BAD_PARAM_ERROR); ++ ++ cr_token_clear (a_this); ++ a_this->type = COMMENT_TK; ++ a_this->u.str = a_str ; ++ return CR_OK; ++} ++ ++enum CRStatus ++cr_token_set_string (CRToken * a_this, CRString * a_str) ++{ ++ g_return_val_if_fail (a_this, CR_BAD_PARAM_ERROR); ++ ++ cr_token_clear (a_this); ++ ++ a_this->type = STRING_TK; ++ ++ a_this->u.str = a_str ; ++ ++ return CR_OK; ++} ++ ++enum CRStatus ++cr_token_set_ident (CRToken * a_this, CRString * a_ident) ++{ ++ g_return_val_if_fail (a_this, CR_BAD_PARAM_ERROR); ++ ++ cr_token_clear (a_this); ++ a_this->type = IDENT_TK; ++ a_this->u.str = a_ident; ++ return CR_OK; ++} ++ ++ ++enum CRStatus ++cr_token_set_function (CRToken * a_this, CRString * a_fun_name) ++{ ++ g_return_val_if_fail (a_this, ++ CR_BAD_PARAM_ERROR); ++ ++ cr_token_clear (a_this); ++ a_this->type = FUNCTION_TK; ++ a_this->u.str = a_fun_name; ++ return CR_OK; ++} ++ ++enum CRStatus ++cr_token_set_hash (CRToken * a_this, CRString * a_hash) ++{ ++ g_return_val_if_fail (a_this, CR_BAD_PARAM_ERROR); ++ ++ cr_token_clear (a_this); ++ a_this->type = HASH_TK; ++ a_this->u.str = a_hash; ++ ++ return CR_OK; ++} ++ ++enum CRStatus ++cr_token_set_rgb (CRToken * a_this, CRRgb * a_rgb) ++{ ++ g_return_val_if_fail (a_this, CR_BAD_PARAM_ERROR); ++ ++ cr_token_clear (a_this); ++ a_this->type = RGB_TK; ++ a_this->u.rgb = a_rgb; ++ ++ return CR_OK; ++} ++ ++enum CRStatus ++cr_token_set_import_sym (CRToken * a_this) ++{ ++ g_return_val_if_fail (a_this, CR_BAD_PARAM_ERROR); ++ ++ cr_token_clear (a_this); ++ ++ a_this->type = IMPORT_SYM_TK; ++ ++ return CR_OK; ++} ++ ++enum CRStatus ++cr_token_set_page_sym (CRToken * a_this) ++{ ++ g_return_val_if_fail (a_this, CR_BAD_PARAM_ERROR); ++ ++ cr_token_clear (a_this); ++ ++ a_this->type = PAGE_SYM_TK; ++ ++ return CR_OK; ++} ++ ++enum CRStatus ++cr_token_set_media_sym (CRToken * a_this) ++{ ++ g_return_val_if_fail (a_this, CR_BAD_PARAM_ERROR); ++ ++ cr_token_clear (a_this); ++ ++ a_this->type = MEDIA_SYM_TK; ++ ++ return CR_OK; ++} ++ ++enum CRStatus ++cr_token_set_font_face_sym (CRToken * a_this) ++{ ++ g_return_val_if_fail (a_this, CR_BAD_PARAM_ERROR); ++ ++ cr_token_clear (a_this); ++ a_this->type = FONT_FACE_SYM_TK; ++ ++ return CR_OK; ++} ++ ++enum CRStatus ++cr_token_set_charset_sym (CRToken * a_this) ++{ ++ g_return_val_if_fail (a_this, CR_BAD_PARAM_ERROR); ++ ++ cr_token_clear (a_this); ++ a_this->type = CHARSET_SYM_TK; ++ ++ return CR_OK; ++} ++ ++enum CRStatus ++cr_token_set_atkeyword (CRToken * a_this, CRString * a_atname) ++{ ++ g_return_val_if_fail (a_this, CR_BAD_PARAM_ERROR); ++ ++ cr_token_clear (a_this); ++ a_this->type = ATKEYWORD_TK; ++ a_this->u.str = a_atname; ++ return CR_OK; ++} ++ ++enum CRStatus ++cr_token_set_important_sym (CRToken * a_this) ++{ ++ g_return_val_if_fail (a_this, CR_BAD_PARAM_ERROR); ++ cr_token_clear (a_this); ++ a_this->type = IMPORTANT_SYM_TK; ++ return CR_OK; ++} ++ ++enum CRStatus ++cr_token_set_ems (CRToken * a_this, CRNum * a_num) ++{ ++ g_return_val_if_fail (a_this, CR_BAD_PARAM_ERROR); ++ cr_token_clear (a_this); ++ a_this->type = EMS_TK; ++ a_this->u.num = a_num; ++ return CR_OK; ++} ++ ++enum CRStatus ++cr_token_set_exs (CRToken * a_this, CRNum * a_num) ++{ ++ g_return_val_if_fail (a_this, CR_BAD_PARAM_ERROR); ++ cr_token_clear (a_this); ++ a_this->type = EXS_TK; ++ a_this->u.num = a_num; ++ return CR_OK; ++} ++ ++enum CRStatus ++cr_token_set_length (CRToken * a_this, CRNum * a_num, ++ enum CRTokenExtraType a_et) ++{ ++ g_return_val_if_fail (a_this, CR_BAD_PARAM_ERROR); ++ ++ cr_token_clear (a_this); ++ ++ a_this->type = LENGTH_TK; ++ a_this->extra_type = a_et; ++ a_this->u.num = a_num; ++ ++ return CR_OK; ++} ++ ++enum CRStatus ++cr_token_set_angle (CRToken * a_this, CRNum * a_num, ++ enum CRTokenExtraType a_et) ++{ ++ g_return_val_if_fail (a_this, CR_BAD_PARAM_ERROR); ++ ++ cr_token_clear (a_this); ++ ++ a_this->type = ANGLE_TK; ++ a_this->extra_type = a_et; ++ a_this->u.num = a_num; ++ ++ return CR_OK; ++} ++ ++enum CRStatus ++cr_token_set_time (CRToken * a_this, CRNum * a_num, ++ enum CRTokenExtraType a_et) ++{ ++ g_return_val_if_fail (a_this, CR_BAD_PARAM_ERROR); ++ ++ cr_token_clear (a_this); ++ ++ a_this->type = TIME_TK; ++ a_this->extra_type = a_et; ++ a_this->u.num = a_num; ++ ++ return CR_OK; ++} ++ ++enum CRStatus ++cr_token_set_freq (CRToken * a_this, CRNum * a_num, ++ enum CRTokenExtraType a_et) ++{ ++ g_return_val_if_fail (a_this, CR_BAD_PARAM_ERROR); ++ ++ cr_token_clear (a_this); ++ ++ a_this->type = FREQ_TK; ++ a_this->extra_type = a_et; ++ a_this->u.num = a_num; ++ ++ return CR_OK; ++} ++ ++enum CRStatus ++cr_token_set_dimen (CRToken * a_this, CRNum * a_num, ++ CRString * a_dim) ++{ ++ g_return_val_if_fail (a_this, CR_BAD_PARAM_ERROR); ++ cr_token_clear (a_this); ++ a_this->type = DIMEN_TK; ++ a_this->u.num = a_num; ++ a_this->dimen = a_dim; ++ return CR_OK; ++ ++} ++ ++enum CRStatus ++cr_token_set_percentage (CRToken * a_this, CRNum * a_num) ++{ ++ g_return_val_if_fail (a_this, CR_BAD_PARAM_ERROR); ++ ++ cr_token_clear (a_this); ++ ++ a_this->type = PERCENTAGE_TK; ++ a_this->u.num = a_num; ++ ++ return CR_OK; ++} ++ ++enum CRStatus ++cr_token_set_number (CRToken * a_this, CRNum * a_num) ++{ ++ g_return_val_if_fail (a_this, CR_BAD_PARAM_ERROR); ++ ++ cr_token_clear (a_this); ++ ++ a_this->type = NUMBER_TK; ++ a_this->u.num = a_num; ++ return CR_OK; ++} ++ ++enum CRStatus ++cr_token_set_uri (CRToken * a_this, CRString * a_uri) ++{ ++ g_return_val_if_fail (a_this, CR_BAD_PARAM_ERROR); ++ ++ cr_token_clear (a_this); ++ ++ a_this->type = URI_TK; ++ a_this->u.str = a_uri; ++ ++ return CR_OK; ++} ++ ++enum CRStatus ++cr_token_set_delim (CRToken * a_this, guint32 a_char) ++{ ++ g_return_val_if_fail (a_this, CR_BAD_PARAM_ERROR); ++ ++ cr_token_clear (a_this); ++ ++ a_this->type = DELIM_TK; ++ a_this->u.unichar = a_char; ++ ++ return CR_OK; ++} ++ ++enum CRStatus ++cr_token_set_semicolon (CRToken * a_this) ++{ ++ g_return_val_if_fail (a_this, CR_BAD_PARAM_ERROR); ++ ++ cr_token_clear (a_this); ++ ++ a_this->type = SEMICOLON_TK; ++ ++ return CR_OK; ++} ++ ++enum CRStatus ++cr_token_set_cbo (CRToken * a_this) ++{ ++ g_return_val_if_fail (a_this, CR_BAD_PARAM_ERROR); ++ ++ cr_token_clear (a_this); ++ ++ a_this->type = CBO_TK; ++ ++ return CR_OK; ++} ++ ++enum CRStatus ++cr_token_set_cbc (CRToken * a_this) ++{ ++ g_return_val_if_fail (a_this, CR_BAD_PARAM_ERROR); ++ ++ cr_token_clear (a_this); ++ ++ a_this->type = CBC_TK; ++ ++ return CR_OK; ++} ++ ++enum CRStatus ++cr_token_set_po (CRToken * a_this) ++{ ++ g_return_val_if_fail (a_this, CR_BAD_PARAM_ERROR); ++ ++ cr_token_clear (a_this); ++ ++ a_this->type = PO_TK; ++ ++ return CR_OK; ++} ++ ++enum CRStatus ++cr_token_set_pc (CRToken * a_this) ++{ ++ g_return_val_if_fail (a_this, CR_BAD_PARAM_ERROR); ++ ++ cr_token_clear (a_this); ++ ++ a_this->type = PC_TK; ++ ++ return CR_OK; ++} ++ ++enum CRStatus ++cr_token_set_bo (CRToken * a_this) ++{ ++ g_return_val_if_fail (a_this, CR_BAD_PARAM_ERROR); ++ ++ cr_token_clear (a_this); ++ ++ a_this->type = BO_TK; ++ ++ return CR_OK; ++} ++ ++enum CRStatus ++cr_token_set_bc (CRToken * a_this) ++{ ++ g_return_val_if_fail (a_this, CR_BAD_PARAM_ERROR); ++ ++ cr_token_clear (a_this); ++ ++ a_this->type = BC_TK; ++ ++ return CR_OK; ++} ++ ++/** ++ *The destructor of the #CRToken class. ++ *@param a_this the current instance of #CRToken. ++ */ ++void ++cr_token_destroy (CRToken * a_this) ++{ ++ g_return_if_fail (a_this); ++ ++ cr_token_clear (a_this); ++ ++ g_free (a_this); ++} +diff --git a/src/st/croco/cr-token.h b/src/st/croco/cr-token.h +new file mode 100644 +index 000000000..f1257b7a8 +--- /dev/null ++++ b/src/st/croco/cr-token.h +@@ -0,0 +1,212 @@ ++/* -*- Mode: C; indent-tabs-mode:nil; c-basic-offset: 8-*- */ ++ ++/* ++ * This file is part of The Croco Library ++ * ++ * 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 ++ * See COPYRIGHTS file for copyright information. ++ */ ++ ++#ifndef __CR_TOKEN_H__ ++#define __CR_TOKEN_H__ ++ ++#include "cr-utils.h" ++#include "cr-input.h" ++#include "cr-num.h" ++#include "cr-rgb.h" ++#include "cr-string.h" ++#include "cr-parsing-location.h" ++ ++G_BEGIN_DECLS ++ ++enum CRTokenType ++{ ++ NO_TK, ++ S_TK, ++ CDO_TK, ++ CDC_TK, ++ INCLUDES_TK, ++ DASHMATCH_TK, ++ COMMENT_TK, ++ STRING_TK, ++ IDENT_TK, ++ HASH_TK, ++ IMPORT_SYM_TK, ++ PAGE_SYM_TK, ++ MEDIA_SYM_TK, ++ FONT_FACE_SYM_TK, ++ CHARSET_SYM_TK, ++ ATKEYWORD_TK, ++ IMPORTANT_SYM_TK, ++ EMS_TK, ++ EXS_TK, ++ LENGTH_TK, ++ ANGLE_TK, ++ TIME_TK, ++ FREQ_TK, ++ DIMEN_TK, ++ PERCENTAGE_TK, ++ NUMBER_TK, ++ RGB_TK, ++ URI_TK, ++ FUNCTION_TK, ++ UNICODERANGE_TK, ++ SEMICOLON_TK, ++ CBO_TK, /*opening curly bracket*/ ++ CBC_TK, /*closing curly bracket*/ ++ PO_TK, /*opening parenthesis*/ ++ PC_TK, /*closing parenthesis*/ ++ BO_TK, /*opening bracket*/ ++ BC_TK, /*closing bracket*/ ++ DELIM_TK ++} ; ++ ++enum CRTokenExtraType ++{ ++ NO_ET = 0, ++ LENGTH_PX_ET, ++ LENGTH_CM_ET, ++ LENGTH_MM_ET, ++ LENGTH_IN_ET, ++ LENGTH_PT_ET, ++ LENGTH_PC_ET, ++ ANGLE_DEG_ET, ++ ANGLE_RAD_ET, ++ ANGLE_GRAD_ET, ++ TIME_MS_ET, ++ TIME_S_ET, ++ FREQ_HZ_ET, ++ FREQ_KHZ_ET ++} ; ++ ++typedef struct _CRToken CRToken ; ++ ++/** ++ *This class abstracts a css2 token. ++ */ ++struct _CRToken ++{ ++ enum CRTokenType type ; ++ enum CRTokenExtraType extra_type ; ++ CRInputPos pos ; ++ ++ union ++ { ++ CRString *str ; ++ CRRgb *rgb ; ++ CRNum *num ; ++ guint32 unichar ; ++ } u ; ++ ++ CRString * dimen ; ++ CRParsingLocation location ; ++} ; ++ ++CRToken* cr_token_new (void) ; ++ ++enum CRStatus cr_token_set_s (CRToken *a_this) ; ++ ++enum CRStatus cr_token_set_cdo (CRToken *a_this) ; ++ ++enum CRStatus cr_token_set_cdc (CRToken *a_this) ; ++ ++enum CRStatus cr_token_set_includes (CRToken *a_this) ; ++ ++enum CRStatus cr_token_set_dashmatch (CRToken *a_this) ; ++ ++enum CRStatus cr_token_set_comment (CRToken *a_this, CRString *a_str) ; ++ ++enum CRStatus cr_token_set_string (CRToken *a_this, CRString *a_str) ; ++ ++enum CRStatus cr_token_set_ident (CRToken *a_this, CRString * a_ident) ; ++ ++enum CRStatus cr_token_set_hash (CRToken *a_this, CRString *a_hash) ; ++ ++enum CRStatus cr_token_set_rgb (CRToken *a_this, CRRgb *a_rgb) ; ++ ++enum CRStatus cr_token_set_import_sym (CRToken *a_this) ; ++ ++enum CRStatus cr_token_set_page_sym (CRToken *a_this) ; ++ ++enum CRStatus cr_token_set_media_sym (CRToken *a_this) ; ++ ++enum CRStatus cr_token_set_font_face_sym (CRToken *a_this) ; ++ ++enum CRStatus cr_token_set_charset_sym (CRToken *a_this) ; ++ ++enum CRStatus cr_token_set_atkeyword (CRToken *a_this, CRString *a_atname) ; ++ ++enum CRStatus cr_token_set_important_sym (CRToken *a_this) ; ++ ++enum CRStatus cr_token_set_ems (CRToken *a_this, CRNum *a_num) ; ++ ++enum CRStatus cr_token_set_exs (CRToken *a_this, CRNum *a_num) ; ++ ++enum CRStatus cr_token_set_length (CRToken *a_this, CRNum *a_num, ++ enum CRTokenExtraType a_et) ; ++ ++enum CRStatus cr_token_set_angle (CRToken *a_this, CRNum *a_num, ++ enum CRTokenExtraType a_et) ; ++ ++enum CRStatus cr_token_set_time (CRToken *a_this, CRNum *a_num, ++ enum CRTokenExtraType a_et) ; ++ ++enum CRStatus cr_token_set_freq (CRToken *a_this, CRNum *a_num, ++ enum CRTokenExtraType a_et) ; ++ ++enum CRStatus cr_token_set_dimen (CRToken *a_this, CRNum *a_num, ++ CRString *a_dim) ; ++ ++enum CRStatus cr_token_set_percentage (CRToken *a_this, CRNum *a_num) ; ++ ++enum CRStatus cr_token_set_number (CRToken *a_this, CRNum *a_num) ; ++ ++enum CRStatus cr_token_set_uri (CRToken *a_this, CRString *a_uri) ; ++ ++enum CRStatus cr_token_set_function (CRToken *a_this, ++ CRString *a_fun_name) ; ++ ++enum CRStatus cr_token_set_bc (CRToken *a_this) ; ++ ++enum CRStatus cr_token_set_bo (CRToken *a_this) ; ++ ++enum CRStatus cr_token_set_po (CRToken *a_this) ; ++ ++enum CRStatus cr_token_set_pc (CRToken *a_this) ; ++ ++enum CRStatus cr_token_set_cbc (CRToken *a_this) ; ++ ++enum CRStatus cr_token_set_cbo (CRToken *a_this) ; ++ ++enum CRStatus cr_token_set_semicolon (CRToken *a_this) ; ++ ++enum CRStatus cr_token_set_delim (CRToken *a_this, guint32 a_char) ; ++ ++ ++/* ++ enum CRStatus ++ cr_token_set_unicoderange (CRToken *a_this, ++ CRUnicodeRange *a_range) ; ++*/ ++ ++void ++cr_token_destroy (CRToken *a_this) ; ++ ++ ++G_END_DECLS ++ ++#endif /*__CR_TOKEN_H__*/ +diff --git a/src/st/croco/cr-utils.c b/src/st/croco/cr-utils.c +new file mode 100644 +index 000000000..2420cec7c +--- /dev/null ++++ b/src/st/croco/cr-utils.c +@@ -0,0 +1,1330 @@ ++/* -*- Mode: C; indent-tabs-mode: nil; c-basic-offset: 8 -*- */ ++ ++/* ++ * This file is part of The Croco Library ++ * ++ * 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 ++ * See COPYRIGHTS file for copyright information. ++ */ ++ ++#include "cr-utils.h" ++#include "cr-string.h" ++ ++/** ++ *@file: ++ *Some misc utility functions used ++ *in the libcroco. ++ *Note that troughout this file I will ++ *refer to the CSS SPECIFICATIONS DOCUMENTATION ++ *written by the w3c guys. You can find that document ++ *at http://www.w3.org/TR/REC-CSS2/ . ++ */ ++ ++/**************************** ++ *Encoding transformations and ++ *encoding helpers ++ ****************************/ ++ ++/* ++ *Here is the correspondance between the ucs-4 charactere codes ++ *and there matching utf-8 encoding pattern as dscribed by RFC 2279: ++ * ++ *UCS-4 range (hex.) UTF-8 octet sequence (binary) ++ *------------------ ----------------------------- ++ *0000 0000-0000 007F 0xxxxxxx ++ *0000 0080-0000 07FF 110xxxxx 10xxxxxx ++ *0000 0800-0000 FFFF 1110xxxx 10xxxxxx 10xxxxxx ++ *0001 0000-001F FFFF 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx ++ *0020 0000-03FF FFFF 111110xx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx ++ *0400 0000-7FFF FFFF 1111110x 10xxxxxx ... 10xxxxxx ++ */ ++ ++/** ++ *Given an utf8 string buffer, calculates ++ *the length of this string if it was encoded ++ *in ucs4. ++ *@param a_in_start a pointer to the begining of ++ *the input utf8 string. ++ *@param a_in_end a pointre to the end of the input ++ *utf8 string (points to the last byte of the buffer) ++ *@param a_len out parameter the calculated length. ++ *@return CR_OK upon succesfull completion, an error code ++ *otherwise. ++ */ ++enum CRStatus ++cr_utils_utf8_str_len_as_ucs4 (const guchar * a_in_start, ++ const guchar * a_in_end, gulong * a_len) ++{ ++ guchar *byte_ptr = NULL; ++ gint len = 0; ++ ++ /* ++ *to store the final decoded ++ *unicode char ++ */ ++ guint c = 0; ++ ++ g_return_val_if_fail (a_in_start && a_in_end && a_len, ++ CR_BAD_PARAM_ERROR); ++ *a_len = 0; ++ ++ for (byte_ptr = (guchar *) a_in_start; ++ byte_ptr <= a_in_end; byte_ptr++) { ++ gint nb_bytes_2_decode = 0; ++ ++ if (*byte_ptr <= 0x7F) { ++ /* ++ *7 bits long char ++ *encoded over 1 byte: ++ * 0xxx xxxx ++ */ ++ c = *byte_ptr; ++ nb_bytes_2_decode = 1; ++ ++ } else if ((*byte_ptr & 0xE0) == 0xC0) { ++ /* ++ *up to 11 bits long char. ++ *encoded over 2 bytes: ++ *110x xxxx 10xx xxxx ++ */ ++ c = *byte_ptr & 0x1F; ++ nb_bytes_2_decode = 2; ++ ++ } else if ((*byte_ptr & 0xF0) == 0xE0) { ++ /* ++ *up to 16 bit long char ++ *encoded over 3 bytes: ++ *1110 xxxx 10xx xxxx 10xx xxxx ++ */ ++ c = *byte_ptr & 0x0F; ++ nb_bytes_2_decode = 3; ++ ++ } else if ((*byte_ptr & 0xF8) == 0xF0) { ++ /* ++ *up to 21 bits long char ++ *encoded over 4 bytes: ++ *1111 0xxx 10xx xxxx 10xx xxxx 10xx xxxx ++ */ ++ c = *byte_ptr & 0x7; ++ nb_bytes_2_decode = 4; ++ ++ } else if ((*byte_ptr & 0xFC) == 0xF8) { ++ /* ++ *up to 26 bits long char ++ *encoded over 5 bytes. ++ *1111 10xx 10xx xxxx 10xx xxxx ++ *10xx xxxx 10xx xxxx ++ */ ++ c = *byte_ptr & 3; ++ nb_bytes_2_decode = 5; ++ ++ } else if ((*byte_ptr & 0xFE) == 0xFC) { ++ /* ++ *up to 31 bits long char ++ *encoded over 6 bytes: ++ *1111 110x 10xx xxxx 10xx xxxx ++ *10xx xxxx 10xx xxxx 10xx xxxx ++ */ ++ c = *byte_ptr & 1; ++ nb_bytes_2_decode = 6; ++ ++ } else { ++ /* ++ *BAD ENCODING ++ */ ++ return CR_ENCODING_ERROR; ++ } ++ ++ /* ++ *Go and decode the remaining byte(s) ++ *(if any) to get the current character. ++ */ ++ for (; nb_bytes_2_decode > 1; nb_bytes_2_decode--) { ++ /*decode the next byte */ ++ byte_ptr++; ++ ++ /*byte pattern must be: 10xx xxxx */ ++ if ((*byte_ptr & 0xC0) != 0x80) { ++ return CR_ENCODING_ERROR; ++ } ++ ++ c = (c << 6) | (*byte_ptr & 0x3F); ++ } ++ ++ len++; ++ } ++ ++ *a_len = len; ++ ++ return CR_OK; ++} ++ ++/** ++ *Given an ucs4 string, this function ++ *returns the size (in bytes) this string ++ *would have occupied if it was encoded in utf-8. ++ *@param a_in_start a pointer to the beginning of the input ++ *buffer. ++ *@param a_in_end a pointer to the end of the input buffer. ++ *@param a_len out parameter. The computed length. ++ *@return CR_OK upon successfull completion, an error code otherwise. ++ */ ++enum CRStatus ++cr_utils_ucs4_str_len_as_utf8 (const guint32 * a_in_start, ++ const guint32 * a_in_end, gulong * a_len) ++{ ++ gint len = 0; ++ guint32 *char_ptr = NULL; ++ ++ g_return_val_if_fail (a_in_start && a_in_end && a_len, ++ CR_BAD_PARAM_ERROR); ++ ++ for (char_ptr = (guint32 *) a_in_start; ++ char_ptr <= a_in_end; char_ptr++) { ++ if (*char_ptr <= 0x7F) { ++ /*the utf-8 char would take 1 byte */ ++ len += 1; ++ } else if (*char_ptr <= 0x7FF) { ++ /*the utf-8 char would take 2 bytes */ ++ len += 2; ++ } else if (*char_ptr <= 0xFFFF) { ++ len += 3; ++ } else if (*char_ptr <= 0x1FFFFF) { ++ len += 4; ++ } else if (*char_ptr <= 0x3FFFFFF) { ++ len += 5; ++ } else if (*char_ptr <= 0x7FFFFFFF) { ++ len += 6; ++ } ++ } ++ ++ *a_len = len; ++ return CR_OK; ++} ++ ++/** ++ *Given an ucsA string, this function ++ *returns the size (in bytes) this string ++ *would have occupied if it was encoded in utf-8. ++ *@param a_in_start a pointer to the beginning of the input ++ *buffer. ++ *@param a_in_end a pointer to the end of the input buffer. ++ *@param a_len out parameter. The computed length. ++ *@return CR_OK upon successfull completion, an error code otherwise. ++ */ ++enum CRStatus ++cr_utils_ucs1_str_len_as_utf8 (const guchar * a_in_start, ++ const guchar * a_in_end, gulong * a_len) ++{ ++ gint len = 0; ++ guchar *char_ptr = NULL; ++ ++ g_return_val_if_fail (a_in_start && a_in_end && a_len, ++ CR_BAD_PARAM_ERROR); ++ ++ for (char_ptr = (guchar *) a_in_start; ++ char_ptr <= a_in_end; char_ptr++) { ++ if (*char_ptr <= 0x7F) { ++ /*the utf-8 char would take 1 byte */ ++ len += 1; ++ } else { ++ /*the utf-8 char would take 2 bytes */ ++ len += 2; ++ } ++ } ++ ++ *a_len = len; ++ return CR_OK; ++} ++ ++/** ++ *Converts an utf8 buffer into an ucs4 buffer. ++ * ++ *@param a_in the input utf8 buffer to convert. ++ *@param a_in_len in/out parameter. The size of the ++ *input buffer to convert. After return, this parameter contains ++ *the actual number of bytes consumed. ++ *@param a_out the output converted ucs4 buffer. Must be allocated by ++ *the caller. ++ *@param a_out_len in/out parameter. The size of the output buffer. ++ *If this size is actually smaller than the real needed size, the function ++ *just converts what it can and returns a success status. After return, ++ *this param points to the actual number of characters decoded. ++ *@return CR_OK upon successfull completion, an error code otherwise. ++ */ ++enum CRStatus ++cr_utils_utf8_to_ucs4 (const guchar * a_in, ++ gulong * a_in_len, guint32 * a_out, gulong * a_out_len) ++{ ++ gulong in_len = 0, ++ out_len = 0, ++ in_index = 0, ++ out_index = 0; ++ enum CRStatus status = CR_OK; ++ ++ /* ++ *to store the final decoded ++ *unicode char ++ */ ++ guint c = 0; ++ ++ g_return_val_if_fail (a_in && a_in_len ++ && a_out && a_out_len, CR_BAD_PARAM_ERROR); ++ ++ if (*a_in_len < 1) { ++ status = CR_OK; ++ goto end; ++ } ++ ++ in_len = *a_in_len; ++ out_len = *a_out_len; ++ ++ for (in_index = 0, out_index = 0; ++ (in_index < in_len) && (out_index < out_len); ++ in_index++, out_index++) { ++ gint nb_bytes_2_decode = 0; ++ ++ if (a_in[in_index] <= 0x7F) { ++ /* ++ *7 bits long char ++ *encoded over 1 byte: ++ * 0xxx xxxx ++ */ ++ c = a_in[in_index]; ++ nb_bytes_2_decode = 1; ++ ++ } else if ((a_in[in_index] & 0xE0) == 0xC0) { ++ /* ++ *up to 11 bits long char. ++ *encoded over 2 bytes: ++ *110x xxxx 10xx xxxx ++ */ ++ c = a_in[in_index] & 0x1F; ++ nb_bytes_2_decode = 2; ++ ++ } else if ((a_in[in_index] & 0xF0) == 0xE0) { ++ /* ++ *up to 16 bit long char ++ *encoded over 3 bytes: ++ *1110 xxxx 10xx xxxx 10xx xxxx ++ */ ++ c = a_in[in_index] & 0x0F; ++ nb_bytes_2_decode = 3; ++ ++ } else if ((a_in[in_index] & 0xF8) == 0xF0) { ++ /* ++ *up to 21 bits long char ++ *encoded over 4 bytes: ++ *1111 0xxx 10xx xxxx 10xx xxxx 10xx xxxx ++ */ ++ c = a_in[in_index] & 0x7; ++ nb_bytes_2_decode = 4; ++ ++ } else if ((a_in[in_index] & 0xFC) == 0xF8) { ++ /* ++ *up to 26 bits long char ++ *encoded over 5 bytes. ++ *1111 10xx 10xx xxxx 10xx xxxx ++ *10xx xxxx 10xx xxxx ++ */ ++ c = a_in[in_index] & 3; ++ nb_bytes_2_decode = 5; ++ ++ } else if ((a_in[in_index] & 0xFE) == 0xFC) { ++ /* ++ *up to 31 bits long char ++ *encoded over 6 bytes: ++ *1111 110x 10xx xxxx 10xx xxxx ++ *10xx xxxx 10xx xxxx 10xx xxxx ++ */ ++ c = a_in[in_index] & 1; ++ nb_bytes_2_decode = 6; ++ ++ } else { ++ /*BAD ENCODING */ ++ goto end; ++ } ++ ++ /* ++ *Go and decode the remaining byte(s) ++ *(if any) to get the current character. ++ */ ++ for (; nb_bytes_2_decode > 1; nb_bytes_2_decode--) { ++ /*decode the next byte */ ++ in_index++; ++ ++ /*byte pattern must be: 10xx xxxx */ ++ if ((a_in[in_index] & 0xC0) != 0x80) { ++ goto end; ++ } ++ ++ c = (c << 6) | (a_in[in_index] & 0x3F); ++ } ++ ++ /* ++ *The decoded ucs4 char is now ++ *in c. ++ */ ++ ++ /************************ ++ *Some security tests ++ ***********************/ ++ ++ /*be sure c is a char */ ++ if (c == 0xFFFF || c == 0xFFFE) ++ goto end; ++ ++ /*be sure c is inferior to the max ucs4 char value */ ++ if (c > 0x10FFFF) ++ goto end; ++ ++ /* ++ *c must be less than UTF16 "lower surrogate begin" ++ *or higher than UTF16 "High surrogate end" ++ */ ++ if (c >= 0xD800 && c <= 0xDFFF) ++ goto end; ++ ++ /*Avoid characters that equals zero */ ++ if (c == 0) ++ goto end; ++ ++ a_out[out_index] = c; ++ } ++ ++ end: ++ *a_out_len = out_index + 1; ++ *a_in_len = in_index + 1; ++ ++ return status; ++} ++ ++/** ++ *Reads a character from an utf8 buffer. ++ *Actually decode the next character code (unicode character code) ++ *and returns it. ++ *@param a_in the starting address of the utf8 buffer. ++ *@param a_in_len the length of the utf8 buffer. ++ *@param a_out output parameter. The resulting read char. ++ *@param a_consumed the number of the bytes consumed to ++ *decode the returned character code. ++ *@return CR_OK upon successfull completion, an error code otherwise. ++ */ ++enum CRStatus ++cr_utils_read_char_from_utf8_buf (const guchar * a_in, ++ gulong a_in_len, ++ guint32 * a_out, gulong * a_consumed) ++{ ++ gulong in_index = 0, ++ nb_bytes_2_decode = 0; ++ enum CRStatus status = CR_OK; ++ ++ /* ++ *to store the final decoded ++ *unicode char ++ */ ++ guint32 c = 0; ++ ++ g_return_val_if_fail (a_in && a_out && a_out ++ && a_consumed, CR_BAD_PARAM_ERROR); ++ ++ if (a_in_len < 1) { ++ status = CR_OK; ++ goto end; ++ } ++ ++ if (*a_in <= 0x7F) { ++ /* ++ *7 bits long char ++ *encoded over 1 byte: ++ * 0xxx xxxx ++ */ ++ c = *a_in; ++ nb_bytes_2_decode = 1; ++ ++ } else if ((*a_in & 0xE0) == 0xC0) { ++ /* ++ *up to 11 bits long char. ++ *encoded over 2 bytes: ++ *110x xxxx 10xx xxxx ++ */ ++ c = *a_in & 0x1F; ++ nb_bytes_2_decode = 2; ++ ++ } else if ((*a_in & 0xF0) == 0xE0) { ++ /* ++ *up to 16 bit long char ++ *encoded over 3 bytes: ++ *1110 xxxx 10xx xxxx 10xx xxxx ++ */ ++ c = *a_in & 0x0F; ++ nb_bytes_2_decode = 3; ++ ++ } else if ((*a_in & 0xF8) == 0xF0) { ++ /* ++ *up to 21 bits long char ++ *encoded over 4 bytes: ++ *1111 0xxx 10xx xxxx 10xx xxxx 10xx xxxx ++ */ ++ c = *a_in & 0x7; ++ nb_bytes_2_decode = 4; ++ ++ } else if ((*a_in & 0xFC) == 0xF8) { ++ /* ++ *up to 26 bits long char ++ *encoded over 5 bytes. ++ *1111 10xx 10xx xxxx 10xx xxxx ++ *10xx xxxx 10xx xxxx ++ */ ++ c = *a_in & 3; ++ nb_bytes_2_decode = 5; ++ ++ } else if ((*a_in & 0xFE) == 0xFC) { ++ /* ++ *up to 31 bits long char ++ *encoded over 6 bytes: ++ *1111 110x 10xx xxxx 10xx xxxx ++ *10xx xxxx 10xx xxxx 10xx xxxx ++ */ ++ c = *a_in & 1; ++ nb_bytes_2_decode = 6; ++ ++ } else { ++ /*BAD ENCODING */ ++ goto end; ++ } ++ ++ if (nb_bytes_2_decode > a_in_len) { ++ status = CR_END_OF_INPUT_ERROR; ++ goto end; ++ } ++ ++ /* ++ *Go and decode the remaining byte(s) ++ *(if any) to get the current character. ++ */ ++ for (in_index = 1; in_index < nb_bytes_2_decode; in_index++) { ++ /*byte pattern must be: 10xx xxxx */ ++ if ((a_in[in_index] & 0xC0) != 0x80) { ++ goto end; ++ } ++ ++ c = (c << 6) | (a_in[in_index] & 0x3F); ++ } ++ ++ /* ++ *The decoded ucs4 char is now ++ *in c. ++ */ ++ ++ /************************ ++ *Some security tests ++ ***********************/ ++ ++ /*be sure c is a char */ ++ if (c == 0xFFFF || c == 0xFFFE) ++ goto end; ++ ++ /*be sure c is inferior to the max ucs4 char value */ ++ if (c > 0x10FFFF) ++ goto end; ++ ++ /* ++ *c must be less than UTF16 "lower surrogate begin" ++ *or higher than UTF16 "High surrogate end" ++ */ ++ if (c >= 0xD800 && c <= 0xDFFF) ++ goto end; ++ ++ /*Avoid characters that equals zero */ ++ if (c == 0) ++ goto end; ++ ++ *a_out = c; ++ ++ end: ++ *a_consumed = nb_bytes_2_decode; ++ ++ return status; ++} ++ ++/** ++ * ++ */ ++enum CRStatus ++cr_utils_utf8_str_len_as_ucs1 (const guchar * a_in_start, ++ const guchar * a_in_end, gulong * a_len) ++{ ++ /* ++ *Note: this function can be made shorter ++ *but it considers all the cases of the utf8 encoding ++ *to ease further extensions ... ++ */ ++ ++ guchar *byte_ptr = NULL; ++ gint len = 0; ++ ++ /* ++ *to store the final decoded ++ *unicode char ++ */ ++ guint c = 0; ++ ++ g_return_val_if_fail (a_in_start && a_in_end && a_len, ++ CR_BAD_PARAM_ERROR); ++ *a_len = 0; ++ ++ for (byte_ptr = (guchar *) a_in_start; ++ byte_ptr <= a_in_end; byte_ptr++) { ++ gint nb_bytes_2_decode = 0; ++ ++ if (*byte_ptr <= 0x7F) { ++ /* ++ *7 bits long char ++ *encoded over 1 byte: ++ * 0xxx xxxx ++ */ ++ c = *byte_ptr; ++ nb_bytes_2_decode = 1; ++ ++ } else if ((*byte_ptr & 0xE0) == 0xC0) { ++ /* ++ *up to 11 bits long char. ++ *encoded over 2 bytes: ++ *110x xxxx 10xx xxxx ++ */ ++ c = *byte_ptr & 0x1F; ++ nb_bytes_2_decode = 2; ++ ++ } else if ((*byte_ptr & 0xF0) == 0xE0) { ++ /* ++ *up to 16 bit long char ++ *encoded over 3 bytes: ++ *1110 xxxx 10xx xxxx 10xx xxxx ++ */ ++ c = *byte_ptr & 0x0F; ++ nb_bytes_2_decode = 3; ++ ++ } else if ((*byte_ptr & 0xF8) == 0xF0) { ++ /* ++ *up to 21 bits long char ++ *encoded over 4 bytes: ++ *1111 0xxx 10xx xxxx 10xx xxxx 10xx xxxx ++ */ ++ c = *byte_ptr & 0x7; ++ nb_bytes_2_decode = 4; ++ ++ } else if ((*byte_ptr & 0xFC) == 0xF8) { ++ /* ++ *up to 26 bits long char ++ *encoded over 5 bytes. ++ *1111 10xx 10xx xxxx 10xx xxxx ++ *10xx xxxx 10xx xxxx ++ */ ++ c = *byte_ptr & 3; ++ nb_bytes_2_decode = 5; ++ ++ } else if ((*byte_ptr & 0xFE) == 0xFC) { ++ /* ++ *up to 31 bits long char ++ *encoded over 6 bytes: ++ *1111 110x 10xx xxxx 10xx xxxx ++ *10xx xxxx 10xx xxxx 10xx xxxx ++ */ ++ c = *byte_ptr & 1; ++ nb_bytes_2_decode = 6; ++ ++ } else { ++ /* ++ *BAD ENCODING ++ */ ++ return CR_ENCODING_ERROR; ++ } ++ ++ /* ++ *Go and decode the remaining byte(s) ++ *(if any) to get the current character. ++ */ ++ for (; nb_bytes_2_decode > 1; nb_bytes_2_decode--) { ++ /*decode the next byte */ ++ byte_ptr++; ++ ++ /*byte pattern must be: 10xx xxxx */ ++ if ((*byte_ptr & 0xC0) != 0x80) { ++ return CR_ENCODING_ERROR; ++ } ++ ++ c = (c << 6) | (*byte_ptr & 0x3F); ++ } ++ ++ /* ++ *The decoded ucs4 char is now ++ *in c. ++ */ ++ ++ if (c <= 0xFF) { /*Add other conditions to support ++ *other char sets (ucs2, ucs3, ucs4). ++ */ ++ len++; ++ } else { ++ /*the char is too long to fit ++ *into the supposed charset len. ++ */ ++ return CR_ENCODING_ERROR; ++ } ++ } ++ ++ *a_len = len; ++ ++ return CR_OK; ++} ++ ++/** ++ *Converts an utf8 string into an ucs4 string. ++ *@param a_in the input string to convert. ++ *@param a_in_len in/out parameter. The length of the input ++ *string. After return, points to the actual number of bytes ++ *consumed. This can be usefull to debug the input stream in case ++ *of encoding error. ++ *@param a_out out parameter. Points to the output string. It is allocated ++ *by this function and must be freed by the caller. ++ *@param a_out_len out parameter. The length of the output string. ++ *@return CR_OK upon successfull completion, an error code otherwise. ++ * ++ */ ++enum CRStatus ++cr_utils_utf8_str_to_ucs4 (const guchar * a_in, ++ gulong * a_in_len, ++ guint32 ** a_out, gulong * a_out_len) ++{ ++ enum CRStatus status = CR_OK; ++ ++ g_return_val_if_fail (a_in && a_in_len ++ && a_out && a_out_len, CR_BAD_PARAM_ERROR); ++ ++ status = cr_utils_utf8_str_len_as_ucs4 (a_in, ++ &a_in[*a_in_len - 1], ++ a_out_len); ++ ++ g_return_val_if_fail (status == CR_OK, status); ++ ++ *a_out = g_malloc0 (*a_out_len * sizeof (guint32)); ++ ++ status = cr_utils_utf8_to_ucs4 (a_in, a_in_len, *a_out, a_out_len); ++ ++ return status; ++} ++ ++/** ++ *Converts an ucs4 buffer into an utf8 buffer. ++ * ++ *@param a_in the input ucs4 buffer to convert. ++ *@param a_in_len in/out parameter. The size of the ++ *input buffer to convert. After return, this parameter contains ++ *the actual number of characters consumed. ++ *@param a_out the output converted utf8 buffer. Must be allocated by ++ *the caller. ++ *@param a_out_len in/out parameter. The size of the output buffer. ++ *If this size is actually smaller than the real needed size, the function ++ *just converts what it can and returns a success status. After return, ++ *this param points to the actual number of bytes in the buffer. ++ *@return CR_OK upon successfull completion, an error code otherwise. ++ */ ++enum CRStatus ++cr_utils_ucs4_to_utf8 (const guint32 * a_in, ++ gulong * a_in_len, guchar * a_out, gulong * a_out_len) ++{ ++ gulong in_len = 0, ++ in_index = 0, ++ out_index = 0; ++ enum CRStatus status = CR_OK; ++ ++ g_return_val_if_fail (a_in && a_in_len && a_out && a_out_len, ++ CR_BAD_PARAM_ERROR); ++ ++ if (*a_in_len < 1) { ++ status = CR_OK; ++ goto end; ++ } ++ ++ in_len = *a_in_len; ++ ++ for (in_index = 0; in_index < in_len; in_index++) { ++ /* ++ *FIXME: return whenever we encounter forbidden char values. ++ */ ++ ++ if (a_in[in_index] <= 0x7F) { ++ a_out[out_index] = a_in[in_index]; ++ out_index++; ++ } else if (a_in[in_index] <= 0x7FF) { ++ a_out[out_index] = (0xC0 | (a_in[in_index] >> 6)); ++ a_out[out_index + 1] = ++ (0x80 | (a_in[in_index] & 0x3F)); ++ out_index += 2; ++ } else if (a_in[in_index] <= 0xFFFF) { ++ a_out[out_index] = (0xE0 | (a_in[in_index] >> 12)); ++ a_out[out_index + 1] = ++ (0x80 | ((a_in[in_index] >> 6) & 0x3F)); ++ a_out[out_index + 2] = ++ (0x80 | (a_in[in_index] & 0x3F)); ++ out_index += 3; ++ } else if (a_in[in_index] <= 0x1FFFFF) { ++ a_out[out_index] = (0xF0 | (a_in[in_index] >> 18)); ++ a_out[out_index + 1] ++ = (0x80 | ((a_in[in_index] >> 12) & 0x3F)); ++ a_out[out_index + 2] ++ = (0x80 | ((a_in[in_index] >> 6) & 0x3F)); ++ a_out[out_index + 3] ++ = (0x80 | (a_in[in_index] & 0x3F)); ++ out_index += 4; ++ } else if (a_in[in_index] <= 0x3FFFFFF) { ++ a_out[out_index] = (0xF8 | (a_in[in_index] >> 24)); ++ a_out[out_index + 1] = ++ (0x80 | (a_in[in_index] >> 18)); ++ a_out[out_index + 2] ++ = (0x80 | ((a_in[in_index] >> 12) & 0x3F)); ++ a_out[out_index + 3] ++ = (0x80 | ((a_in[in_index] >> 6) & 0x3F)); ++ a_out[out_index + 4] ++ = (0x80 | (a_in[in_index] & 0x3F)); ++ out_index += 5; ++ } else if (a_in[in_index] <= 0x7FFFFFFF) { ++ a_out[out_index] = (0xFC | (a_in[in_index] >> 30)); ++ a_out[out_index + 1] = ++ (0x80 | (a_in[in_index] >> 24)); ++ a_out[out_index + 2] ++ = (0x80 | ((a_in[in_index] >> 18) & 0x3F)); ++ a_out[out_index + 3] ++ = (0x80 | ((a_in[in_index] >> 12) & 0x3F)); ++ a_out[out_index + 4] ++ = (0x80 | ((a_in[in_index] >> 6) & 0x3F)); ++ a_out[out_index + 4] ++ = (0x80 | (a_in[in_index] & 0x3F)); ++ out_index += 6; ++ } else { ++ status = CR_ENCODING_ERROR; ++ goto end; ++ } ++ } /*end for */ ++ ++ end: ++ *a_in_len = in_index + 1; ++ *a_out_len = out_index + 1; ++ ++ return status; ++} ++ ++/** ++ *Converts an ucs4 string into an utf8 string. ++ *@param a_in the input string to convert. ++ *@param a_in_len in/out parameter. The length of the input ++ *string. After return, points to the actual number of characters ++ *consumed. This can be usefull to debug the input string in case ++ *of encoding error. ++ *@param a_out out parameter. Points to the output string. It is allocated ++ *by this function and must be freed by the caller. ++ *@param a_out_len out parameter. The length (in bytes) of the output string. ++ *@return CR_OK upon successfull completion, an error code otherwise. ++ */ ++enum CRStatus ++cr_utils_ucs4_str_to_utf8 (const guint32 * a_in, ++ gulong * a_in_len, ++ guchar ** a_out, gulong * a_out_len) ++{ ++ enum CRStatus status = CR_OK; ++ ++ g_return_val_if_fail (a_in && a_in_len && a_out ++ && a_out_len, CR_BAD_PARAM_ERROR); ++ ++ status = cr_utils_ucs4_str_len_as_utf8 (a_in, ++ &a_in[*a_out_len - 1], ++ a_out_len); ++ ++ g_return_val_if_fail (status == CR_OK, status); ++ ++ status = cr_utils_ucs4_to_utf8 (a_in, a_in_len, *a_out, a_out_len); ++ ++ return status; ++} ++ ++/** ++ *Converts an ucs1 buffer into an utf8 buffer. ++ *The caller must know the size of the resulting buffer and ++ *allocate it prior to calling this function. ++ * ++ *@param a_in the input ucs1 buffer. ++ * ++ *@param a_in_len in/out parameter. The length of the input buffer. ++ *After return, points to the number of bytes actually consumed even ++ *in case of encoding error. ++ * ++ *@param a_out out parameter. The output utf8 converted buffer. ++ * ++ *@param a_out_len in/out parameter. The size of the output buffer. ++ *If the output buffer size is shorter than the actual needed size, ++ *this function just convert what it can. ++ * ++ *@return CR_OK upon successfull completion, an error code otherwise. ++ * ++ */ ++enum CRStatus ++cr_utils_ucs1_to_utf8 (const guchar * a_in, ++ gulong * a_in_len, guchar * a_out, gulong * a_out_len) ++{ ++ gulong out_index = 0, ++ in_index = 0, ++ in_len = 0, ++ out_len = 0; ++ enum CRStatus status = CR_OK; ++ ++ g_return_val_if_fail (a_in && a_in_len ++ && a_out_len, ++ CR_BAD_PARAM_ERROR); ++ ++ if (*a_in_len == 0) { ++ *a_out_len = 0 ; ++ return status; ++ } ++ g_return_val_if_fail (a_out, CR_BAD_PARAM_ERROR) ; ++ ++ in_len = *a_in_len; ++ out_len = *a_out_len; ++ ++ for (in_index = 0, out_index = 0; ++ (in_index < in_len) && (out_index < out_len); in_index++) { ++ /* ++ *FIXME: return whenever we encounter forbidden char values. ++ */ ++ ++ if (a_in[in_index] <= 0x7F) { ++ a_out[out_index] = a_in[in_index]; ++ out_index++; ++ } else { ++ a_out[out_index] = (0xC0 | (a_in[in_index] >> 6)); ++ a_out[out_index + 1] = ++ (0x80 | (a_in[in_index] & 0x3F)); ++ out_index += 2; ++ } ++ } /*end for */ ++ ++ *a_in_len = in_index; ++ *a_out_len = out_index; ++ ++ return status; ++} ++ ++/** ++ *Converts an ucs1 string into an utf8 string. ++ *@param a_in_start the beginning of the input string to convert. ++ *@param a_in_end the end of the input string to convert. ++ *@param a_out out parameter. The converted string. ++ *@param a_out out parameter. The length of the converted string. ++ *@return CR_OK upon successfull completion, an error code otherwise. ++ * ++ */ ++enum CRStatus ++cr_utils_ucs1_str_to_utf8 (const guchar * a_in, ++ gulong * a_in_len, ++ guchar ** a_out, gulong * a_out_len) ++{ ++ gulong out_len = 0; ++ enum CRStatus status = CR_OK; ++ ++ g_return_val_if_fail (a_in && a_in_len && a_out ++ && a_out_len, CR_BAD_PARAM_ERROR); ++ ++ if (*a_in_len < 1) { ++ *a_out_len = 0; ++ *a_out = NULL; ++ return CR_OK; ++ } ++ ++ status = cr_utils_ucs1_str_len_as_utf8 (a_in, &a_in[*a_in_len - 1], ++ &out_len); ++ ++ g_return_val_if_fail (status == CR_OK, status); ++ ++ *a_out = g_malloc0 (out_len); ++ ++ status = cr_utils_ucs1_to_utf8 (a_in, a_in_len, *a_out, &out_len); ++ ++ *a_out_len = out_len; ++ ++ return status; ++} ++ ++/** ++ *Converts an utf8 buffer into an ucs1 buffer. ++ *The caller must know the size of the resulting ++ *converted buffer, and allocated it prior to calling this ++ *function. ++ * ++ *@param a_in the input utf8 buffer to convert. ++ * ++ *@param a_in_len in/out parameter. The size of the input utf8 buffer. ++ *After return, points to the number of bytes consumed ++ *by the function even in case of encoding error. ++ * ++ *@param a_out out parameter. Points to the resulting buffer. ++ *Must be allocated by the caller. If the size of a_out is shorter ++ *than its required size, this function converts what it can and return ++ *a successfull status. ++ * ++ *@param a_out_len in/out parameter. The size of the output buffer. ++ *After return, points to the number of bytes consumed even in case of ++ *encoding error. ++ * ++ *@return CR_OK upon successfull completion, an error code otherwise. ++ */ ++enum CRStatus ++cr_utils_utf8_to_ucs1 (const guchar * a_in, ++ gulong * a_in_len, guchar * a_out, gulong * a_out_len) ++{ ++ gulong in_index = 0, ++ out_index = 0, ++ in_len = 0, ++ out_len = 0; ++ enum CRStatus status = CR_OK; ++ ++ /* ++ *to store the final decoded ++ *unicode char ++ */ ++ guint32 c = 0; ++ ++ g_return_val_if_fail (a_in && a_in_len ++ && a_out && a_out_len, CR_BAD_PARAM_ERROR); ++ ++ if (*a_in_len < 1) { ++ goto end; ++ } ++ ++ in_len = *a_in_len; ++ out_len = *a_out_len; ++ ++ for (in_index = 0, out_index = 0; ++ (in_index < in_len) && (out_index < out_len); ++ in_index++, out_index++) { ++ gint nb_bytes_2_decode = 0; ++ ++ if (a_in[in_index] <= 0x7F) { ++ /* ++ *7 bits long char ++ *encoded over 1 byte: ++ * 0xxx xxxx ++ */ ++ c = a_in[in_index]; ++ nb_bytes_2_decode = 1; ++ ++ } else if ((a_in[in_index] & 0xE0) == 0xC0) { ++ /* ++ *up to 11 bits long char. ++ *encoded over 2 bytes: ++ *110x xxxx 10xx xxxx ++ */ ++ c = a_in[in_index] & 0x1F; ++ nb_bytes_2_decode = 2; ++ ++ } else if ((a_in[in_index] & 0xF0) == 0xE0) { ++ /* ++ *up to 16 bit long char ++ *encoded over 3 bytes: ++ *1110 xxxx 10xx xxxx 10xx xxxx ++ */ ++ c = a_in[in_index] & 0x0F; ++ nb_bytes_2_decode = 3; ++ ++ } else if ((a_in[in_index] & 0xF8) == 0xF0) { ++ /* ++ *up to 21 bits long char ++ *encoded over 4 bytes: ++ *1111 0xxx 10xx xxxx 10xx xxxx 10xx xxxx ++ */ ++ c = a_in[in_index] & 0x7; ++ nb_bytes_2_decode = 4; ++ ++ } else if ((a_in[in_index] & 0xFC) == 0xF8) { ++ /* ++ *up to 26 bits long char ++ *encoded over 5 bytes. ++ *1111 10xx 10xx xxxx 10xx xxxx ++ *10xx xxxx 10xx xxxx ++ */ ++ c = a_in[in_index] & 3; ++ nb_bytes_2_decode = 5; ++ ++ } else if ((a_in[in_index] & 0xFE) == 0xFC) { ++ /* ++ *up to 31 bits long char ++ *encoded over 6 bytes: ++ *1111 110x 10xx xxxx 10xx xxxx ++ *10xx xxxx 10xx xxxx 10xx xxxx ++ */ ++ c = a_in[in_index] & 1; ++ nb_bytes_2_decode = 6; ++ ++ } else { ++ /*BAD ENCODING */ ++ status = CR_ENCODING_ERROR; ++ goto end; ++ } ++ ++ /* ++ *Go and decode the remaining byte(s) ++ *(if any) to get the current character. ++ */ ++ if (in_index + nb_bytes_2_decode - 1 >= in_len) { ++ goto end; ++ } ++ ++ for (; nb_bytes_2_decode > 1; nb_bytes_2_decode--) { ++ /*decode the next byte */ ++ in_index++; ++ ++ /*byte pattern must be: 10xx xxxx */ ++ if ((a_in[in_index] & 0xC0) != 0x80) { ++ status = CR_ENCODING_ERROR; ++ goto end; ++ } ++ ++ c = (c << 6) | (a_in[in_index] & 0x3F); ++ } ++ ++ /* ++ *The decoded ucs4 char is now ++ *in c. ++ */ ++ ++ if (c > 0xFF) { ++ status = CR_ENCODING_ERROR; ++ goto end; ++ } ++ ++ a_out[out_index] = c; ++ } ++ ++ end: ++ *a_out_len = out_index; ++ *a_in_len = in_index; ++ ++ return status; ++} ++ ++/** ++ *Converts an utf8 buffer into an ++ *ucs1 buffer. ++ *@param a_in_start the start of the input buffer. ++ *@param a_in_end the end of the input buffer. ++ *@param a_out out parameter. The resulting converted ucs4 buffer. ++ *Must be freed by the caller. ++ *@param a_out_len out parameter. The length of the converted buffer. ++ *@return CR_OK upon successfull completion, an error code otherwise. ++ *Note that out parameters are valid if and only if this function ++ *returns CR_OK. ++ */ ++enum CRStatus ++cr_utils_utf8_str_to_ucs1 (const guchar * a_in, ++ gulong * a_in_len, ++ guchar ** a_out, gulong * a_out_len) ++{ ++ enum CRStatus status = CR_OK; ++ ++ g_return_val_if_fail (a_in && a_in_len ++ && a_out && a_out_len, CR_BAD_PARAM_ERROR); ++ ++ if (*a_in_len < 1) { ++ *a_out_len = 0; ++ *a_out = NULL; ++ return CR_OK; ++ } ++ ++ status = cr_utils_utf8_str_len_as_ucs4 (a_in, &a_in[*a_in_len - 1], ++ a_out_len); ++ ++ g_return_val_if_fail (status == CR_OK, status); ++ ++ *a_out = g_malloc0 (*a_out_len * sizeof (guint32)); ++ ++ status = cr_utils_utf8_to_ucs1 (a_in, a_in_len, *a_out, a_out_len); ++ return status; ++} ++ ++/***************************************** ++ *CSS basic types identification utilities ++ *****************************************/ ++ ++/** ++ *Returns TRUE if a_char is a white space as ++ *defined in the css spec in chap 4.1.1. ++ * ++ *white-space ::= ' '| \t|\r|\n|\f ++ * ++ *@param a_char the character to test. ++ *return TRUE if is a white space, false otherwise. ++ */ ++gboolean ++cr_utils_is_white_space (guint32 a_char) ++{ ++ switch (a_char) { ++ case ' ': ++ case '\t': ++ case '\r': ++ case '\n': ++ case '\f': ++ return TRUE; ++ break; ++ default: ++ return FALSE; ++ } ++} ++ ++/** ++ *Returns true if the character is a newline ++ *as defined in the css spec in the chap 4.1.1. ++ * ++ *nl ::= \n|\r\n|\r|\f ++ * ++ *@param a_char the character to test. ++ *@return TRUE if the character is a newline, FALSE otherwise. ++ */ ++gboolean ++cr_utils_is_newline (guint32 a_char) ++{ ++ switch (a_char) { ++ case '\n': ++ case '\r': ++ case '\f': ++ return TRUE; ++ break; ++ default: ++ return FALSE; ++ } ++} ++ ++/** ++ *returns TRUE if the char is part of an hexa num char: ++ *i.e hexa_char ::= [0-9A-F] ++ */ ++gboolean ++cr_utils_is_hexa_char (guint32 a_char) ++{ ++ if ((a_char >= '0' && a_char <= '9') ++ || (a_char >= 'A' && a_char <= 'F')) { ++ return TRUE; ++ } ++ return FALSE; ++} ++ ++/** ++ *Returns true if the character is a nonascii ++ *character (as defined in the css spec chap 4.1.1): ++ * ++ *nonascii ::= [^\0-\177] ++ * ++ *@param a_char the character to test. ++ *@return TRUE if the character is a nonascii char, ++ *FALSE otherwise. ++ */ ++gboolean ++cr_utils_is_nonascii (guint32 a_char) ++{ ++ if (a_char <= 177) { ++ return FALSE; ++ } ++ ++ return TRUE; ++} ++ ++/** ++ *Dumps a character a_nb times on a file. ++ *@param a_char the char to dump ++ *@param a_fp the destination file pointer ++ *@param a_nb the number of times a_char is to be dumped. ++ */ ++void ++cr_utils_dump_n_chars (guchar a_char, FILE * a_fp, glong a_nb) ++{ ++ glong i = 0; ++ ++ for (i = 0; i < a_nb; i++) { ++ fprintf (a_fp, "%c", a_char); ++ } ++} ++ ++void ++cr_utils_dump_n_chars2 (guchar a_char, GString * a_string, glong a_nb) ++{ ++ glong i = 0; ++ ++ g_return_if_fail (a_string); ++ ++ for (i = 0; i < a_nb; i++) { ++ g_string_append_printf (a_string, "%c", a_char); ++ } ++} ++ ++/** ++ *Duplicates a list of GString instances. ++ *@return the duplicated list of GString instances or NULL if ++ *something bad happened. ++ *@param a_list_of_strings the list of strings to be duplicated. ++ */ ++GList * ++cr_utils_dup_glist_of_string (GList const * a_list_of_strings) ++{ ++ GList const *cur = NULL; ++ GList *result = NULL; ++ ++ g_return_val_if_fail (a_list_of_strings, NULL); ++ ++ for (cur = a_list_of_strings; cur; cur = cur->next) { ++ GString *str = NULL; ++ ++ str = g_string_new_len (((GString *) cur->data)->str, ++ ((GString *) cur->data)->len); ++ if (str) ++ result = g_list_append (result, str); ++ } ++ ++ return result; ++} ++ ++/** ++ *Duplicate a GList where the GList::data is a CRString. ++ *@param a_list_of_strings the list to duplicate ++ *@return the duplicated list, or NULL if something bad ++ *happened. ++ */ ++GList * ++cr_utils_dup_glist_of_cr_string (GList const * a_list_of_strings) ++{ ++ GList const *cur = NULL; ++ GList *result = NULL; ++ ++ g_return_val_if_fail (a_list_of_strings, NULL); ++ ++ for (cur = a_list_of_strings; cur; cur = cur->next) { ++ CRString *str = NULL; ++ ++ str = cr_string_dup ((CRString const *) cur->data) ; ++ if (str) ++ result = g_list_append (result, str); ++ } ++ ++ return result; ++} +diff --git a/src/st/croco/cr-utils.h b/src/st/croco/cr-utils.h +new file mode 100644 +index 000000000..54aa24973 +--- /dev/null ++++ b/src/st/croco/cr-utils.h +@@ -0,0 +1,246 @@ ++/* -*- Mode: C; indent-tabs-mode: nil; c-basic-offset: 8 -*- */ ++ ++/* ++ * This file is part of The Croco Library ++ * ++ * 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 ++ * Look at file COPYRIGHTS for copyright information ++ */ ++ ++#ifndef __CR_DEFS_H__ ++#define __CR_DEFS_H__ ++ ++#include ++#include ++#include "libcroco-config.h" ++ ++G_BEGIN_DECLS ++ ++/** ++ *@file ++ *The Croco library basic types definitions ++ *And global definitions. ++ */ ++ ++/** ++ *The status type returned ++ *by the methods of the croco library. ++ */ ++enum CRStatus { ++ CR_OK, ++ CR_BAD_PARAM_ERROR, ++ CR_INSTANCIATION_FAILED_ERROR, ++ CR_UNKNOWN_TYPE_ERROR, ++ CR_UNKNOWN_PROP_ERROR, ++ CR_UNKNOWN_PROP_VAL_ERROR, ++ CR_UNEXPECTED_POSITION_SCHEME, ++ CR_START_OF_INPUT_ERROR, ++ CR_END_OF_INPUT_ERROR, ++ CR_OUTPUT_TOO_SHORT_ERROR, ++ CR_INPUT_TOO_SHORT_ERROR, ++ CR_OUT_OF_BOUNDS_ERROR, ++ CR_EMPTY_PARSER_INPUT_ERROR, ++ CR_ENCODING_ERROR, ++ CR_ENCODING_NOT_FOUND_ERROR, ++ CR_PARSING_ERROR, ++ CR_SYNTAX_ERROR, ++ CR_NO_ROOT_NODE_ERROR, ++ CR_NO_TOKEN, ++ CR_OUT_OF_MEMORY_ERROR, ++ CR_PSEUDO_CLASS_SEL_HANDLER_NOT_FOUND_ERROR, ++ CR_BAD_PSEUDO_CLASS_SEL_HANDLER_ERROR, ++ CR_ERROR, ++ CR_FILE_NOT_FOUND_ERROR, ++ CR_VALUE_NOT_FOUND_ERROR ++} ; ++ ++/** ++ *Values used by ++ *cr_input_seek_position() ; ++ */ ++enum CRSeekPos { ++ CR_SEEK_CUR, ++ CR_SEEK_BEGIN, ++ CR_SEEK_END ++} ; ++ ++/** ++ *Encoding values. ++ */ ++enum CREncoding ++{ ++ CR_UCS_4 = 1/*Must be not NULL*/, ++ CR_UCS_1, ++ CR_ISO_8859_1, ++ CR_ASCII, ++ CR_UTF_8, ++ CR_UTF_16, ++ CR_AUTO/*should be the last one*/ ++} ; ++ ++ ++ ++ ++#define CROCO_LOG_DOMAIN "LIBCROCO" ++ ++#ifdef __GNUC__ ++#define cr_utils_trace(a_log_level, a_msg) \ ++g_log (CROCO_LOG_DOMAIN, \ ++ G_LOG_LEVEL_CRITICAL, \ ++ "file %s: line %d (%s): %s\n", \ ++ __FILE__, \ ++ __LINE__, \ ++ __PRETTY_FUNCTION__, \ ++ a_msg) ++#else /*__GNUC__*/ ++ ++#define cr_utils_trace(a_log_level, a_msg) \ ++g_log (CROCO_LOG_DOMAIN, \ ++ G_LOG_LEVEL_CRITICAL, \ ++ "file %s: line %d: %s\n", \ ++ __FILE__, \ ++ __LINE__, \ ++ a_msg) ++#endif ++ ++/** ++ *Traces an info message. ++ *The file, line and enclosing function ++ *of the message will be automatically ++ *added to the message. ++ *@param a_msg the msg to trace. ++ */ ++#define cr_utils_trace_info(a_msg) \ ++cr_utils_trace (G_LOG_LEVEL_INFO, a_msg) ++ ++/** ++ *Trace a debug message. ++ *The file, line and enclosing function ++ *of the message will be automatically ++ *added to the message. ++ *@param a_msg the msg to trace. ++ */ ++#define cr_utils_trace_debug(a_msg) \ ++cr_utils_trace (G_LOG_LEVEL_DEBUG, a_msg) ; ++ ++ ++/**************************** ++ *Encoding transformations and ++ *encoding helpers ++ ****************************/ ++ ++enum CRStatus ++cr_utils_read_char_from_utf8_buf (const guchar * a_in, gulong a_in_len, ++ guint32 *a_out, gulong *a_consumed) ; ++ ++enum CRStatus ++cr_utils_ucs1_to_utf8 (const guchar *a_in, gulong *a_in_len, ++ guchar *a_out, gulong *a_out_len) ; ++ ++enum CRStatus ++cr_utils_utf8_to_ucs1 (const guchar * a_in, gulong * a_in_len, ++ guchar *a_out, gulong *a_out_len) ; ++ ++enum CRStatus ++cr_utils_ucs4_to_utf8 (const guint32 *a_in, gulong *a_in_len, ++ guchar *a_out, gulong *a_out_len) ; ++ ++enum CRStatus ++cr_utils_utf8_str_len_as_ucs4 (const guchar *a_in_start, ++ const guchar *a_in_end, ++ gulong *a_len) ; ++enum CRStatus ++cr_utils_ucs1_str_len_as_utf8 (const guchar *a_in_start, ++ const guchar *a_in_end, ++ gulong *a_len) ; ++enum CRStatus ++cr_utils_utf8_str_len_as_ucs1 (const guchar *a_in_start, ++ const guchar *a_in_end, ++ gulong *a_len) ; ++enum CRStatus ++cr_utils_ucs4_str_len_as_utf8 (const guint32 *a_in_start, ++ const guint32 *a_in_end, ++ gulong *a_len) ; ++ ++enum CRStatus ++cr_utils_ucs1_str_to_utf8 (const guchar *a_in_start, ++ gulong *a_in_len, ++ guchar **a_out, ++ gulong *a_len) ; ++ ++enum CRStatus ++cr_utils_utf8_str_to_ucs1 (const guchar * a_in_start, ++ gulong * a_in_len, ++ guchar **a_out, ++ gulong *a_out_len) ; ++ ++enum CRStatus ++cr_utils_utf8_to_ucs4 (const guchar * a_in, ++ gulong * a_in_len, ++ guint32 *a_out, gulong *a_out_len) ; ++ ++enum CRStatus ++cr_utils_ucs4_str_to_utf8 (const guint32 *a_in, ++ gulong *a_in_len, ++ guchar **a_out, gulong *a_out_len) ; ++ ++enum CRStatus ++cr_utils_utf8_str_to_ucs4 (const guchar * a_in, ++ gulong *a_in_len, ++ guint32 **a_out, ++ gulong *a_out_len) ; ++ ++ ++/***************************************** ++ *CSS basic types identification utilities ++ *****************************************/ ++ ++gboolean ++cr_utils_is_newline (guint32 a_char) ; ++ ++gboolean ++cr_utils_is_white_space (guint32 a_char) ; ++ ++gboolean ++cr_utils_is_nonascii (guint32 a_char) ; ++ ++gboolean ++cr_utils_is_hexa_char (guint32 a_char) ; ++ ++ ++/********************************** ++ *Miscellaneous utility functions ++ ***********************************/ ++ ++void ++cr_utils_dump_n_chars (guchar a_char, ++ FILE *a_fp, ++ glong a_nb) ; ++ ++void ++cr_utils_dump_n_chars2 (guchar a_char, ++ GString *a_string, ++ glong a_nb) ; ++GList * ++cr_utils_dup_glist_of_string (GList const *a_list) ; ++ ++GList * ++cr_utils_dup_glist_of_cr_string (GList const * a_list_of_strings) ; ++ ++G_END_DECLS ++ ++#endif /*__CR_DEFS_H__*/ +diff --git a/src/st/croco/libcroco-config.h b/src/st/croco/libcroco-config.h +new file mode 100644 +index 000000000..1ffb758ea +--- /dev/null ++++ b/src/st/croco/libcroco-config.h +@@ -0,0 +1,13 @@ ++#ifndef LIBCROCO_VERSION_NUMBER ++#define LIBCROCO_VERSION_NUMBER 612 ++#endif ++ ++#ifndef LIBCROCO_VERSION ++#define LIBCROCO_VERSION "0.6.12" ++#endif ++ ++#ifndef G_DISABLE_CHECKS ++#if 0 ++#define G_DISABLE_CHECKS 0 ++#endif ++#endif +diff --git a/src/st/croco/libcroco.h b/src/st/croco/libcroco.h +new file mode 100644 +index 000000000..6187a7cb9 +--- /dev/null ++++ b/src/st/croco/libcroco.h +@@ -0,0 +1,42 @@ ++/* ++ * This file is part of The Croco Library ++ * ++ * Copyright (C) 2002-2003 Dodji Seketeli ++ * ++ * 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 ++ */ ++ ++#ifndef __LIBCROCO_H__ ++#define __LIBCROCO_H__ ++ ++#include "libcroco-config.h" ++ ++#include "cr-utils.h" ++#include "cr-pseudo.h" ++#include "cr-term.h" ++#include "cr-attr-sel.h" ++#include "cr-simple-sel.h" ++#include "cr-selector.h" ++#include "cr-enc-handler.h" ++#include "cr-doc-handler.h" ++#include "cr-input.h" ++#include "cr-parser.h" ++#include "cr-statement.h" ++#include "cr-stylesheet.h" ++#include "cr-om-parser.h" ++#include "cr-prop-list.h" ++#include "cr-string.h" ++ ++#endif /*__LIBCROCO_H__*/ +diff --git a/src/st/meson.build b/src/st/meson.build +index 97ce6134d..c1994755b 100644 +--- a/src/st/meson.build ++++ b/src/st/meson.build +@@ -1,3 +1,4 @@ ++# please, keep this sorted alphabetically + st_headers = [ + 'st-adjustment.h', + 'st-bin.h', +@@ -43,13 +44,68 @@ st_h = configure_file( + + st_inc = include_directories('.', '..') + ++# please, keep this sorted alphabetically + st_private_headers = [ ++ 'croco/cr-additional-sel.h', ++ 'croco/cr-attr-sel.h', ++ 'croco/cr-cascade.h', ++ 'croco/cr-declaration.h', ++ 'croco/cr-doc-handler.h', ++ 'croco/cr-enc-handler.h', ++ 'croco/cr-fonts.h', ++ 'croco/cr-input.h', ++ 'croco/cr-num.h', ++ 'croco/cr-om-parser.h', ++ 'croco/cr-parser.h', ++ 'croco/cr-parsing-location.h', ++ 'croco/cr-prop-list.h', ++ 'croco/cr-pseudo.h', ++ 'croco/cr-rgb.h', ++ 'croco/cr-selector.h', ++ 'croco/cr-simple-sel.h', ++ 'croco/cr-statement.h', ++ 'croco/cr-string.h', ++ 'croco/cr-stylesheet.h', ++ 'croco/cr-term.h', ++ 'croco/cr-tknzr.h', ++ 'croco/cr-token.h', ++ 'croco/cr-utils.h', ++ 'croco/libcroco-config.h', ++ 'croco/libcroco.h', + 'st-private.h', + 'st-theme-private.h', + 'st-theme-node-private.h', + 'st-theme-node-transition.h' + ] + ++# please, keep this sorted alphabetically ++croco_sources = [ ++ 'croco/cr-additional-sel.c', ++ 'croco/cr-attr-sel.c', ++ 'croco/cr-cascade.c', ++ 'croco/cr-declaration.c', ++ 'croco/cr-doc-handler.c', ++ 'croco/cr-enc-handler.c', ++ 'croco/cr-fonts.c', ++ 'croco/cr-input.c', ++ 'croco/cr-num.c', ++ 'croco/cr-om-parser.c', ++ 'croco/cr-parser.c', ++ 'croco/cr-parsing-location.c', ++ 'croco/cr-prop-list.c', ++ 'croco/cr-pseudo.c', ++ 'croco/cr-rgb.c', ++ 'croco/cr-selector.c', ++ 'croco/cr-simple-sel.c', ++ 'croco/cr-statement.c', ++ 'croco/cr-string.c', ++ 'croco/cr-stylesheet.c', ++ 'croco/cr-term.c', ++ 'croco/cr-tknzr.c', ++ 'croco/cr-token.c', ++ 'croco/cr-utils.c', ++] ++ + # please, keep this sorted alphabetically + st_sources = [ + 'st-adjustment.c', +@@ -119,9 +175,9 @@ st_cflags = [ + + # Currently meson requires a shared library for building girs + libst = shared_library('st-1.0', +- sources: st_gir_sources + st_non_gir_sources, ++ sources: st_gir_sources + st_non_gir_sources + croco_sources, + c_args: st_cflags, +- dependencies: [clutter_dep, gtk_dep, croco_dep, x11_dep, m_dep], ++ dependencies: [clutter_dep, gtk_dep, x11_dep, m_dep], + install_rpath: mutter_typelibdir, + install_dir: pkglibdir, + install: true +@@ -134,7 +190,7 @@ libst_dep = declare_dependency(link_with: libst, + test_theme = executable('test-theme', + sources: 'test-theme.c', + c_args: st_cflags, +- dependencies: [clutter_dep, gtk_dep], ++ dependencies: [clutter_dep, gtk_dep, libxml_dep], + link_with: libst + ) + +diff --git a/src/st/st-theme-node-private.h b/src/st/st-theme-node-private.h +index 2e6b232f6..659bc37ba 100644 +--- a/src/st/st-theme-node-private.h ++++ b/src/st/st-theme-node-private.h +@@ -25,7 +25,7 @@ + #include + + #include "st-theme-node.h" +-#include ++#include "croco/libcroco.h" + #include "st-types.h" + + G_BEGIN_DECLS +diff --git a/src/st/st-theme-private.h b/src/st/st-theme-private.h +index 08f3a1864..2083a7c84 100644 +--- a/src/st/st-theme-private.h ++++ b/src/st/st-theme-private.h +@@ -21,7 +21,7 @@ + #ifndef __ST_THEME_PRIVATE_H__ + #define __ST_THEME_PRIVATE_H__ + +-#include ++#include "croco/libcroco.h" + #include "st-theme.h" + + G_BEGIN_DECLS +-- +2.23.0 + diff --git a/gnome-shell.spec b/gnome-shell.spec index f0a8f25..e5d830b 100644 --- a/gnome-shell.spec +++ b/gnome-shell.spec @@ -1,6 +1,6 @@ Name: gnome-shell Version: 3.30.1 -Release: 5 +Release: 6 Summary: Core user interface functions for the GNOME 3 desktop Group: User Interface/Desktops License: GPLv2+ @@ -11,6 +11,7 @@ Patch1: gnome-shell-favourite-apps-firefox.patch Patch2: 0001-endSessionDialog-Immediately-add-buttons-to-the-dial.patch Patch3: 0002-endSessionDialog-Support-rebooting-into-the-bootload.patch Patch4: 0001-keyboardManager-Avoid-idempotent-calls-to-meta_backe.patch +Patch5: 0001-Include-the-libcroco-sources-directly-under-src-st-c.patch BuildRequires: meson git ibus-devel chrpath dbus-glib-devel desktop-file-utils BuildRequires: evolution-data-server-devel gcr-devel gjs-devel glib2-devel @@ -120,6 +121,10 @@ glib-compile-schemas --allow-any-name %{_datadir}/glib-2.0/schemas &> /dev/null %{_mandir}/man1/%{name}.1.gz %changelog +* Thu Dec 03 2020 wangxiao -3.30.1-6 +- move the libcroco sources directly under src/st + remove the libcroco dependency from the meson.build files + * Fri Dec 27 2019 Jiangping Hu - 3.30.1-5 - Type:bugfix - Id:NA -- Gitee From 9962d51a4108aed80352f8e7f292196bb4265369 Mon Sep 17 00:00:00 2001 From: small_leek Date: Fri, 4 Dec 2020 15:51:53 +0800 Subject: [PATCH 2/2] =?UTF-8?q?=E5=9B=9E=E9=80=80=20'Pull=20Request=20!6?= =?UTF-8?q?=20:=20Move=20the=20libcroco=20sources=20directly=20under=20src?= =?UTF-8?q?/st;=20remove=20the=20libcroco=20dependency=20from=20the=20meso?= =?UTF-8?q?n.build=20files'?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ...roco-sources-directly-under-src-st-c.patch | 25201 ---------------- gnome-shell.spec | 7 +- 2 files changed, 1 insertion(+), 25207 deletions(-) delete mode 100644 0001-Include-the-libcroco-sources-directly-under-src-st-c.patch diff --git a/0001-Include-the-libcroco-sources-directly-under-src-st-c.patch b/0001-Include-the-libcroco-sources-directly-under-src-st-c.patch deleted file mode 100644 index 2c7e2cf..0000000 --- a/0001-Include-the-libcroco-sources-directly-under-src-st-c.patch +++ /dev/null @@ -1,25201 +0,0 @@ -From 47758d16ff0acd9edbd8ff6eb3922e59fb14f8bb Mon Sep 17 00:00:00 2001 -From: Federico Mena Quintero -Date: Thu, 21 Nov 2019 14:24:02 -0600 -Subject: [PATCH] Include the libcroco sources directly under src/st/croco - -This is all of the original libcroco, minus these two which we don't use: - - - cr-sel-eng - the CSS selection engine for xmlNode. - - cr-style. - -Part of https://gitlab.gnome.org/GNOME/gnome-shell/issues/1934 ---- - meson.build | 2 - - src/st/croco/cr-additional-sel.c | 500 +++ - src/st/croco/cr-additional-sel.h | 98 + - src/st/croco/cr-attr-sel.c | 235 ++ - src/st/croco/cr-attr-sel.h | 74 + - src/st/croco/cr-cascade.c | 215 ++ - src/st/croco/cr-cascade.h | 74 + - src/st/croco/cr-declaration.c | 801 +++++ - src/st/croco/cr-declaration.h | 136 + - src/st/croco/cr-doc-handler.c | 276 ++ - src/st/croco/cr-doc-handler.h | 298 ++ - src/st/croco/cr-enc-handler.c | 184 ++ - src/st/croco/cr-enc-handler.h | 94 + - src/st/croco/cr-fonts.c | 949 ++++++ - src/st/croco/cr-fonts.h | 315 ++ - src/st/croco/cr-input.c | 1191 ++++++++ - src/st/croco/cr-input.h | 174 ++ - src/st/croco/cr-num.c | 313 ++ - src/st/croco/cr-num.h | 127 + - src/st/croco/cr-om-parser.c | 1142 +++++++ - src/st/croco/cr-om-parser.h | 98 + - src/st/croco/cr-parser.c | 4525 ++++++++++++++++++++++++++++ - src/st/croco/cr-parser.h | 128 + - src/st/croco/cr-parsing-location.c | 172 ++ - src/st/croco/cr-parsing-location.h | 70 + - src/st/croco/cr-prop-list.c | 404 +++ - src/st/croco/cr-prop-list.h | 80 + - src/st/croco/cr-pseudo.c | 167 + - src/st/croco/cr-pseudo.h | 64 + - src/st/croco/cr-rgb.c | 687 +++++ - src/st/croco/cr-rgb.h | 94 + - src/st/croco/cr-selector.c | 306 ++ - src/st/croco/cr-selector.h | 95 + - src/st/croco/cr-simple-sel.c | 325 ++ - src/st/croco/cr-simple-sel.h | 130 + - src/st/croco/cr-statement.c | 2794 +++++++++++++++++ - src/st/croco/cr-statement.h | 440 +++ - src/st/croco/cr-string.c | 168 ++ - src/st/croco/cr-string.h | 76 + - src/st/croco/cr-stylesheet.c | 178 ++ - src/st/croco/cr-stylesheet.h | 102 + - src/st/croco/cr-term.c | 790 +++++ - src/st/croco/cr-term.h | 190 ++ - src/st/croco/cr-tknzr.c | 2762 +++++++++++++++++ - src/st/croco/cr-tknzr.h | 115 + - src/st/croco/cr-token.c | 636 ++++ - src/st/croco/cr-token.h | 212 ++ - src/st/croco/cr-utils.c | 1330 ++++++++ - src/st/croco/cr-utils.h | 246 ++ - src/st/croco/libcroco-config.h | 13 + - src/st/croco/libcroco.h | 42 + - src/st/meson.build | 62 +- - src/st/st-theme-node-private.h | 2 +- - src/st/st-theme-private.h | 2 +- - 54 files changed, 24696 insertions(+), 7 deletions(-) - create mode 100644 src/st/croco/cr-additional-sel.c - create mode 100644 src/st/croco/cr-additional-sel.h - create mode 100644 src/st/croco/cr-attr-sel.c - create mode 100644 src/st/croco/cr-attr-sel.h - create mode 100644 src/st/croco/cr-cascade.c - create mode 100644 src/st/croco/cr-cascade.h - create mode 100644 src/st/croco/cr-declaration.c - create mode 100644 src/st/croco/cr-declaration.h - create mode 100644 src/st/croco/cr-doc-handler.c - create mode 100644 src/st/croco/cr-doc-handler.h - create mode 100644 src/st/croco/cr-enc-handler.c - create mode 100644 src/st/croco/cr-enc-handler.h - create mode 100644 src/st/croco/cr-fonts.c - create mode 100644 src/st/croco/cr-fonts.h - create mode 100644 src/st/croco/cr-input.c - create mode 100644 src/st/croco/cr-input.h - create mode 100644 src/st/croco/cr-num.c - create mode 100644 src/st/croco/cr-num.h - create mode 100644 src/st/croco/cr-om-parser.c - create mode 100644 src/st/croco/cr-om-parser.h - create mode 100644 src/st/croco/cr-parser.c - create mode 100644 src/st/croco/cr-parser.h - create mode 100644 src/st/croco/cr-parsing-location.c - create mode 100644 src/st/croco/cr-parsing-location.h - create mode 100644 src/st/croco/cr-prop-list.c - create mode 100644 src/st/croco/cr-prop-list.h - create mode 100644 src/st/croco/cr-pseudo.c - create mode 100644 src/st/croco/cr-pseudo.h - create mode 100644 src/st/croco/cr-rgb.c - create mode 100644 src/st/croco/cr-rgb.h - create mode 100644 src/st/croco/cr-selector.c - create mode 100644 src/st/croco/cr-selector.h - create mode 100644 src/st/croco/cr-simple-sel.c - create mode 100644 src/st/croco/cr-simple-sel.h - create mode 100644 src/st/croco/cr-statement.c - create mode 100644 src/st/croco/cr-statement.h - create mode 100644 src/st/croco/cr-string.c - create mode 100644 src/st/croco/cr-string.h - create mode 100644 src/st/croco/cr-stylesheet.c - create mode 100644 src/st/croco/cr-stylesheet.h - create mode 100644 src/st/croco/cr-term.c - create mode 100644 src/st/croco/cr-term.h - create mode 100644 src/st/croco/cr-tknzr.c - create mode 100644 src/st/croco/cr-tknzr.h - create mode 100644 src/st/croco/cr-token.c - create mode 100644 src/st/croco/cr-token.h - create mode 100644 src/st/croco/cr-utils.c - create mode 100644 src/st/croco/cr-utils.h - create mode 100644 src/st/croco/libcroco-config.h - create mode 100644 src/st/croco/libcroco.h - -diff --git a/meson.build b/meson.build -index bfe4ee8a6..9c6d5b946 100644 ---- a/meson.build -+++ b/meson.build -@@ -13,7 +13,6 @@ cogl_pc = 'mutter-cogl-' + mutter_api_version - cogl_pango_pc = 'mutter-cogl-pango-' + mutter_api_version - libmutter_pc = 'libmutter-' + mutter_api_version - --croco_req = '>= 0.6.8' - ecal_req = '>= 3.5.3' - eds_req = '>= 3.17.2' - gcr_req = '>= 3.7.5' -@@ -89,7 +88,6 @@ gio_unix_dep = dependency('gio-unix-2.0', version: gio_req) - gjs_dep = dependency('gjs-1.0', version: gjs_req) - gtk_dep = dependency('gtk+-3.0', version: gtk_req) - libxml_dep = dependency('libxml-2.0') --croco_dep = dependency('libcroco-0.6', version: croco_req) - clutter_dep = dependency(clutter_pc, version: mutter_req) - cogl_dep = dependency(cogl_pc, version: mutter_req) - cogl_pango_dep = dependency(cogl_pango_pc, version: mutter_req) -diff --git a/src/st/croco/cr-additional-sel.c b/src/st/croco/cr-additional-sel.c -new file mode 100644 -index 000000000..c34b8d243 ---- /dev/null -+++ b/src/st/croco/cr-additional-sel.c -@@ -0,0 +1,500 @@ -+/* -*- Mode: C; indent-tabs-mode:nil; c-basic-offset: 8-*- */ -+ -+/* -+ * This file is part of The Croco Library -+ * -+ * 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 -+ * See COPYRIGHTS file for copyright information. -+ * -+ */ -+ -+#include "cr-additional-sel.h" -+#include "string.h" -+ -+/** -+ * CRAdditionalSel: -+ * -+ * #CRAdditionalSel abstracts an additionnal selector. -+ * An additional selector is the selector part -+ * that comes after the combination of type selectors. -+ * It can be either "a class selector (the .class part), -+ * a pseudo class selector, an attribute selector -+ * or an id selector. -+ */ -+ -+/** -+ * cr_additional_sel_new: -+ * -+ * Default constructor of #CRAdditionalSel. -+ * Returns the newly build instance of #CRAdditionalSel. -+ */ -+CRAdditionalSel * -+cr_additional_sel_new (void) -+{ -+ CRAdditionalSel *result = NULL; -+ -+ result = g_try_malloc (sizeof (CRAdditionalSel)); -+ -+ if (result == NULL) { -+ cr_utils_trace_debug ("Out of memory"); -+ return NULL; -+ } -+ -+ memset (result, 0, sizeof (CRAdditionalSel)); -+ -+ return result; -+} -+ -+/** -+ * cr_additional_sel_new_with_type: -+ * @a_sel_type: the type of the newly built instance -+ * of #CRAdditionalSel. -+ * -+ * Constructor of #CRAdditionalSel. -+ * Returns the newly built instance of #CRAdditionalSel. -+ */ -+CRAdditionalSel * -+cr_additional_sel_new_with_type (enum AddSelectorType a_sel_type) -+{ -+ CRAdditionalSel *result = NULL; -+ -+ result = cr_additional_sel_new (); -+ -+ g_return_val_if_fail (result, NULL); -+ -+ result->type = a_sel_type; -+ -+ return result; -+} -+ -+/** -+ * cr_additional_sel_set_class_name: -+ * @a_this: the "this pointer" of the current instance -+ * of #CRAdditionalSel . -+ * @a_class_name: the new class name to set. -+ * -+ * Sets a new class name to a -+ * CLASS additional selector. -+ */ -+void -+cr_additional_sel_set_class_name (CRAdditionalSel * a_this, -+ CRString * a_class_name) -+{ -+ g_return_if_fail (a_this && a_this->type == CLASS_ADD_SELECTOR); -+ -+ if (a_this->content.class_name) { -+ cr_string_destroy (a_this->content.class_name); -+ } -+ -+ a_this->content.class_name = a_class_name; -+} -+ -+/** -+ * cr_additional_sel_set_id_name: -+ * @a_this: the "this pointer" of the current instance -+ * of #CRAdditionalSel . -+ * @a_id: the new id to set. -+ * -+ * Sets a new id name to an -+ * ID additional selector. -+ */ -+void -+cr_additional_sel_set_id_name (CRAdditionalSel * a_this, CRString * a_id) -+{ -+ g_return_if_fail (a_this && a_this->type == ID_ADD_SELECTOR); -+ -+ if (a_this->content.id_name) { -+ cr_string_destroy (a_this->content.id_name); -+ } -+ -+ a_this->content.id_name = a_id; -+} -+ -+/** -+ * cr_additional_sel_set_pseudo: -+ * @a_this: the "this pointer" of the current instance -+ * of #CRAdditionalSel . -+ * @a_pseudo: the new pseudo to set. -+ * -+ * Sets a new pseudo to a -+ * PSEUDO additional selector. -+ */ -+void -+cr_additional_sel_set_pseudo (CRAdditionalSel * a_this, CRPseudo * a_pseudo) -+{ -+ g_return_if_fail (a_this -+ && a_this->type == PSEUDO_CLASS_ADD_SELECTOR); -+ -+ if (a_this->content.pseudo) { -+ cr_pseudo_destroy (a_this->content.pseudo); -+ } -+ -+ a_this->content.pseudo = a_pseudo; -+} -+ -+/** -+ * cr_additional_sel_set_attr_sel: -+ * @a_this: the "this pointer" of the current instance -+ * of #CRAdditionalSel . -+ * @a_sel: the new instance of #CRAttrSel to set. -+ * -+ * Sets a new instance of #CRAttrSel to -+ * a ATTRIBUTE additional selector. -+ */ -+void -+cr_additional_sel_set_attr_sel (CRAdditionalSel * a_this, CRAttrSel * a_sel) -+{ -+ g_return_if_fail (a_this && a_this->type == ATTRIBUTE_ADD_SELECTOR); -+ -+ if (a_this->content.attr_sel) { -+ cr_attr_sel_destroy (a_this->content.attr_sel); -+ } -+ -+ a_this->content.attr_sel = a_sel; -+} -+ -+/** -+ * cr_additional_sel_append: -+ * @a_this: the "this pointer" of the current instance -+ * of #CRAdditionalSel . -+ * @a_sel: the new instance to #CRAdditional to append. -+ * -+ * Appends a new instance of #CRAdditional to the -+ * current list of #CRAdditional. -+ * -+ * Returns the new list of CRAdditionalSel or NULL if an error arises. -+ */ -+CRAdditionalSel * -+cr_additional_sel_append (CRAdditionalSel * a_this, CRAdditionalSel * a_sel) -+{ -+ CRAdditionalSel *cur_sel = NULL; -+ -+ g_return_val_if_fail (a_sel, NULL); -+ -+ if (a_this == NULL) { -+ return a_sel; -+ } -+ -+ if (a_sel == NULL) -+ return NULL; -+ -+ for (cur_sel = a_this; -+ cur_sel && cur_sel->next; cur_sel = cur_sel->next) ; -+ -+ g_return_val_if_fail (cur_sel != NULL, NULL); -+ -+ cur_sel->next = a_sel; -+ a_sel->prev = cur_sel; -+ -+ return a_this; -+} -+ -+/** -+ * cr_additional_sel_prepend: -+ * @a_this: the "this pointer" of the current instance -+ * of #CRAdditionalSel . -+ * @a_sel: the new instance to #CRAdditional to preappend. -+ * -+ * Preppends a new instance of #CRAdditional to the -+ * current list of #CRAdditional. -+ * -+ * Returns the new list of CRAdditionalSel or NULL if an error arises. -+ */ -+CRAdditionalSel * -+cr_additional_sel_prepend (CRAdditionalSel * a_this, CRAdditionalSel * a_sel) -+{ -+ g_return_val_if_fail (a_sel, NULL); -+ -+ if (a_this == NULL) { -+ return a_sel; -+ } -+ -+ a_sel->next = a_this; -+ a_this->prev = a_sel; -+ -+ return a_sel; -+} -+ -+guchar * -+cr_additional_sel_to_string (CRAdditionalSel const * a_this) -+{ -+ guchar *result = NULL; -+ GString *str_buf = NULL; -+ CRAdditionalSel const *cur = NULL; -+ -+ g_return_val_if_fail (a_this, NULL); -+ -+ str_buf = g_string_new (NULL); -+ -+ for (cur = a_this; cur; cur = cur->next) { -+ switch (cur->type) { -+ case CLASS_ADD_SELECTOR: -+ { -+ guchar *name = NULL; -+ -+ if (cur->content.class_name) { -+ name = (guchar *) g_strndup -+ (cur->content.class_name->stryng->str, -+ cur->content.class_name->stryng->len); -+ -+ if (name) { -+ g_string_append_printf -+ (str_buf, ".%s", -+ name); -+ g_free (name); -+ name = NULL; -+ } -+ } -+ } -+ break; -+ -+ case ID_ADD_SELECTOR: -+ { -+ guchar *name = NULL; -+ -+ if (cur->content.id_name) { -+ name = (guchar *) g_strndup -+ (cur->content.id_name->stryng->str, -+ cur->content.id_name->stryng->len); -+ -+ if (name) { -+ g_string_append_printf -+ (str_buf, "#%s", -+ name); -+ g_free (name); -+ name = NULL; -+ } -+ } -+ } -+ -+ break; -+ -+ case PSEUDO_CLASS_ADD_SELECTOR: -+ { -+ if (cur->content.pseudo) { -+ guchar *tmp_str = NULL; -+ -+ tmp_str = cr_pseudo_to_string -+ (cur->content.pseudo); -+ if (tmp_str) { -+ g_string_append_printf -+ (str_buf, ":%s", -+ tmp_str); -+ g_free (tmp_str); -+ tmp_str = NULL; -+ } -+ } -+ } -+ break; -+ -+ case ATTRIBUTE_ADD_SELECTOR: -+ if (cur->content.attr_sel) { -+ guchar *tmp_str = NULL; -+ -+ g_string_append_c (str_buf, '['); -+ tmp_str = cr_attr_sel_to_string -+ (cur->content.attr_sel); -+ if (tmp_str) { -+ g_string_append_printf -+ (str_buf, "%s]", tmp_str); -+ g_free (tmp_str); -+ tmp_str = NULL; -+ } -+ } -+ break; -+ -+ default: -+ break; -+ } -+ } -+ -+ if (str_buf) { -+ result = (guchar *) str_buf->str; -+ g_string_free (str_buf, FALSE); -+ str_buf = NULL; -+ } -+ -+ return result; -+} -+ -+guchar * -+cr_additional_sel_one_to_string (CRAdditionalSel const *a_this) -+{ -+ guchar *result = NULL; -+ GString *str_buf = NULL; -+ -+ g_return_val_if_fail (a_this, NULL) ; -+ -+ str_buf = g_string_new (NULL) ; -+ -+ switch (a_this->type) { -+ case CLASS_ADD_SELECTOR: -+ { -+ guchar *name = NULL; -+ -+ if (a_this->content.class_name) { -+ name = (guchar *) g_strndup -+ (a_this->content.class_name->stryng->str, -+ a_this->content.class_name->stryng->len); -+ -+ if (name) { -+ g_string_append_printf -+ (str_buf, ".%s", -+ name); -+ g_free (name); -+ name = NULL; -+ } -+ } -+ } -+ break; -+ -+ case ID_ADD_SELECTOR: -+ { -+ guchar *name = NULL; -+ -+ if (a_this->content.id_name) { -+ name = (guchar *) g_strndup -+ (a_this->content.id_name->stryng->str, -+ a_this->content.id_name->stryng->len); -+ -+ if (name) { -+ g_string_append_printf -+ (str_buf, "#%s", -+ name); -+ g_free (name); -+ name = NULL; -+ } -+ } -+ } -+ -+ break; -+ -+ case PSEUDO_CLASS_ADD_SELECTOR: -+ { -+ if (a_this->content.pseudo) { -+ guchar *tmp_str = NULL; -+ -+ tmp_str = cr_pseudo_to_string -+ (a_this->content.pseudo); -+ if (tmp_str) { -+ g_string_append_printf -+ (str_buf, ":%s", -+ tmp_str); -+ g_free (tmp_str); -+ tmp_str = NULL; -+ } -+ } -+ } -+ break; -+ -+ case ATTRIBUTE_ADD_SELECTOR: -+ if (a_this->content.attr_sel) { -+ guchar *tmp_str = NULL; -+ -+ g_string_append_printf (str_buf, "["); -+ tmp_str = cr_attr_sel_to_string -+ (a_this->content.attr_sel); -+ if (tmp_str) { -+ g_string_append_printf -+ (str_buf, "%s]", tmp_str); -+ g_free (tmp_str); -+ tmp_str = NULL; -+ } -+ } -+ break; -+ -+ default: -+ break; -+ } -+ -+ if (str_buf) { -+ result = (guchar *) str_buf->str; -+ g_string_free (str_buf, FALSE); -+ str_buf = NULL; -+ } -+ -+ return result; -+} -+ -+/** -+ * cr_additional_sel_dump: -+ * @a_this: the "this pointer" of the current instance of -+ * #CRAdditionalSel. -+ * @a_fp: the destination file. -+ * -+ * Dumps the current instance of #CRAdditionalSel to a file -+ */ -+void -+cr_additional_sel_dump (CRAdditionalSel const * a_this, FILE * a_fp) -+{ -+ guchar *tmp_str = NULL; -+ -+ g_return_if_fail (a_fp); -+ -+ if (a_this) { -+ tmp_str = cr_additional_sel_to_string (a_this); -+ if (tmp_str) { -+ fprintf (a_fp, "%s", tmp_str); -+ g_free (tmp_str); -+ tmp_str = NULL; -+ } -+ } -+} -+ -+/** -+ * cr_additional_sel_destroy: -+ * @a_this: the "this pointer" of the current instance -+ * of #CRAdditionalSel . -+ * -+ * Destroys an instance of #CRAdditional. -+ */ -+void -+cr_additional_sel_destroy (CRAdditionalSel * a_this) -+{ -+ g_return_if_fail (a_this); -+ -+ switch (a_this->type) { -+ case CLASS_ADD_SELECTOR: -+ cr_string_destroy (a_this->content.class_name); -+ a_this->content.class_name = NULL; -+ break; -+ -+ case PSEUDO_CLASS_ADD_SELECTOR: -+ cr_pseudo_destroy (a_this->content.pseudo); -+ a_this->content.pseudo = NULL; -+ break; -+ -+ case ID_ADD_SELECTOR: -+ cr_string_destroy (a_this->content.id_name); -+ a_this->content.id_name = NULL; -+ break; -+ -+ case ATTRIBUTE_ADD_SELECTOR: -+ cr_attr_sel_destroy (a_this->content.attr_sel); -+ a_this->content.attr_sel = NULL; -+ break; -+ -+ default: -+ break; -+ } -+ -+ if (a_this->next) { -+ cr_additional_sel_destroy (a_this->next); -+ } -+ -+ g_free (a_this); -+} -diff --git a/src/st/croco/cr-additional-sel.h b/src/st/croco/cr-additional-sel.h -new file mode 100644 -index 000000000..7ca3e07d5 ---- /dev/null -+++ b/src/st/croco/cr-additional-sel.h -@@ -0,0 +1,98 @@ -+/* -*- Mode: C; indent-tabs-mode:nil; c-basic-offset: 8-*- */ -+ -+/* -+ * This file is part of The Croco Library -+ * -+ * 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 -+ * See the COPYRIGHTS file for copyright information. -+ */ -+ -+ -+#ifndef __CR_ADD_SEL_H__ -+#define __CR_ADD_SEL_H__ -+ -+#include -+#include -+#include "cr-utils.h" -+#include "cr-attr-sel.h" -+#include "cr-pseudo.h" -+#include "cr-additional-sel.h" -+ -+G_BEGIN_DECLS -+ -+enum AddSelectorType -+{ -+ NO_ADD_SELECTOR = 0 , -+ CLASS_ADD_SELECTOR = 1 , -+ PSEUDO_CLASS_ADD_SELECTOR = 1 << 1, -+ ID_ADD_SELECTOR = 1 << 3, -+ ATTRIBUTE_ADD_SELECTOR = 1 << 4 -+} ; -+ -+union CRAdditionalSelectorContent -+{ -+ CRString *class_name ; -+ CRString *id_name ; -+ CRPseudo *pseudo ; -+ CRAttrSel *attr_sel ; -+} ; -+ -+typedef struct _CRAdditionalSel CRAdditionalSel ; -+ -+struct _CRAdditionalSel -+{ -+ enum AddSelectorType type ; -+ union CRAdditionalSelectorContent content ; -+ -+ CRAdditionalSel * next ; -+ CRAdditionalSel * prev ; -+ CRParsingLocation location ; -+} ; -+ -+CRAdditionalSel * cr_additional_sel_new (void) ; -+ -+CRAdditionalSel * cr_additional_sel_new_with_type (enum AddSelectorType a_sel_type) ; -+ -+CRAdditionalSel * cr_additional_sel_append (CRAdditionalSel *a_this, -+ CRAdditionalSel *a_sel) ; -+ -+void cr_additional_sel_set_class_name (CRAdditionalSel *a_this, -+ CRString *a_class_name) ; -+ -+void cr_additional_sel_set_id_name (CRAdditionalSel *a_this, -+ CRString *a_id) ; -+ -+void cr_additional_sel_set_pseudo (CRAdditionalSel *a_this, -+ CRPseudo *a_pseudo) ; -+ -+void cr_additional_sel_set_attr_sel (CRAdditionalSel *a_this, -+ CRAttrSel *a_sel) ; -+ -+CRAdditionalSel * cr_additional_sel_prepend (CRAdditionalSel *a_this, -+ CRAdditionalSel *a_sel) ; -+ -+guchar * cr_additional_sel_to_string (CRAdditionalSel const *a_this) ; -+ -+guchar * cr_additional_sel_one_to_string (CRAdditionalSel const *a_this) ; -+ -+void cr_additional_sel_dump (CRAdditionalSel const *a_this, FILE *a_fp) ; -+ -+void cr_additional_sel_destroy (CRAdditionalSel *a_this) ; -+ -+G_END_DECLS -+ -+#endif /*__CR_ADD_SEL_H*/ -diff --git a/src/st/croco/cr-attr-sel.c b/src/st/croco/cr-attr-sel.c -new file mode 100644 -index 000000000..c057bbbf6 ---- /dev/null -+++ b/src/st/croco/cr-attr-sel.c -@@ -0,0 +1,235 @@ -+/* -*- Mode: C; indent-tabs-mode:nil; c-basic-offset: 8-*- */ -+ -+/* -+ * This file is part of The Croco Library -+ * -+ * 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 -+ * -+ * See COPYRIGHTS file for copyrights information. -+ */ -+ -+#include -+#include "cr-attr-sel.h" -+ -+/** -+ * CRAttrSel: -+ * -+ * #CRAdditionalSel abstracts an attribute selector. -+ * Attributes selectors are described in the css2 spec [5.8]. -+ * There are more generally used in the css2 selectors described in -+ * css2 spec [5] . -+ */ -+ -+/** -+ * cr_attr_sel_new: -+ * The constructor of #CRAttrSel. -+ * Returns the newly allocated instance -+ * of #CRAttrSel. -+ */ -+CRAttrSel * -+cr_attr_sel_new (void) -+{ -+ CRAttrSel *result = NULL; -+ -+ result = g_malloc0 (sizeof (CRAttrSel)); -+ -+ return result; -+} -+ -+/** -+ * cr_attr_sel_append_attr_sel: -+ * @a_this: the this pointer of the current instance of #CRAttrSel. -+ * @a_attr_sel: selector to append. -+ * -+ * Appends an attribute selector to the current list of -+ * attribute selectors represented by a_this. -+ * Returns CR_OK upon successfull completion, an error code otherwise. -+ */ -+enum CRStatus -+cr_attr_sel_append_attr_sel (CRAttrSel * a_this, CRAttrSel * a_attr_sel) -+{ -+ CRAttrSel *cur_sel = NULL; -+ -+ g_return_val_if_fail (a_this && a_attr_sel, -+ CR_BAD_PARAM_ERROR); -+ -+ for (cur_sel = a_this; -+ cur_sel->next; -+ cur_sel = cur_sel->next) ; -+ -+ cur_sel->next = a_attr_sel; -+ a_attr_sel->prev = cur_sel; -+ -+ return CR_OK; -+} -+ -+/** -+ * cr_attr_sel_prepend_attr_sel: -+ *@a_this: the "this pointer" of the current instance *of #CRAttrSel. -+ *@a_attr_sel: the attribute selector to append. -+ * -+ *Prepends an attribute selector to the list of -+ *attributes selector represented by a_this. -+ *Returns CR_OK upon successfull completion, an error code otherwise. -+ */ -+enum CRStatus -+cr_attr_sel_prepend_attr_sel (CRAttrSel * a_this, -+ CRAttrSel * a_attr_sel) -+{ -+ g_return_val_if_fail (a_this && a_attr_sel, -+ CR_BAD_PARAM_ERROR); -+ -+ a_attr_sel->next = a_this; -+ a_this->prev = a_attr_sel; -+ -+ return CR_OK; -+} -+ -+/** -+ * cr_attr_sel_to_string: -+ * @a_this: the current instance of #CRAttrSel. -+ * -+ * Serializes an attribute selector into a string -+ * Returns the serialized attribute selector. -+ */ -+guchar * -+cr_attr_sel_to_string (CRAttrSel const * a_this) -+{ -+ CRAttrSel const *cur = NULL; -+ guchar *result = NULL; -+ GString *str_buf = NULL; -+ -+ g_return_val_if_fail (a_this, NULL); -+ -+ str_buf = g_string_new (NULL); -+ -+ for (cur = a_this; cur; cur = cur->next) { -+ if (cur->prev) { -+ g_string_append_c (str_buf, ' '); -+ } -+ -+ if (cur->name) { -+ guchar *name = NULL; -+ -+ name = (guchar *) g_strndup (cur->name->stryng->str, -+ cur->name->stryng->len); -+ if (name) { -+ g_string_append (str_buf, (const gchar *) name); -+ g_free (name); -+ name = NULL; -+ } -+ } -+ -+ if (cur->value) { -+ guchar *value = NULL; -+ -+ value = (guchar *) g_strndup (cur->value->stryng->str, -+ cur->value->stryng->len); -+ if (value) { -+ switch (cur->match_way) { -+ case SET: -+ break; -+ -+ case EQUALS: -+ g_string_append_c (str_buf, '='); -+ break; -+ -+ case INCLUDES: -+ g_string_append (str_buf, "~="); -+ break; -+ -+ case DASHMATCH: -+ g_string_append (str_buf, "|="); -+ break; -+ -+ default: -+ break; -+ } -+ -+ g_string_append_printf -+ (str_buf, "\"%s\"", value); -+ -+ g_free (value); -+ value = NULL; -+ } -+ } -+ } -+ -+ if (str_buf) { -+ result = (guchar *) str_buf->str; -+ g_string_free (str_buf, FALSE); -+ } -+ -+ return result; -+} -+ -+/** -+ * cr_attr_sel_dump: -+ * @a_this: the "this pointer" of the current instance of -+ * #CRAttrSel. -+ * @a_fp: the destination file. -+ * -+ * Dumps the current instance of #CRAttrSel to a file. -+ */ -+void -+cr_attr_sel_dump (CRAttrSel const * a_this, FILE * a_fp) -+{ -+ guchar *tmp_str = NULL; -+ -+ g_return_if_fail (a_this); -+ -+ tmp_str = cr_attr_sel_to_string (a_this); -+ -+ if (tmp_str) { -+ fprintf (a_fp, "%s", tmp_str); -+ g_free (tmp_str); -+ tmp_str = NULL; -+ } -+} -+ -+/** -+ *cr_attr_sel_destroy: -+ *@a_this: the "this pointer" of the current -+ *instance of #CRAttrSel. -+ * -+ *Destroys the current instance of #CRAttrSel. -+ *Frees all the fields if they are non null. -+ */ -+void -+cr_attr_sel_destroy (CRAttrSel * a_this) -+{ -+ g_return_if_fail (a_this); -+ -+ if (a_this->name) { -+ cr_string_destroy (a_this->name); -+ a_this->name = NULL; -+ } -+ -+ if (a_this->value) { -+ cr_string_destroy (a_this->value); -+ a_this->value = NULL; -+ } -+ -+ if (a_this->next) { -+ cr_attr_sel_destroy (a_this->next); -+ a_this->next = NULL; -+ } -+ -+ if (a_this) { -+ g_free (a_this); -+ a_this = NULL; -+ } -+} -+ -diff --git a/src/st/croco/cr-attr-sel.h b/src/st/croco/cr-attr-sel.h -new file mode 100644 -index 000000000..82d5a87d7 ---- /dev/null -+++ b/src/st/croco/cr-attr-sel.h -@@ -0,0 +1,74 @@ -+/* -*- Mode: C; indent-tabs-mode:nil; c-basic-offset: 8-*- */ -+ -+/* -+ * This file is part of The Croco Library -+ * -+ * 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 -+ * See COPYRIGHTS file for copyright information. -+ */ -+ -+#ifndef __CR_ATTR_SEL_H__ -+#define __CR_ATTR_SEL_H__ -+ -+#include -+#include -+#include "cr-utils.h" -+#include "cr-parsing-location.h" -+#include "cr-string.h" -+ -+G_BEGIN_DECLS -+ -+ -+struct _CRAttrSel ; -+typedef struct _CRAttrSel CRAttrSel ; -+ -+enum AttrMatchWay -+{ -+ NO_MATCH = 0, -+ SET, -+ EQUALS, -+ INCLUDES, -+ DASHMATCH -+} ; -+ -+struct _CRAttrSel -+{ -+ CRString *name ; -+ CRString *value ; -+ enum AttrMatchWay match_way ; -+ CRAttrSel *next ; -+ CRAttrSel *prev ; -+ CRParsingLocation location ; -+} ; -+ -+CRAttrSel * cr_attr_sel_new (void) ; -+ -+enum CRStatus cr_attr_sel_append_attr_sel (CRAttrSel * a_this, -+ CRAttrSel *a_attr_sel) ; -+ -+enum CRStatus cr_attr_sel_prepend_attr_sel (CRAttrSel *a_this, -+ CRAttrSel *a_attr_sel) ; -+ -+guchar * cr_attr_sel_to_string (CRAttrSel const *a_this) ; -+ -+void cr_attr_sel_dump (CRAttrSel const *a_this, FILE *a_fp) ; -+ -+void cr_attr_sel_destroy (CRAttrSel *a_this) ; -+ -+G_END_DECLS -+ -+#endif /*__CR_ATTR_SEL_H__*/ -diff --git a/src/st/croco/cr-cascade.c b/src/st/croco/cr-cascade.c -new file mode 100644 -index 000000000..b8f827716 ---- /dev/null -+++ b/src/st/croco/cr-cascade.c -@@ -0,0 +1,215 @@ -+/* -*- Mode: C; indent-tabs-mode:nil; c-basic-offset: 8-*- */ -+ -+/* -+ * This file is part of The Croco Library -+ * -+ * Copyright (C) 2002-2003 Dodji Seketeli -+ * -+ * 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 -+ */ -+ -+/* -+ *$Id$ -+ */ -+ -+#include -+#include "cr-cascade.h" -+ -+#define PRIVATE(a_this) ((a_this)->priv) -+ -+struct _CRCascadePriv { -+ /** -+ *the 3 style sheets of the cascade: -+ *author, user, and useragent sheet. -+ *Intended to be addressed by -+ *sheets[ORIGIN_AUTHOR] or sheets[ORIGIN_USER] -+ *of sheets[ORIGIN_UA] ; -+ */ -+ CRStyleSheet *sheets[3]; -+ guint ref_count; -+}; -+ -+/** -+ * cr_cascade_new: -+ *@a_author_sheet: the author origin style sheet. May be NULL. -+ *@a_user_sheet: the user origin style sheet. May be NULL. -+ *@a_ua_sheet: the user agent origin style sheet. May be NULL. -+ * -+ *Constructor of the #CRCascade class. -+ *Note that all three parameters of this -+ *method are ref counted and their refcount is increased. -+ *Their refcount will be decreased at the destruction of -+ *the instance of #CRCascade. -+ *So the caller should not call their destructor. The caller -+ *should call their ref/unref method instead if it wants -+ * -+ *Returns the newly built instance of CRCascade or NULL if -+ *an error arose during constrution. -+ */ -+CRCascade * -+cr_cascade_new (CRStyleSheet * a_author_sheet, -+ CRStyleSheet * a_user_sheet, CRStyleSheet * a_ua_sheet) -+{ -+ CRCascade *result = NULL; -+ -+ result = g_try_malloc (sizeof (CRCascade)); -+ if (!result) { -+ cr_utils_trace_info ("Out of memory"); -+ return NULL; -+ } -+ memset (result, 0, sizeof (CRCascade)); -+ -+ PRIVATE (result) = g_try_malloc (sizeof (CRCascadePriv)); -+ if (!PRIVATE (result)) { -+ cr_utils_trace_info ("Out of memory"); -+ g_free (result); -+ return NULL; -+ } -+ memset (PRIVATE (result), 0, sizeof (CRCascadePriv)); -+ -+ if (a_author_sheet) { -+ cr_cascade_set_sheet (result, a_author_sheet, ORIGIN_AUTHOR); -+ } -+ if (a_user_sheet) { -+ cr_cascade_set_sheet (result, a_user_sheet, ORIGIN_USER); -+ } -+ if (a_ua_sheet) { -+ cr_cascade_set_sheet (result, a_ua_sheet, ORIGIN_UA); -+ } -+ -+ return result; -+} -+ -+/** -+ * cr_cascade_get_sheet: -+ *@a_this: the current instance of #CRCascade. -+ *@a_origin: the origin of the style sheet as -+ *defined in the css2 spec in chapter 6.4. -+ *Gets a given origin sheet. -+ * -+ *Gets a sheet, part of the cascade. -+ *Note that the returned stylesheet -+ *is refcounted so if the caller wants -+ *to manage it's lifecycle, it must use -+ *cr_stylesheet_ref()/cr_stylesheet_unref() instead -+ *of the cr_stylesheet_destroy() method. -+ *Returns the style sheet, or NULL if it does not -+ *exist. -+ */ -+CRStyleSheet * -+cr_cascade_get_sheet (CRCascade * a_this, enum CRStyleOrigin a_origin) -+{ -+ g_return_val_if_fail (a_this -+ && a_origin >= ORIGIN_UA -+ && a_origin < NB_ORIGINS, NULL); -+ -+ return PRIVATE (a_this)->sheets[a_origin]; -+} -+ -+/** -+ * cr_cascade_set_sheet: -+ *@a_this: the current instance of #CRCascade. -+ *@a_sheet: the stylesheet to set. -+ *@a_origin: the origin of the stylesheet. -+ * -+ *Sets a stylesheet in the cascade -+ * -+ *Returns CR_OK upon successfull completion, an error -+ *code otherwise. -+ */ -+enum CRStatus -+cr_cascade_set_sheet (CRCascade * a_this, -+ CRStyleSheet * a_sheet, enum CRStyleOrigin a_origin) -+{ -+ g_return_val_if_fail (a_this -+ && a_sheet -+ && a_origin >= ORIGIN_UA -+ && a_origin < NB_ORIGINS, CR_BAD_PARAM_ERROR); -+ -+ if (PRIVATE (a_this)->sheets[a_origin]) -+ cr_stylesheet_unref (PRIVATE (a_this)->sheets[a_origin]); -+ PRIVATE (a_this)->sheets[a_origin] = a_sheet; -+ cr_stylesheet_ref (a_sheet); -+ a_sheet->origin = a_origin; -+ return CR_OK; -+} -+ -+/** -+ *cr_cascade_ref: -+ *@a_this: the current instance of #CRCascade -+ * -+ *Increases the reference counter of the current instance -+ *of #CRCascade. -+ */ -+void -+cr_cascade_ref (CRCascade * a_this) -+{ -+ g_return_if_fail (a_this && PRIVATE (a_this)); -+ -+ PRIVATE (a_this)->ref_count++; -+} -+ -+/** -+ * cr_cascade_unref: -+ *@a_this: the current instance of -+ *#CRCascade. -+ * -+ *Decrements the reference counter associated -+ *to this instance of #CRCascade. If the reference -+ *counter reaches zero, the instance is destroyed -+ *using cr_cascade_destroy() -+ */ -+void -+cr_cascade_unref (CRCascade * a_this) -+{ -+ g_return_if_fail (a_this && PRIVATE (a_this)); -+ -+ if (PRIVATE (a_this)->ref_count) -+ PRIVATE (a_this)->ref_count--; -+ if (!PRIVATE (a_this)->ref_count) { -+ cr_cascade_destroy (a_this); -+ } -+} -+ -+/** -+ * cr_cascade_destroy: -+ * @a_this: the current instance of #CRCascade -+ * -+ * Destructor of #CRCascade. -+ */ -+void -+cr_cascade_destroy (CRCascade * a_this) -+{ -+ g_return_if_fail (a_this); -+ -+ if (PRIVATE (a_this)) { -+ gulong i = 0; -+ -+ for (i = 0; PRIVATE (a_this)->sheets && i < NB_ORIGINS; i++) { -+ if (PRIVATE (a_this)->sheets[i]) { -+ if (cr_stylesheet_unref -+ (PRIVATE (a_this)->sheets[i]) -+ == TRUE) { -+ PRIVATE (a_this)->sheets[i] = NULL; -+ } -+ } -+ } -+ g_free (PRIVATE (a_this)); -+ PRIVATE (a_this) = NULL; -+ } -+ g_free (a_this); -+} -diff --git a/src/st/croco/cr-cascade.h b/src/st/croco/cr-cascade.h -new file mode 100644 -index 000000000..3119ae85f ---- /dev/null -+++ b/src/st/croco/cr-cascade.h -@@ -0,0 +1,74 @@ -+/* -*- Mode: C; indent-tabs-mode:nil; c-basic-offset: 8-*- */ -+ -+/* -+ * This file is part of The Croco Library -+ * -+ * 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 -+ * -+ */ -+ -+/* -+ *$Id$ -+ */ -+ -+#ifndef __CR_CASCADE_H__ -+#define __CR_CASCADE_H__ -+ -+#include "cr-stylesheet.h" -+ -+/** -+ *@file -+ *the declaration of the #CRCascade class. -+ */ -+ -+G_BEGIN_DECLS -+ -+ -+typedef struct _CRCascadePriv CRCascadePriv ; -+ -+/** -+ *An abstraction of the "Cascade" defined -+ *in the css2 spec, chapter 6.4. -+ */ -+typedef struct _CRCascade CRCascade ; -+ -+struct _CRCascade -+{ -+ CRCascadePriv *priv ; -+}; -+ -+ -+CRCascade * cr_cascade_new (CRStyleSheet *a_author_sheet, -+ CRStyleSheet *a_user_sheet, -+ CRStyleSheet *a_ua_sheet) ; -+ -+CRStyleSheet * cr_cascade_get_sheet (CRCascade *a_this, -+ enum CRStyleOrigin a_origin) ; -+ -+enum CRStatus cr_cascade_set_sheet (CRCascade *a_this, -+ CRStyleSheet *a_sheet, -+ enum CRStyleOrigin a_origin) ; -+ -+void cr_cascade_ref (CRCascade *a_this) ; -+ -+void cr_cascade_unref (CRCascade *a_this) ; -+ -+void cr_cascade_destroy (CRCascade *a_this) ; -+ -+G_END_DECLS -+ -+#endif /*__CR_CASCADE_H__*/ -diff --git a/src/st/croco/cr-declaration.c b/src/st/croco/cr-declaration.c -new file mode 100644 -index 000000000..2a13c8266 ---- /dev/null -+++ b/src/st/croco/cr-declaration.c -@@ -0,0 +1,801 @@ -+/* -*- Mode: C; indent-tabs-mode: nil; c-basic-offset: 8 -*- */ -+ -+/* -+ * This file is part of The Croco Library -+ * -+ * 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. -+ * See COPYRIGHTS file for copyright information. -+ */ -+ -+ -+#include -+#include "cr-declaration.h" -+#include "cr-statement.h" -+#include "cr-parser.h" -+ -+/** -+ *@CRDeclaration: -+ * -+ *The definition of the #CRDeclaration class. -+ */ -+ -+/** -+ * dump: -+ *@a_this: the current instance of #CRDeclaration. -+ *@a_fp: the destination file pointer. -+ *@a_indent: the number of indentation white char. -+ * -+ *Dumps (serializes) one css declaration to a file. -+ */ -+static void -+dump (CRDeclaration const * a_this, FILE * a_fp, glong a_indent) -+{ -+ guchar *str = NULL; -+ -+ g_return_if_fail (a_this); -+ -+ str = (guchar *) cr_declaration_to_string (a_this, a_indent); -+ if (str) { -+ fprintf (a_fp, "%s", str); -+ g_free (str); -+ str = NULL; -+ } -+} -+ -+/** -+ * cr_declaration_new: -+ * @a_statement: the statement this declaration belongs to. can be NULL. -+ *@a_property: the property string of the declaration -+ *@a_value: the value expression of the declaration. -+ *Constructor of #CRDeclaration. -+ * -+ *Returns the newly built instance of #CRDeclaration, or NULL in -+ *case of error. -+ * -+ *The returned CRDeclaration takes ownership of @a_property and @a_value. -+ *(E.g. cr_declaration_destroy on this CRDeclaration will also free -+ *@a_property and @a_value.) -+ */ -+CRDeclaration * -+cr_declaration_new (CRStatement * a_statement, -+ CRString * a_property, CRTerm * a_value) -+{ -+ CRDeclaration *result = NULL; -+ -+ g_return_val_if_fail (a_property, NULL); -+ -+ if (a_statement) -+ g_return_val_if_fail (a_statement -+ && ((a_statement->type == RULESET_STMT) -+ || (a_statement->type -+ == AT_FONT_FACE_RULE_STMT) -+ || (a_statement->type -+ == AT_PAGE_RULE_STMT)), NULL); -+ -+ result = g_try_malloc (sizeof (CRDeclaration)); -+ if (!result) { -+ cr_utils_trace_info ("Out of memory"); -+ return NULL; -+ } -+ memset (result, 0, sizeof (CRDeclaration)); -+ result->property = a_property; -+ result->value = a_value; -+ -+ if (a_value) { -+ cr_term_ref (a_value); -+ } -+ result->parent_statement = a_statement; -+ return result; -+} -+ -+/** -+ * cr_declaration_parse_from_buf: -+ *@a_statement: the parent css2 statement of this -+ *this declaration. Must be non NULL and of type -+ *RULESET_STMT (must be a ruleset). -+ *@a_str: the string that contains the statement. -+ *@a_enc: the encoding of a_str. -+ * -+ *Parses a text buffer that contains -+ *a css declaration. -+ *Returns the parsed declaration, or NULL in case of error. -+ */ -+CRDeclaration * -+cr_declaration_parse_from_buf (CRStatement * a_statement, -+ const guchar * a_str, enum CREncoding a_enc) -+{ -+ enum CRStatus status = CR_OK; -+ CRTerm *value = NULL; -+ CRString *property = NULL; -+ CRDeclaration *result = NULL; -+ CRParser *parser = NULL; -+ gboolean important = FALSE; -+ -+ g_return_val_if_fail (a_str, NULL); -+ if (a_statement) -+ g_return_val_if_fail (a_statement->type == RULESET_STMT, -+ NULL); -+ -+ parser = cr_parser_new_from_buf ((guchar*)a_str, strlen ((const char *) a_str), a_enc, FALSE); -+ g_return_val_if_fail (parser, NULL); -+ -+ status = cr_parser_try_to_skip_spaces_and_comments (parser); -+ if (status != CR_OK) -+ goto cleanup; -+ -+ status = cr_parser_parse_declaration (parser, &property, -+ &value, &important); -+ if (status != CR_OK || !property) -+ goto cleanup; -+ -+ result = cr_declaration_new (a_statement, property, value); -+ if (result) { -+ property = NULL; -+ value = NULL; -+ result->important = important; -+ } -+ -+ cleanup: -+ -+ if (parser) { -+ cr_parser_destroy (parser); -+ parser = NULL; -+ } -+ -+ if (property) { -+ cr_string_destroy (property); -+ property = NULL; -+ } -+ -+ if (value) { -+ cr_term_destroy (value); -+ value = NULL; -+ } -+ -+ return result; -+} -+ -+/** -+ * cr_declaration_parse_list_from_buf: -+ *@a_str: the input buffer that contains the list of declaration to -+ *parse. -+ *@a_enc: the encoding of a_str -+ * -+ *Parses a ';' separated list of properties declaration. -+ *Returns the parsed list of declaration, NULL if parsing failed. -+ */ -+CRDeclaration * -+cr_declaration_parse_list_from_buf (const guchar * a_str, -+ enum CREncoding a_enc) -+{ -+ -+ enum CRStatus status = CR_OK; -+ CRTerm *value = NULL; -+ CRString *property = NULL; -+ CRDeclaration *result = NULL, -+ *cur_decl = NULL; -+ CRParser *parser = NULL; -+ CRTknzr *tokenizer = NULL; -+ gboolean important = FALSE; -+ -+ g_return_val_if_fail (a_str, NULL); -+ -+ parser = cr_parser_new_from_buf ((guchar*)a_str, strlen ((const char *) a_str), a_enc, FALSE); -+ g_return_val_if_fail (parser, NULL); -+ status = cr_parser_get_tknzr (parser, &tokenizer); -+ if (status != CR_OK || !tokenizer) { -+ if (status == CR_OK) -+ status = CR_ERROR; -+ goto cleanup; -+ } -+ status = cr_parser_try_to_skip_spaces_and_comments (parser); -+ if (status != CR_OK) -+ goto cleanup; -+ -+ status = cr_parser_parse_declaration (parser, &property, -+ &value, &important); -+ if (status != CR_OK || !property) { -+ if (status != CR_OK) -+ status = CR_ERROR; -+ goto cleanup; -+ } -+ result = cr_declaration_new (NULL, property, value); -+ if (result) { -+ property = NULL; -+ value = NULL; -+ result->important = important; -+ } -+ /*now, go parse the other declarations */ -+ for (;;) { -+ guint32 c = 0; -+ -+ cr_parser_try_to_skip_spaces_and_comments (parser); -+ status = cr_tknzr_peek_char (tokenizer, &c); -+ if (status != CR_OK) { -+ if (status == CR_END_OF_INPUT_ERROR) -+ status = CR_OK; -+ goto cleanup; -+ } -+ if (c == ';') { -+ status = cr_tknzr_read_char (tokenizer, &c); -+ } else { -+ break; -+ } -+ important = FALSE; -+ cr_parser_try_to_skip_spaces_and_comments (parser); -+ status = cr_parser_parse_declaration (parser, &property, -+ &value, &important); -+ if (status != CR_OK || !property) { -+ if (status == CR_END_OF_INPUT_ERROR) { -+ status = CR_OK; -+ } -+ break; -+ } -+ cur_decl = cr_declaration_new (NULL, property, value); -+ if (cur_decl) { -+ cur_decl->important = important; -+ result = cr_declaration_append (result, cur_decl); -+ property = NULL; -+ value = NULL; -+ cur_decl = NULL; -+ } else { -+ break; -+ } -+ } -+ -+ cleanup: -+ -+ if (parser) { -+ cr_parser_destroy (parser); -+ parser = NULL; -+ } -+ -+ if (property) { -+ cr_string_destroy (property); -+ property = NULL; -+ } -+ -+ if (value) { -+ cr_term_destroy (value); -+ value = NULL; -+ } -+ -+ if (status != CR_OK && result) { -+ cr_declaration_destroy (result); -+ result = NULL; -+ } -+ return result; -+} -+ -+/** -+ * cr_declaration_append: -+ *@a_this: the current declaration list. -+ *@a_new: the declaration to append. -+ * -+ *Appends a new declaration to the current declarations list. -+ *Returns the declaration list with a_new appended to it, or NULL -+ *in case of error. -+ */ -+CRDeclaration * -+cr_declaration_append (CRDeclaration * a_this, CRDeclaration * a_new) -+{ -+ CRDeclaration *cur = NULL; -+ -+ g_return_val_if_fail (a_new, NULL); -+ -+ if (!a_this) -+ return a_new; -+ -+ for (cur = a_this; cur && cur->next; cur = cur->next) ; -+ -+ cur->next = a_new; -+ a_new->prev = cur; -+ -+ return a_this; -+} -+ -+/** -+ * cr_declaration_unlink: -+ *@a_decls: the declaration to unlink. -+ * -+ *Unlinks the declaration from the declaration list. -+ *case of a successfull completion, NULL otherwise. -+ * -+ *Returns a pointer to the unlinked declaration in -+ */ -+CRDeclaration * -+cr_declaration_unlink (CRDeclaration * a_decl) -+{ -+ CRDeclaration *result = a_decl; -+ -+ g_return_val_if_fail (result, NULL); -+ -+ /* -+ *some sanity checks first -+ */ -+ if (a_decl->prev) { -+ g_return_val_if_fail (a_decl->prev->next == a_decl, NULL); -+ -+ } -+ if (a_decl->next) { -+ g_return_val_if_fail (a_decl->next->prev == a_decl, NULL); -+ } -+ -+ /* -+ *now, the real unlinking job. -+ */ -+ if (a_decl->prev) { -+ a_decl->prev->next = a_decl->next; -+ } -+ if (a_decl->next) { -+ a_decl->next->prev = a_decl->prev; -+ } -+ if (a_decl->parent_statement) { -+ CRDeclaration **children_decl_ptr = NULL; -+ -+ switch (a_decl->parent_statement->type) { -+ case RULESET_STMT: -+ if (a_decl->parent_statement->kind.ruleset) { -+ children_decl_ptr = -+ &a_decl->parent_statement-> -+ kind.ruleset->decl_list; -+ } -+ -+ break; -+ -+ case AT_FONT_FACE_RULE_STMT: -+ if (a_decl->parent_statement->kind.font_face_rule) { -+ children_decl_ptr = -+ &a_decl->parent_statement-> -+ kind.font_face_rule->decl_list; -+ } -+ break; -+ case AT_PAGE_RULE_STMT: -+ if (a_decl->parent_statement->kind.page_rule) { -+ children_decl_ptr = -+ &a_decl->parent_statement-> -+ kind.page_rule->decl_list; -+ } -+ -+ default: -+ break; -+ } -+ if (children_decl_ptr -+ && *children_decl_ptr && *children_decl_ptr == a_decl) -+ *children_decl_ptr = (*children_decl_ptr)->next; -+ } -+ -+ a_decl->next = NULL; -+ a_decl->prev = NULL; -+ a_decl->parent_statement = NULL; -+ -+ return result; -+} -+ -+/** -+ * cr_declaration_prepend: -+ * @a_this: the current declaration list. -+ * @a_new: the declaration to prepend. -+ * -+ * prepends a declaration to the current declaration list. -+ * -+ * Returns the list with a_new prepended or NULL in case of error. -+ */ -+CRDeclaration * -+cr_declaration_prepend (CRDeclaration * a_this, CRDeclaration * a_new) -+{ -+ CRDeclaration *cur = NULL; -+ -+ g_return_val_if_fail (a_new, NULL); -+ -+ if (!a_this) -+ return a_new; -+ -+ a_this->prev = a_new; -+ a_new->next = a_this; -+ -+ for (cur = a_new; cur && cur->prev; cur = cur->prev) ; -+ -+ return cur; -+} -+ -+/** -+ * cr_declaration_append2: -+ *@a_this: the current declaration list. -+ *@a_prop: the property string of the declaration to append. -+ *@a_value: the value of the declaration to append. -+ * -+ *Appends a declaration to the current declaration list. -+ *Returns the list with the new property appended to it, or NULL in -+ *case of an error. -+ */ -+CRDeclaration * -+cr_declaration_append2 (CRDeclaration * a_this, -+ CRString * a_prop, CRTerm * a_value) -+{ -+ CRDeclaration *new_elem = NULL; -+ -+ if (a_this) { -+ new_elem = cr_declaration_new (a_this->parent_statement, -+ a_prop, a_value); -+ } else { -+ new_elem = cr_declaration_new (NULL, a_prop, a_value); -+ } -+ -+ g_return_val_if_fail (new_elem, NULL); -+ -+ return cr_declaration_append (a_this, new_elem); -+} -+ -+/** -+ * cr_declaration_dump: -+ *@a_this: the current instance of #CRDeclaration. -+ *@a_fp: the destination file. -+ *@a_indent: the number of indentation white char. -+ *@a_one_per_line: whether to put one declaration per line of not . -+ * -+ * -+ *Dumps a declaration list to a file. -+ */ -+void -+cr_declaration_dump (CRDeclaration const * a_this, FILE * a_fp, glong a_indent, -+ gboolean a_one_per_line) -+{ -+ CRDeclaration const *cur = NULL; -+ -+ g_return_if_fail (a_this); -+ -+ for (cur = a_this; cur; cur = cur->next) { -+ if (cur->prev) { -+ if (a_one_per_line == TRUE) -+ fprintf (a_fp, ";\n"); -+ else -+ fprintf (a_fp, "; "); -+ } -+ dump (cur, a_fp, a_indent); -+ } -+} -+ -+/** -+ * cr_declaration_dump_one: -+ *@a_this: the current instance of #CRDeclaration. -+ *@a_fp: the destination file. -+ *@a_indent: the number of indentation white char. -+ * -+ *Dumps the first declaration of the declaration list to a file. -+ */ -+void -+cr_declaration_dump_one (CRDeclaration const * a_this, FILE * a_fp, glong a_indent) -+{ -+ g_return_if_fail (a_this); -+ -+ dump (a_this, a_fp, a_indent); -+} -+ -+/** -+ * cr_declaration_to_string: -+ *@a_this: the current instance of #CRDeclaration. -+ *@a_indent: the number of indentation white char -+ *to put before the actual serialisation. -+ * -+ *Serializes the declaration into a string -+ *Returns the serialized form the declaration. The caller must -+ *free the string using g_free(). -+ */ -+gchar * -+cr_declaration_to_string (CRDeclaration const * a_this, gulong a_indent) -+{ -+ GString *stringue = NULL; -+ -+ gchar *str = NULL, -+ *result = NULL; -+ -+ g_return_val_if_fail (a_this, NULL); -+ -+ stringue = g_string_new (NULL); -+ -+ if (a_this->property -+ && a_this->property->stryng -+ && a_this->property->stryng->str) { -+ str = g_strndup (a_this->property->stryng->str, -+ a_this->property->stryng->len); -+ if (str) { -+ cr_utils_dump_n_chars2 (' ', stringue, -+ a_indent); -+ g_string_append (stringue, str); -+ g_free (str); -+ str = NULL; -+ } else -+ goto error; -+ -+ if (a_this->value) { -+ guchar *value_str = NULL; -+ -+ value_str = cr_term_to_string (a_this->value); -+ if (value_str) { -+ g_string_append_printf (stringue, " : %s", -+ value_str); -+ g_free (value_str); -+ } else -+ goto error; -+ } -+ if (a_this->important == TRUE) { -+ g_string_append_printf (stringue, " %s", -+ "!important"); -+ } -+ } -+ if (stringue && stringue->str) { -+ result = stringue->str; -+ g_string_free (stringue, FALSE); -+ } -+ return result; -+ -+ error: -+ if (stringue) { -+ g_string_free (stringue, TRUE); -+ stringue = NULL; -+ } -+ if (str) { -+ g_free (str); -+ str = NULL; -+ } -+ -+ return result; -+} -+ -+/** -+ * cr_declaration_list_to_string: -+ *@a_this: the current instance of #CRDeclaration. -+ *@a_indent: the number of indentation white char -+ *to put before the actual serialisation. -+ * -+ *Serializes the declaration list into a string -+ */ -+guchar * -+cr_declaration_list_to_string (CRDeclaration const * a_this, gulong a_indent) -+{ -+ CRDeclaration const *cur = NULL; -+ GString *stringue = NULL; -+ guchar *str = NULL, -+ *result = NULL; -+ -+ g_return_val_if_fail (a_this, NULL); -+ -+ stringue = g_string_new (NULL); -+ -+ for (cur = a_this; cur; cur = cur->next) { -+ str = (guchar *) cr_declaration_to_string (cur, a_indent); -+ if (str) { -+ g_string_append_printf (stringue, "%s;", str); -+ g_free (str); -+ } else -+ break; -+ } -+ if (stringue && stringue->str) { -+ result = (guchar *) stringue->str; -+ g_string_free (stringue, FALSE); -+ } -+ -+ return result; -+} -+ -+/** -+ * cr_declaration_list_to_string2: -+ *@a_this: the current instance of #CRDeclaration. -+ *@a_indent: the number of indentation white char -+ *@a_one_decl_per_line: whether to output one doc per line or not. -+ *to put before the actual serialisation. -+ * -+ *Serializes the declaration list into a string -+ *Returns the serialized form the declararation. -+ */ -+guchar * -+cr_declaration_list_to_string2 (CRDeclaration const * a_this, -+ gulong a_indent, gboolean a_one_decl_per_line) -+{ -+ CRDeclaration const *cur = NULL; -+ GString *stringue = NULL; -+ guchar *str = NULL, -+ *result = NULL; -+ -+ g_return_val_if_fail (a_this, NULL); -+ -+ stringue = g_string_new (NULL); -+ -+ for (cur = a_this; cur; cur = cur->next) { -+ str = (guchar *) cr_declaration_to_string (cur, a_indent); -+ if (str) { -+ if (a_one_decl_per_line == TRUE) { -+ if (cur->next) -+ g_string_append_printf (stringue, -+ "%s;\n", str); -+ else -+ g_string_append (stringue, -+ (const gchar *) str); -+ } else { -+ if (cur->next) -+ g_string_append_printf (stringue, -+ "%s;", str); -+ else -+ g_string_append (stringue, -+ (const gchar *) str); -+ } -+ g_free (str); -+ } else -+ break; -+ } -+ if (stringue && stringue->str) { -+ result = (guchar *) stringue->str; -+ g_string_free (stringue, FALSE); -+ } -+ -+ return result; -+} -+ -+/** -+ * cr_declaration_nr_props: -+ *@a_this: the current instance of #CRDeclaration. -+ *Return the number of properties in the declaration -+ */ -+gint -+cr_declaration_nr_props (CRDeclaration const * a_this) -+{ -+ CRDeclaration 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_declaration_get_from_list: -+ *@a_this: the current instance of #CRDeclaration. -+ *@itemnr: the index into the declaration list. -+ * -+ *Use an index to get a CRDeclaration from the declaration list. -+ * -+ *Returns #CRDeclaration at position itemnr, -+ *if itemnr > number of declarations - 1, -+ *it will return NULL. -+ */ -+CRDeclaration * -+cr_declaration_get_from_list (CRDeclaration * a_this, int itemnr) -+{ -+ CRDeclaration *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_declaration_get_by_prop_name: -+ *@a_this: the current instance of #CRDeclaration. -+ *@a_prop: the property name to search for. -+ * -+ *Use property name to get a CRDeclaration from the declaration list. -+ *Returns #CRDeclaration with property name a_prop, or NULL if not found. -+ */ -+CRDeclaration * -+cr_declaration_get_by_prop_name (CRDeclaration * a_this, -+ const guchar * a_prop) -+{ -+ CRDeclaration *cur = NULL; -+ -+ g_return_val_if_fail (a_this, NULL); -+ g_return_val_if_fail (a_prop, NULL); -+ -+ for (cur = a_this; cur; cur = cur->next) { -+ if (cur->property -+ && cur->property->stryng -+ && cur->property->stryng->str) { -+ if (!strcmp (cur->property->stryng->str, -+ (const char *) a_prop)) { -+ return cur; -+ } -+ } -+ } -+ return NULL; -+} -+ -+/** -+ * cr_declaration_ref: -+ *@a_this: the current instance of #CRDeclaration. -+ * -+ *Increases the ref count of the current instance of #CRDeclaration. -+ */ -+void -+cr_declaration_ref (CRDeclaration * a_this) -+{ -+ g_return_if_fail (a_this); -+ -+ a_this->ref_count++; -+} -+ -+/** -+ * cr_declaration_unref: -+ *@a_this: the current instance of #CRDeclaration. -+ * -+ *Decrements the ref count of the current instance of #CRDeclaration. -+ *If the ref count reaches zero, the current instance of #CRDeclaration -+ *if destroyed. -+ *Returns TRUE if @a_this was destroyed (ref count reached zero), -+ *FALSE otherwise. -+ */ -+gboolean -+cr_declaration_unref (CRDeclaration * a_this) -+{ -+ g_return_val_if_fail (a_this, FALSE); -+ -+ if (a_this->ref_count) { -+ a_this->ref_count--; -+ } -+ -+ if (a_this->ref_count == 0) { -+ cr_declaration_destroy (a_this); -+ return TRUE; -+ } -+ return FALSE; -+} -+ -+/** -+ * cr_declaration_destroy: -+ *@a_this: the current instance of #CRDeclaration. -+ * -+ *Destructor of the declaration list. -+ */ -+void -+cr_declaration_destroy (CRDeclaration * a_this) -+{ -+ CRDeclaration *cur = NULL; -+ -+ g_return_if_fail (a_this); -+ -+ /* -+ * Go to the last element of the list. -+ */ -+ for (cur = a_this; cur->next; cur = cur->next) -+ g_assert (cur->next->prev == cur); -+ -+ /* -+ * Walk backward the list and free each "next" element. -+ * Meanwhile, free each property/value pair contained in the list. -+ */ -+ for (; cur; cur = cur->prev) { -+ g_free (cur->next); -+ cur->next = NULL; -+ -+ if (cur->property) { -+ cr_string_destroy (cur->property); -+ cur->property = NULL; -+ } -+ -+ if (cur->value) { -+ cr_term_destroy (cur->value); -+ cur->value = NULL; -+ } -+ } -+ -+ g_free (a_this); -+} -diff --git a/src/st/croco/cr-declaration.h b/src/st/croco/cr-declaration.h -new file mode 100644 -index 000000000..eee8be321 ---- /dev/null -+++ b/src/st/croco/cr-declaration.h -@@ -0,0 +1,136 @@ -+/* -*- Mode: C; indent-tabs-mode: nil; c-basic-offset: 8 -*- */ -+ -+/* -+ * This file is part of The Croco Library -+ * -+ * 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 -+ * -+ * See the COPYRIGHTS file for copyright information. -+ */ -+ -+#ifndef __CR_DECLARATION_H__ -+#define __CR_DECLARATION_H__ -+ -+#include -+#include "cr-utils.h" -+#include "cr-term.h" -+#include "cr-parsing-location.h" -+ -+G_BEGIN_DECLS -+ -+/** -+ *@file -+ *The declaration of the #CRDeclaration class. -+ */ -+ -+/*forward declaration of what is defined in cr-statement.h*/ -+typedef struct _CRStatement CRStatement ; -+ -+/** -+ *The abstraction of a css declaration defined by the -+ *css2 spec in chapter 4. -+ *It is actually a chained list of property/value pairs. -+ */ -+typedef struct _CRDeclaration CRDeclaration ; -+struct _CRDeclaration -+{ -+ /**The property.*/ -+ CRString *property ; -+ -+ /**The value of the property.*/ -+ CRTerm *value ; -+ -+ /*the ruleset that contains this declaration*/ -+ CRStatement *parent_statement ; -+ -+ /*the next declaration*/ -+ CRDeclaration *next ; -+ -+ /*the previous one declaration*/ -+ CRDeclaration *prev ; -+ -+ /*does the declaration have the important keyword ?*/ -+ gboolean important ; -+ -+ glong ref_count ; -+ -+ CRParsingLocation location ; -+ /*reserved for future usage*/ -+ gpointer rfu0 ; -+ gpointer rfu1 ; -+ gpointer rfu2 ; -+ gpointer rfu3 ; -+} ; -+ -+ -+CRDeclaration * cr_declaration_new (CRStatement *a_statement, -+ CRString *a_property, -+ CRTerm *a_value) ; -+ -+ -+CRDeclaration * cr_declaration_parse_from_buf (CRStatement *a_statement, -+ const guchar *a_str, -+ enum CREncoding a_enc) ; -+ -+CRDeclaration * cr_declaration_parse_list_from_buf (const guchar *a_str, -+ enum CREncoding a_enc) ; -+ -+CRDeclaration * cr_declaration_append (CRDeclaration *a_this, -+ CRDeclaration *a_new) ; -+ -+CRDeclaration * cr_declaration_append2 (CRDeclaration *a_this, -+ CRString *a_prop, -+ CRTerm *a_value) ; -+ -+CRDeclaration * cr_declaration_prepend (CRDeclaration *a_this, -+ CRDeclaration *a_new) ; -+ -+CRDeclaration * cr_declaration_unlink (CRDeclaration * a_decl) ; -+ -+void -+cr_declaration_dump (CRDeclaration const *a_this, -+ FILE *a_fp, glong a_indent, -+ gboolean a_one_per_line) ; -+ -+void cr_declaration_dump_one (CRDeclaration const *a_this, -+ FILE *a_fp, glong a_indent) ; -+ -+gint cr_declaration_nr_props (CRDeclaration const *a_this) ; -+ -+CRDeclaration * cr_declaration_get_from_list (CRDeclaration *a_this, -+ int itemnr) ; -+ -+CRDeclaration * cr_declaration_get_by_prop_name (CRDeclaration *a_this, -+ const guchar *a_str) ; -+ -+gchar * cr_declaration_to_string (CRDeclaration const *a_this, -+ gulong a_indent) ; -+ -+guchar * cr_declaration_list_to_string (CRDeclaration const *a_this, -+ gulong a_indent) ; -+ -+guchar * cr_declaration_list_to_string2 (CRDeclaration const *a_this, -+ gulong a_indent, -+ gboolean a_one_decl_per_line) ; -+ -+void cr_declaration_ref (CRDeclaration *a_this) ; -+ -+gboolean cr_declaration_unref (CRDeclaration *a_this) ; -+ -+void cr_declaration_destroy (CRDeclaration *a_this) ; -+ -+G_END_DECLS -+ -+#endif /*__CR_DECLARATION_H__*/ -diff --git a/src/st/croco/cr-doc-handler.c b/src/st/croco/cr-doc-handler.c -new file mode 100644 -index 000000000..bbb158298 ---- /dev/null -+++ b/src/st/croco/cr-doc-handler.c -@@ -0,0 +1,276 @@ -+/* -*- Mode: C; indent-tabs-mode: nil; c-basic-offset: 8 -*- */ -+ -+/* -+ * This file is part of The Croco Library -+ * -+ * 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 -+ * -+ * See COPRYRIGHTS file for copyright information. -+ */ -+ -+#include -+#include "cr-doc-handler.h" -+#include "cr-parser.h" -+ -+/** -+ *@CRDocHandler: -+ * -+ *The definition of the CRDocHandler class. -+ *Contains methods to instantiate, destroy, -+ *and initialyze instances of #CRDocHandler -+ *to custom values. -+ */ -+ -+#define PRIVATE(obj) (obj)->priv -+ -+struct _CRDocHandlerPriv { -+ /** -+ *This pointer is to hold an application parsing context. -+ *For example, it used by the Object Model parser to -+ *store it parsing context. #CRParser does not touch it, but -+ *#CROMParser does. #CROMParser allocates this pointer at -+ *the beginning of the css document, and frees it at the end -+ *of the document. -+ */ -+ gpointer context; -+ -+ /** -+ *The place where #CROMParser puts the result of its parsing, if -+ *any. -+ */ -+ gpointer result; -+ /** -+ *a pointer to the parser used to parse -+ *the current document. -+ */ -+ CRParser *parser ; -+}; -+ -+/** -+ * cr_doc_handler_new: -+ *Constructor of #CRDocHandler. -+ * -+ *Returns the newly built instance of -+ *#CRDocHandler -+ * -+ */ -+CRDocHandler * -+cr_doc_handler_new (void) -+{ -+ CRDocHandler *result = NULL; -+ -+ result = g_try_malloc (sizeof (CRDocHandler)); -+ -+ g_return_val_if_fail (result, NULL); -+ -+ memset (result, 0, sizeof (CRDocHandler)); -+ result->ref_count++; -+ -+ result->priv = g_try_malloc (sizeof (CRDocHandlerPriv)); -+ if (!result->priv) { -+ cr_utils_trace_info ("Out of memory exception"); -+ g_free (result); -+ return NULL; -+ } -+ -+ cr_doc_handler_set_default_sac_handler (result); -+ -+ return result; -+} -+ -+/** -+ * cr_doc_handler_get_ctxt: -+ *@a_this: the current instance of #CRDocHandler. -+ *@a_ctxt: out parameter. The new parsing context. -+ * -+ *Gets the private parsing context associated to the document handler -+ *The private parsing context is used by libcroco only. -+ * -+ *Returns CR_OK upon successfull completion, an error code otherwise. -+ */ -+enum CRStatus -+cr_doc_handler_get_ctxt (CRDocHandler const * a_this, gpointer * a_ctxt) -+{ -+ g_return_val_if_fail (a_this && a_this->priv, CR_BAD_PARAM_ERROR); -+ -+ *a_ctxt = a_this->priv->context; -+ -+ return CR_OK; -+} -+ -+/** -+ * cr_doc_handler_set_ctxt: -+ *@a_this: the current instance of #CRDocHandler -+ *@a_ctxt: a pointer to the parsing context. -+ * -+ *Sets the private parsing context. -+ *This is used by libcroco only. -+ *Returns CR_OK upon successfull completion, an error code otherwise. -+ */ -+enum CRStatus -+cr_doc_handler_set_ctxt (CRDocHandler * a_this, gpointer a_ctxt) -+{ -+ g_return_val_if_fail (a_this && a_this->priv, CR_BAD_PARAM_ERROR); -+ a_this->priv->context = a_ctxt; -+ return CR_OK; -+} -+ -+/** -+ * cr_doc_handler_get_result: -+ *@a_this: the current instance of #CRDocHandler -+ *@a_result: out parameter. The returned result. -+ * -+ *Gets the private parsing result. -+ *The private parsing result is used by libcroco only. -+ * -+ *Returns CR_OK upon successfull completion, an error code otherwise. -+ */ -+enum CRStatus -+cr_doc_handler_get_result (CRDocHandler const * a_this, gpointer * a_result) -+{ -+ g_return_val_if_fail (a_this && a_this->priv, CR_BAD_PARAM_ERROR); -+ -+ *a_result = a_this->priv->result; -+ -+ return CR_OK; -+} -+ -+/** -+ * cr_doc_handler_set_result: -+ *@a_this: the current instance of #CRDocHandler -+ *@a_result: the new result. -+ * -+ *Sets the private parsing context. -+ *This is used by libcroco only. -+ * -+ *Returns CR_OK upon successfull completion, an error code otherwise. -+ */ -+enum CRStatus -+cr_doc_handler_set_result (CRDocHandler * a_this, gpointer a_result) -+{ -+ g_return_val_if_fail (a_this && a_this->priv, CR_BAD_PARAM_ERROR); -+ a_this->priv->result = a_result; -+ return CR_OK; -+} -+ -+/** -+ *cr_doc_handler_set_default_sac_handler: -+ *@a_this: a pointer to the current instance of #CRDocHandler. -+ * -+ *Sets the sac handlers contained in the current -+ *instance of DocHandler to the default handlers. -+ *For the time being the default handlers are -+ *test handlers. This is expected to change in a -+ *near future, when the libcroco gets a bit debugged. -+ * -+ *Returns CR_OK upon successfull completion, an error code otherwise. -+ */ -+enum CRStatus -+cr_doc_handler_set_default_sac_handler (CRDocHandler * a_this) -+{ -+ g_return_val_if_fail (a_this, CR_BAD_PARAM_ERROR); -+ -+ a_this->start_document = NULL; -+ a_this->end_document = NULL; -+ a_this->import_style = NULL; -+ a_this->namespace_declaration = NULL; -+ a_this->comment = NULL; -+ a_this->start_selector = NULL; -+ a_this->end_selector = NULL; -+ a_this->property = NULL; -+ a_this->start_font_face = NULL; -+ a_this->end_font_face = NULL; -+ a_this->start_media = NULL; -+ a_this->end_media = NULL; -+ a_this->start_page = NULL; -+ a_this->end_page = NULL; -+ a_this->ignorable_at_rule = NULL; -+ a_this->error = NULL; -+ a_this->unrecoverable_error = NULL; -+ return CR_OK; -+} -+ -+/** -+ * cr_doc_handler_ref: -+ *@a_this: the current instance of #CRDocHandler. -+ */ -+void -+cr_doc_handler_ref (CRDocHandler * a_this) -+{ -+ g_return_if_fail (a_this); -+ -+ a_this->ref_count++; -+} -+ -+/** -+ * cr_doc_handler_unref: -+ *@a_this: the currrent instance of #CRDocHandler. -+ * -+ *Decreases the ref count of the current instance of #CRDocHandler. -+ *If the ref count reaches '0' then, destroys the instance. -+ * -+ *Returns TRUE if the instance as been destroyed, FALSE otherwise. -+ */ -+gboolean -+cr_doc_handler_unref (CRDocHandler * a_this) -+{ -+ g_return_val_if_fail (a_this, FALSE); -+ -+ if (a_this->ref_count > 0) { -+ a_this->ref_count--; -+ } -+ -+ if (a_this->ref_count == 0) { -+ cr_doc_handler_destroy (a_this); -+ return TRUE; -+ } -+ return FALSE ; -+} -+ -+/** -+ * cr_doc_handler_destroy: -+ *@a_this: the instance of #CRDocHandler to -+ *destroy. -+ * -+ *The destructor of the #CRDocHandler class. -+ */ -+void -+cr_doc_handler_destroy (CRDocHandler * a_this) -+{ -+ g_return_if_fail (a_this); -+ -+ if (a_this->priv) { -+ g_free (a_this->priv); -+ a_this->priv = NULL; -+ } -+ g_free (a_this); -+} -+ -+/** -+ * cr_doc_handler_associate_a_parser: -+ *Associates a parser to the current document handler -+ * -+ *@a_this: the current instance of document handler. -+ *@a_parser: the parser to associate. -+ */ -+void -+cr_doc_handler_associate_a_parser (CRDocHandler *a_this, -+ gpointer a_parser) -+{ -+ g_return_if_fail (a_this && PRIVATE (a_this) -+ && a_parser) ; -+ -+ PRIVATE (a_this)->parser = a_parser ; -+} -diff --git a/src/st/croco/cr-doc-handler.h b/src/st/croco/cr-doc-handler.h -new file mode 100644 -index 000000000..d12673f31 ---- /dev/null -+++ b/src/st/croco/cr-doc-handler.h -@@ -0,0 +1,298 @@ -+/* -*- Mode: C; indent-tabs-mode: nil; c-basic-offset: 8 -*- */ -+ -+/* -+ * This file is part of The Croco Library -+ * -+ * 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 -+ * -+ * See the COPYRIGHTS file for copyright information. -+ */ -+ -+#ifndef __CR_DOC_HANDLER_H__ -+#define __CR_DOC_HANDLER_H__ -+ -+/** -+ *@file -+ *The declaration of the #CRDocumentHandler class. -+ *This class is actually the parsing events handler. -+ */ -+ -+#include -+#include "cr-utils.h" -+#include "cr-input.h" -+#include "cr-stylesheet.h" -+ -+G_BEGIN_DECLS -+ -+ -+typedef struct _CRDocHandler CRDocHandler ; -+ -+struct _CRDocHandlerPriv ; -+typedef struct _CRDocHandlerPriv CRDocHandlerPriv ; -+ -+ -+/** -+ *The SAC document handler. -+ *An instance of this class is to -+ *be passed to a parser. Then, during the parsing -+ *the parser calls the convenient function pointer -+ *whenever a particular event (a css construction) occurs. -+ */ -+struct _CRDocHandler -+{ -+ CRDocHandlerPriv *priv ; -+ -+ /** -+ *This pointer is to be used by the application for -+ *it custom needs. It is there to extend the doc handler. -+ */ -+ gpointer app_data ; -+ -+ /** -+ *Is called at the beginning of the parsing of the document. -+ *@param a_this a pointer to the current instance of -+ *#CRDocHandler. -+ */ -+ void (*start_document) (CRDocHandler *a_this) ; -+ -+ /** -+ *Is called to notify the end of the parsing of the document. -+ *@param a_this a pointer to the current instance of -+ *#CRDocHandler. -+ */ -+ void (*end_document) (CRDocHandler *a_this) ; -+ -+ /** -+ *Is called to notify an at charset rule. -+ *@param a_this the document handler. -+ *@param a_charset the declared charset. -+ */ -+ void (*charset) (CRDocHandler *a_this, -+ CRString *a_charset, -+ CRParsingLocation *a_charset_sym_location) ; -+ -+ /** -+ *Is called to notify an import statement in -+ *the stylesheet. -+ *@param a_this the current instance of #CRDocHandler. -+ *@param a_media_list a doubly linked list of GString objects. -+ *Each GString object contains a string which is the -+ *destination media for style information. -+ *@param a_uri the uri of the imported style sheet. -+ *@param a_uri_default_ns the default namespace of URI -+ *@param a_location the parsing location of the '\@import' -+ *keyword. -+ *of the imported style sheet. -+ */ -+ void (*import_style) (CRDocHandler *a_this, -+ GList *a_media_list, -+ CRString *a_uri, -+ CRString *a_uri_default_ns, -+ CRParsingLocation *a_location) ; -+ -+ void (*import_style_result) (CRDocHandler *a_this, -+ GList *a_media_list, -+ CRString *a_uri, -+ CRString *a_uri_default_ns, -+ CRStyleSheet *a_sheet) ; -+ -+ /** -+ *Is called to notify a namespace declaration. -+ *Not used yet. -+ *@param a_this the current instance of #CRDocHandler. -+ *@param a_prefix the prefix of the namespace. -+ *@param a_uri the uri of the namespace. -+ *@param a_location the location of the "@namespace" keyword. -+ */ -+ void (*namespace_declaration) (CRDocHandler *a_this, -+ CRString *a_prefix, -+ CRString *a_uri, -+ CRParsingLocation *a_location) ; -+ -+ /** -+ *Is called to notify a comment. -+ *@param a_this a pointer to the current instance -+ *of #CRDocHandler. -+ *@param a_comment the comment. -+ */ -+ void (*comment) (CRDocHandler *a_this, -+ CRString *a_comment) ; -+ -+ /** -+ *Is called to notify the beginning of a rule -+ *statement. -+ *@param a_this the current instance of #CRDocHandler. -+ *@param a_selector_list the list of selectors that precedes -+ *the rule declarations. -+ */ -+ void (*start_selector) (CRDocHandler * a_this, -+ CRSelector *a_selector_list) ; -+ -+ /** -+ *Is called to notify the end of a rule statement. -+ *@param a_this the current instance of #CRDocHandler. -+ *@param a_selector_list the list of selectors that precedes -+ *the rule declarations. This pointer is the same as -+ *the one passed to start_selector() ; -+ */ -+ void (*end_selector) (CRDocHandler *a_this, -+ CRSelector *a_selector_list) ; -+ -+ -+ /** -+ *Is called to notify a declaration. -+ *@param a_this a pointer to the current instance -+ *of #CRDocHandler. -+ *@param a_name the name of the parsed property. -+ *@param a_expression a css expression that represents -+ *the value of the property. A css expression is -+ *actually a linked list of 'terms'. Each term can -+ *be linked to other using operators. -+ * -+ */ -+ void (*property) (CRDocHandler *a_this, -+ CRString *a_name, -+ CRTerm *a_expression, -+ gboolean a_is_important) ; -+ /** -+ *Is called to notify the start of a font face statement. -+ *The parser invokes this method at the beginning of every -+ *font face statement in the style sheet. There will -+ *be a corresponding end_font_face () event for every -+ *start_font_face () event. -+ * -+ *@param a_this a pointer to the current instance of -+ *#CRDocHandler. -+ *@param a_location the parsing location of the "\@font-face" -+ *keyword. -+ */ -+ void (*start_font_face) (CRDocHandler *a_this, -+ CRParsingLocation *a_location) ; -+ -+ /** -+ *Is called to notify the end of a font face statement. -+ *@param a_this a pointer to the current instance of -+ *#CRDocHandler. -+ */ -+ void (*end_font_face) (CRDocHandler *a_this) ; -+ -+ -+ /** -+ *Is called to notify the beginning of a media statement. -+ *The parser will invoke this method at the beginning of -+ *every media statement in the style sheet. There will be -+ *a corresponding end_media() event for every start_media() -+ *event. -+ *@param a_this a pointer to the current instance of -+ *#CRDocHandler. -+ *@param a_media_list a double linked list of -+ #CRString * objects. -+ *Each CRString objects is actually a destination media for -+ *the style information. -+ */ -+ void (*start_media) (CRDocHandler *a_this, -+ GList *a_media_list, -+ CRParsingLocation *a_location) ; -+ -+ /** -+ *Is called to notify the end of a media statement. -+ *@param a_this a pointer to the current instance -+ *of #CRDocHandler. -+ *@param a_media_list a double linked list of GString * objects. -+ *Each GString objects is actually a destination media for -+ *the style information. -+ */ -+ void (*end_media) (CRDocHandler *a_this, -+ GList *a_media_list) ; -+ -+ /** -+ *Is called to notify the beginning of a page statement. -+ *The parser invokes this function at the beginning of -+ *every page statement in the style sheet. There will be -+ *a corresponding end_page() event for every single -+ *start_page() event. -+ *@param a_this a pointer to the current instance of -+ *#CRDocHandler. -+ *@param a_name the name of the page (if any, null otherwise). -+ *@param a_pseudo_page the pseudo page (if any, null otherwise). -+ *@param a_location the parsing location of the "\@page" keyword. -+ */ -+ void (*start_page) (CRDocHandler *a_this, -+ CRString *a_name, -+ CRString *a_pseudo_page, -+ CRParsingLocation *a_location) ; -+ -+ /** -+ *Is called to notify the end of a page statement. -+ *@param a_this a pointer to the current instance of -+ *#CRDocHandler. -+ *@param a_name the name of the page (if any, null otherwise). -+ *@param a_pseudo_page the pseudo page (if any, null otherwise). -+ */ -+ void (*end_page) (CRDocHandler *a_this, -+ CRString *a_name, -+ CRString *pseudo_page) ; -+ -+ /** -+ *Is Called to notify an unknown at-rule not supported -+ *by this parser. -+ */ -+ void (*ignorable_at_rule) (CRDocHandler *a_this, -+ CRString *a_name) ; -+ -+ /** -+ *Is called to notify a parsing error. After this error -+ *the application must ignore the rule being parsed, if -+ *any. After completion of this callback, -+ *the parser will then try to resume the parsing, -+ *ignoring the current error. -+ */ -+ void (*error) (CRDocHandler *a_this) ; -+ -+ /** -+ *Is called to notify an unrecoverable parsing error. -+ *This is the place to put emergency routines that free allocated -+ *resources. -+ */ -+ void (*unrecoverable_error) (CRDocHandler *a_this) ; -+ -+ gboolean resolve_import ; -+ gulong ref_count ; -+} ; -+ -+CRDocHandler * cr_doc_handler_new (void) ; -+ -+enum CRStatus cr_doc_handler_set_result (CRDocHandler *a_this, gpointer a_result) ; -+ -+enum CRStatus cr_doc_handler_get_result (CRDocHandler const *a_this, gpointer * a_result) ; -+ -+enum CRStatus cr_doc_handler_set_ctxt (CRDocHandler *a_this, gpointer a_ctxt) ; -+ -+enum CRStatus cr_doc_handler_get_ctxt (CRDocHandler const *a_this, gpointer * a_ctxt) ; -+ -+enum CRStatus cr_doc_handler_set_default_sac_handler (CRDocHandler *a_this) ; -+ -+void cr_doc_handler_associate_a_parser (CRDocHandler *a_this, -+ gpointer a_parser) ; -+ -+void cr_doc_handler_ref (CRDocHandler *a_this) ; -+ -+gboolean cr_doc_handler_unref (CRDocHandler *a_this) ; -+ -+void cr_doc_handler_destroy (CRDocHandler *a_this) ; -+ -+G_END_DECLS -+ -+#endif /*__CR_DOC_HANDLER_H__*/ -diff --git a/src/st/croco/cr-enc-handler.c b/src/st/croco/cr-enc-handler.c -new file mode 100644 -index 000000000..a7c4269ad ---- /dev/null -+++ b/src/st/croco/cr-enc-handler.c -@@ -0,0 +1,184 @@ -+/* -*- Mode: C; indent-tabs-mode: nil; c-basic-offset: 8 -*- */ -+ -+/* -+ * This file is part of The Croco Library -+ * -+ * Copyright (C) 2002-2003 Dodji Seketeli -+ * -+ * 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 -+ */ -+ -+/* -+ *$Id$ -+ */ -+ -+/** -+ *@file -+ *The definition of the #CREncHandler class. -+ */ -+ -+#include "cr-enc-handler.h" -+#include "cr-utils.h" -+ -+#include -+ -+struct CREncAlias { -+ const gchar *name; -+ enum CREncoding encoding; -+}; -+ -+static struct CREncAlias gv_default_aliases[] = { -+ {"UTF-8", CR_UTF_8}, -+ {"UTF_8", CR_UTF_8}, -+ {"UTF8", CR_UTF_8}, -+ {"UTF-16", CR_UTF_16}, -+ {"UTF_16", CR_UTF_16}, -+ {"UTF16", CR_UTF_16}, -+ {"UCS1", CR_UCS_1}, -+ {"UCS-1", CR_UCS_1}, -+ {"UCS_1", CR_UCS_1}, -+ {"ISO-8859-1", CR_UCS_1}, -+ {"ISO_8859-1", CR_UCS_1}, -+ {"UCS-1", CR_UCS_1}, -+ {"UCS_1", CR_UCS_1}, -+ {"UCS4", CR_UCS_4}, -+ {"UCS-4", CR_UCS_4}, -+ {"UCS_4", CR_UCS_4}, -+ {"ASCII", CR_ASCII}, -+ {0, 0} -+}; -+ -+static CREncHandler gv_default_enc_handlers[] = { -+ {CR_UCS_1, cr_utils_ucs1_to_utf8, cr_utils_utf8_to_ucs1, -+ cr_utils_ucs1_str_len_as_utf8, cr_utils_utf8_str_len_as_ucs1}, -+ -+ {CR_ISO_8859_1, cr_utils_ucs1_to_utf8, cr_utils_utf8_to_ucs1, -+ cr_utils_ucs1_str_len_as_utf8, cr_utils_utf8_str_len_as_ucs1}, -+ -+ {CR_ASCII, cr_utils_ucs1_to_utf8, cr_utils_utf8_to_ucs1, -+ cr_utils_ucs1_str_len_as_utf8, cr_utils_utf8_str_len_as_ucs1}, -+ -+ {0, NULL, NULL, NULL, NULL} -+}; -+ -+/** -+ * cr_enc_handler_get_instance: -+ *@a_enc: the encoding of the Handler. -+ * -+ *Gets the instance of encoding handler. -+ *This function implements a singleton pattern. -+ * -+ *Returns the instance of #CREncHandler. -+ */ -+CREncHandler * -+cr_enc_handler_get_instance (enum CREncoding a_enc) -+{ -+ gulong i = 0; -+ -+ for (i = 0; gv_default_enc_handlers[i].encoding; i++) { -+ if (gv_default_enc_handlers[i].encoding == a_enc) { -+ return (CREncHandler *) & gv_default_enc_handlers[i]; -+ } -+ } -+ -+ return NULL; -+} -+ -+/** -+ * cr_enc_handler_resolve_enc_alias: -+ *@a_alias_name: the encoding name. -+ *@a_enc: output param. The returned encoding type -+ *or 0 if the alias is not supported. -+ * -+ *Given an encoding name (called an alias name) -+ *the function returns the matching encoding type. -+ * -+ *Returns CR_OK upon successfull completion, an error code otherwise. -+ */ -+enum CRStatus -+cr_enc_handler_resolve_enc_alias (const guchar * a_alias_name, -+ enum CREncoding *a_enc) -+{ -+ gulong i = 0; -+ guchar *alias_name_up = NULL; -+ enum CRStatus status = CR_ENCODING_NOT_FOUND_ERROR; -+ -+ g_return_val_if_fail (a_alias_name != NULL, CR_BAD_PARAM_ERROR); -+ -+ alias_name_up = (guchar *) g_ascii_strup ((const gchar *) a_alias_name, -1); -+ -+ for (i = 0; gv_default_aliases[i].name; i++) { -+ if (!strcmp (gv_default_aliases[i].name, (const gchar *) alias_name_up)) { -+ *a_enc = gv_default_aliases[i].encoding; -+ status = CR_OK; -+ break; -+ } -+ } -+ -+ return status; -+} -+ -+/** -+ * cr_enc_handler_convert_input: -+ *@a_this: the current instance of #CREncHandler. -+ *@a_in: the input buffer to convert. -+ *@a_in_len: in/out parameter. The len of the input -+ *buffer to convert. After return, contains the number of -+ *bytes actually consumed. -+ *@a_out: output parameter. The converted output buffer. -+ *Must be freed by the buffer. -+ *@a_out_len: output parameter. The length of the output buffer. -+ * -+ *Converts a raw input buffer into an utf8 buffer. -+ * -+ *Returns CR_OK upon successfull completion, an error code otherwise. -+ */ -+enum CRStatus -+cr_enc_handler_convert_input (CREncHandler * a_this, -+ const guchar * a_in, -+ gulong * a_in_len, -+ guchar ** a_out, gulong * a_out_len) -+{ -+ enum CRStatus status = CR_OK; -+ -+ g_return_val_if_fail (a_this && a_in && a_in_len && a_out, -+ CR_BAD_PARAM_ERROR); -+ -+ if (a_this->decode_input == NULL) -+ return CR_OK; -+ -+ if (a_this->enc_str_len_as_utf8) { -+ status = a_this->enc_str_len_as_utf8 (a_in, -+ &a_in[*a_in_len - 1], -+ a_out_len); -+ -+ g_return_val_if_fail (status == CR_OK, status); -+ } else { -+ *a_out_len = *a_in_len; -+ } -+ -+ *a_out = g_malloc0 (*a_out_len); -+ -+ status = a_this->decode_input (a_in, a_in_len, *a_out, a_out_len); -+ -+ if (status != CR_OK) { -+ g_free (*a_out); -+ *a_out = NULL; -+ } -+ -+ g_return_val_if_fail (status == CR_OK, status); -+ -+ return CR_OK; -+} -diff --git a/src/st/croco/cr-enc-handler.h b/src/st/croco/cr-enc-handler.h -new file mode 100644 -index 000000000..0727764c0 ---- /dev/null -+++ b/src/st/croco/cr-enc-handler.h -@@ -0,0 +1,94 @@ -+/* -*- Mode: C; indent-tabs-mode: nil; c-basic-offset: 8 -*- */ -+ -+/* -+ * This file is part of The Croco Library -+ * -+ * Copyright (C) 2002-2003 Dodji Seketeli -+ * -+ * 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 -+ */ -+ -+/* -+ *$Id$ -+ */ -+ -+/** -+ *@file: -+ *The declaration of the #CREncHandler class. -+ * -+ */ -+ -+#ifndef __CR_ENC_HANDLER_H__ -+#define __CR_ENC_HANDLER_H__ -+ -+#include "cr-utils.h" -+ -+G_BEGIN_DECLS -+ -+ -+typedef struct _CREncHandler CREncHandler ; -+ -+typedef enum CRStatus (*CREncInputFunc) (const guchar * a_in, -+ gulong *a_in_len, -+ guchar *a_out, -+ gulong *a_out_len) ; -+ -+typedef enum CRStatus (*CREncOutputFunc) (const guchar * a_in, -+ gulong *a_in_len, -+ guchar *a_out, -+ gulong *a_out_len) ; -+ -+typedef enum CRStatus (*CREncInputStrLenAsUtf8Func) -+(const guchar *a_in_start, -+ const guchar *a_in_end, -+ gulong *a_in_size); -+ -+typedef enum CRStatus (*CREncUtf8StrLenAsOutputFunc) -+(const guchar *a_in_start, -+ const guchar *a_in_end, -+ gulong *a_in_size) ; -+ -+/** -+ *This class is responsible of the -+ *the encoding conversions stuffs in -+ *libcroco. -+ */ -+ -+struct _CREncHandler -+{ -+ enum CREncoding encoding ; -+ CREncInputFunc decode_input ; -+ CREncInputFunc encode_output ; -+ CREncInputStrLenAsUtf8Func enc_str_len_as_utf8 ; -+ CREncUtf8StrLenAsOutputFunc utf8_str_len_as_enc ; -+} ; -+ -+CREncHandler * -+cr_enc_handler_get_instance (enum CREncoding a_enc) ; -+ -+enum CRStatus -+cr_enc_handler_resolve_enc_alias (const guchar *a_alias_name, -+ enum CREncoding *a_enc) ; -+ -+enum CRStatus -+cr_enc_handler_convert_input (CREncHandler *a_this, -+ const guchar *a_in, -+ gulong *a_in_len, -+ guchar **a_out, -+ gulong *a_out_len) ; -+ -+G_END_DECLS -+ -+#endif /*__CR_ENC_HANDLER_H__*/ -diff --git a/src/st/croco/cr-fonts.c b/src/st/croco/cr-fonts.c -new file mode 100644 -index 000000000..3a5788cea ---- /dev/null -+++ b/src/st/croco/cr-fonts.c -@@ -0,0 +1,949 @@ -+/* -*- Mode: C; indent-tabs-mode:nil; c-basic-offset: 8-*- */ -+ -+/* -+ * This file is part of The Croco Library -+ * -+ * -+ * 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 -+ * -+ *See COPYRIGHTS file for copyright information -+ */ -+ -+#include "cr-fonts.h" -+#include -+ -+static enum CRStatus -+cr_font_family_to_string_real (CRFontFamily const * a_this, -+ gboolean a_walk_list, GString ** a_string) -+{ -+ guchar const *name = NULL; -+ enum CRStatus result = CR_OK; -+ -+ if (!*a_string) { -+ *a_string = g_string_new (NULL); -+ g_return_val_if_fail (*a_string, -+ CR_INSTANCIATION_FAILED_ERROR); -+ } -+ -+ if (!a_this) { -+ g_string_append (*a_string, "NULL"); -+ return CR_OK; -+ } -+ -+ switch (a_this->type) { -+ case FONT_FAMILY_SANS_SERIF: -+ name = (guchar const *) "sans-serif"; -+ break; -+ -+ case FONT_FAMILY_SERIF: -+ name = (guchar const *) "sans-serif"; -+ break; -+ -+ case FONT_FAMILY_CURSIVE: -+ name = (guchar const *) "cursive"; -+ break; -+ -+ case FONT_FAMILY_FANTASY: -+ name = (guchar const *) "fantasy"; -+ break; -+ -+ case FONT_FAMILY_MONOSPACE: -+ name = (guchar const *) "monospace"; -+ break; -+ -+ case FONT_FAMILY_NON_GENERIC: -+ name = (guchar const *) a_this->name; -+ break; -+ -+ default: -+ name = NULL; -+ break; -+ } -+ -+ if (name) { -+ if (a_this->prev) { -+ g_string_append_printf (*a_string, ", %s", name); -+ } else { -+ g_string_append (*a_string, (const gchar *) name); -+ } -+ } -+ if (a_walk_list == TRUE && a_this->next) { -+ result = cr_font_family_to_string_real (a_this->next, -+ TRUE, a_string); -+ } -+ return result; -+} -+ -+static const gchar * -+cr_predefined_absolute_font_size_to_string (enum CRPredefinedAbsoluteFontSize -+ a_code) -+{ -+ gchar const *str = NULL; -+ -+ switch (a_code) { -+ case FONT_SIZE_XX_SMALL: -+ str = "xx-small"; -+ break; -+ case FONT_SIZE_X_SMALL: -+ str = "x-small"; -+ break; -+ case FONT_SIZE_SMALL: -+ str = "small"; -+ break; -+ case FONT_SIZE_MEDIUM: -+ str = "medium"; -+ break; -+ case FONT_SIZE_LARGE: -+ str = "large"; -+ break; -+ case FONT_SIZE_X_LARGE: -+ str = "x-large"; -+ break; -+ case FONT_SIZE_XX_LARGE: -+ str = "xx-large"; -+ break; -+ default: -+ str = "unknown absolute font size value"; -+ } -+ return str; -+} -+ -+static const gchar * -+cr_relative_font_size_to_string (enum CRRelativeFontSize a_code) -+{ -+ gchar const *str = NULL; -+ -+ switch (a_code) { -+ case FONT_SIZE_LARGER: -+ str = "larger"; -+ break; -+ case FONT_SIZE_SMALLER: -+ str = "smaller"; -+ break; -+ default: -+ str = "unknown relative font size value"; -+ break; -+ } -+ return str; -+} -+ -+/** -+ * cr_font_family_new: -+ * @a_type: the type of font family to create. -+ * @a_name: the name of the font family. -+ * -+ * create a font family. -+ * -+ * Returns the newly built font family. -+ */ -+CRFontFamily * -+cr_font_family_new (enum CRFontFamilyType a_type, guchar * a_name) -+{ -+ CRFontFamily *result = NULL; -+ -+ result = g_try_malloc (sizeof (CRFontFamily)); -+ -+ if (!result) { -+ cr_utils_trace_info ("Out of memory"); -+ return NULL; -+ } -+ -+ memset (result, 0, sizeof (CRFontFamily)); -+ result->type = a_type; -+ -+ cr_font_family_set_name (result, a_name); -+ -+ return result; -+} -+ -+/** -+ * cr_font_family_to_string: -+ * @a_this: the current instance of #CRFontFamily. -+ * @a_walk_font_family_list: wether the serialize the entire list. -+ * -+ * Returns the seriliazed font family. The caller has to free it using -+ * g_free(). -+ */ -+guchar * -+cr_font_family_to_string (CRFontFamily const * a_this, -+ gboolean a_walk_font_family_list) -+{ -+ enum CRStatus status = CR_OK; -+ guchar *result = NULL; -+ GString *stringue = NULL; -+ -+ if (!a_this) { -+ result = (guchar *) g_strdup ("NULL"); -+ g_return_val_if_fail (result, NULL); -+ return result; -+ } -+ status = cr_font_family_to_string_real (a_this, -+ a_walk_font_family_list, -+ &stringue); -+ -+ if (status == CR_OK && stringue) { -+ result = (guchar *) stringue->str; -+ g_string_free (stringue, FALSE); -+ stringue = NULL; -+ -+ } else { -+ if (stringue) { -+ g_string_free (stringue, TRUE); -+ stringue = NULL; -+ } -+ } -+ -+ return result; -+} -+ -+/** -+ * cr_font_family_set_name: -+ * @a_this: the current instance of #CRFontFamily. -+ * @a_name: the new name -+ * -+ * Returns CR_OK upon sucessful completion, an error code otherwise. -+ */ -+enum CRStatus -+cr_font_family_set_name (CRFontFamily * a_this, guchar * a_name) -+{ -+ g_return_val_if_fail (a_this, CR_BAD_PARAM_ERROR); -+ -+ /* -+ *only non generic font families can have a name -+ */ -+ -+ if (a_this->type != FONT_FAMILY_NON_GENERIC) { -+ return CR_BAD_PARAM_ERROR; -+ } -+ -+ if (a_this->name) { -+ g_free (a_this->name); -+ a_this->name = NULL; -+ } -+ -+ a_this->name = a_name; -+ return CR_OK; -+} -+ -+/** -+ * cr_font_family_append: -+ * @a_this: the current instance of #CRFontFamily. -+ * @a_family_to_append: the font family to append to the list -+ * -+ * Returns the new font family list. -+ */ -+CRFontFamily * -+cr_font_family_append (CRFontFamily * a_this, -+ CRFontFamily * a_family_to_append) -+{ -+ CRFontFamily *cur_ff = NULL; -+ -+ g_return_val_if_fail (a_family_to_append, NULL); -+ -+ if (!a_this) -+ return a_family_to_append; -+ -+ for (cur_ff = a_this; cur_ff && cur_ff->next; cur_ff = cur_ff->next) ; -+ -+ cur_ff->next = a_family_to_append; -+ a_family_to_append->prev = cur_ff; -+ -+ return a_this; -+ -+} -+ -+/** -+ * cr_font_family_prepend: -+ * @a_this: the current instance #CRFontFamily. -+ * @a_family_to_prepend: the font family to prepend to the list. -+ * -+ * Returns the font family list. -+ */ -+CRFontFamily * -+cr_font_family_prepend (CRFontFamily * a_this, -+ CRFontFamily * a_family_to_prepend) -+{ -+ g_return_val_if_fail (a_this && a_family_to_prepend, NULL); -+ -+ if (!a_this) -+ return a_family_to_prepend; -+ -+ a_family_to_prepend->next = a_this; -+ a_this->prev = a_family_to_prepend; -+ -+ return a_family_to_prepend; -+} -+ -+/** -+ * cr_font_family_destroy: -+ * @a_this: the current instance of #CRFontFamily. -+ * -+ * Returns CR_OK upon sucessful completion, an error code otherwise. -+ */ -+enum CRStatus -+cr_font_family_destroy (CRFontFamily * a_this) -+{ -+ CRFontFamily *cur_ff = NULL; -+ -+ g_return_val_if_fail (a_this, CR_BAD_PARAM_ERROR); -+ -+ for (cur_ff = a_this; cur_ff && cur_ff->next; cur_ff = cur_ff->next) ; -+ -+ for (; cur_ff; cur_ff = cur_ff->prev) { -+ if (a_this->name) { -+ g_free (a_this->name); -+ a_this->name = NULL; -+ } -+ -+ if (cur_ff->next) { -+ g_free (cur_ff->next); -+ -+ } -+ -+ if (cur_ff->prev == NULL) { -+ g_free (a_this); -+ } -+ } -+ -+ return CR_OK; -+} -+ -+/*************************************************** -+ *'font-size' manipulation functions definitions -+ ***************************************************/ -+ -+/** -+ * cr_font_size_new: -+ * -+ * Returns the newly created font size. -+ */ -+CRFontSize * -+cr_font_size_new (void) -+{ -+ CRFontSize *result = NULL; -+ -+ result = g_try_malloc (sizeof (CRFontSize)); -+ if (!result) { -+ cr_utils_trace_info ("Out of memory"); -+ return NULL; -+ } -+ memset (result, 0, sizeof (CRFontSize)); -+ -+ return result; -+} -+ -+/** -+ * cr_font_size_clear: -+ * @a_this: the current instance of #CRFontSize -+ * -+ * Returns CR_OK upon successful completion, an error code otherwise. -+ */ -+enum CRStatus -+cr_font_size_clear (CRFontSize * a_this) -+{ -+ g_return_val_if_fail (a_this, CR_BAD_PARAM_ERROR); -+ -+ switch (a_this->type) { -+ case PREDEFINED_ABSOLUTE_FONT_SIZE: -+ case RELATIVE_FONT_SIZE: -+ case INHERITED_FONT_SIZE: -+ memset (a_this, 0, sizeof (CRFontSize)); -+ break; -+ -+ case ABSOLUTE_FONT_SIZE: -+ memset (a_this, 0, sizeof (CRFontSize)); -+ break; -+ -+ default: -+ return CR_UNKNOWN_TYPE_ERROR; -+ } -+ -+ return CR_OK; -+} -+ -+/** -+ * cr_font_size_copy: -+ * @a_dst: the destination #CRFontSize (where to copy to). -+ * @a_src: the source #CRFontSize (where to copy from). -+ * -+ * Returns CR_OK upon successful completion, an error code otherwise. -+ */ -+enum CRStatus -+cr_font_size_copy (CRFontSize * a_dst, CRFontSize const * a_src) -+{ -+ g_return_val_if_fail (a_dst && a_src, CR_BAD_PARAM_ERROR); -+ -+ switch (a_src->type) { -+ case PREDEFINED_ABSOLUTE_FONT_SIZE: -+ case RELATIVE_FONT_SIZE: -+ case INHERITED_FONT_SIZE: -+ cr_font_size_clear (a_dst); -+ memcpy (a_dst, a_src, sizeof (CRFontSize)); -+ break; -+ -+ case ABSOLUTE_FONT_SIZE: -+ cr_font_size_clear (a_dst); -+ cr_num_copy (&a_dst->value.absolute, -+ &a_src->value.absolute); -+ a_dst->type = a_src->type; -+ break; -+ -+ default: -+ return CR_UNKNOWN_TYPE_ERROR; -+ } -+ return CR_OK; -+} -+ -+/** -+ * cr_font_size_set_predefined_absolute_font_size: -+ * @a_this: the current instance of #CRFontSize. -+ * @a_predefined: what to set. -+ * -+ * Returns CR_OK upon sucessful completion, an error code otherwise. -+ */ -+enum CRStatus -+cr_font_size_set_predefined_absolute_font_size (CRFontSize *a_this, -+ enum CRPredefinedAbsoluteFontSize a_predefined) -+{ -+ g_return_val_if_fail (a_this, CR_BAD_PARAM_ERROR) ; -+ g_return_val_if_fail (a_predefined >= FONT_SIZE_XX_SMALL -+ && a_predefined < NB_PREDEFINED_ABSOLUTE_FONT_SIZES, -+ CR_BAD_PARAM_ERROR) ; -+ -+ a_this->type = PREDEFINED_ABSOLUTE_FONT_SIZE ; -+ a_this->value.predefined = a_predefined ; -+ -+ return CR_OK ; -+} -+ -+/** -+ * cr_font_size_set_relative_font_size: -+ * @a_this: the current instance of #CRFontSize -+ * @a_relative: the new relative font size -+ * -+ * Returns CR_OK upon successful completion, an error code otherwise. -+ */ -+enum CRStatus -+cr_font_size_set_relative_font_size (CRFontSize *a_this, -+ enum CRRelativeFontSize a_relative) -+{ -+ g_return_val_if_fail (a_this, CR_BAD_PARAM_ERROR) ; -+ g_return_val_if_fail (a_relative >= FONT_SIZE_LARGER -+ && a_relative < NB_RELATIVE_FONT_SIZE, -+ CR_BAD_PARAM_ERROR) ; -+ -+ a_this->type = RELATIVE_FONT_SIZE ; -+ a_this->value.relative = a_relative ; -+ return CR_OK ; -+} -+ -+/** -+ * cr_font_size_set_absolute_font_size: -+ * @a_this: the current instance of #CRFontSize -+ * @a_num_type: the type of number to set. -+ * @a_value: the actual value to set. -+ * -+ * Returns CR_OK upon succesful completion, an error code otherwise. -+ */ -+enum CRStatus -+cr_font_size_set_absolute_font_size (CRFontSize *a_this, -+ enum CRNumType a_num_type, -+ gdouble a_value) -+{ -+ g_return_val_if_fail (a_this, CR_BAD_PARAM_ERROR) ; -+ g_return_val_if_fail (a_num_type >= NUM_AUTO -+ && a_num_type < NB_NUM_TYPE, -+ CR_BAD_PARAM_ERROR) ; -+ -+ a_this->type = ABSOLUTE_FONT_SIZE ; -+ cr_num_set (&a_this->value.absolute, -+ a_value, a_num_type) ; -+ return CR_OK ; -+} -+ -+/** -+ * cr_font_size_set_to_inherit: -+ * @a_this: the current instance of #CRFontSize -+ * -+ * Returns CR_OK upon succesful completion, an error code otherwise. -+ */ -+enum CRStatus -+cr_font_size_set_to_inherit (CRFontSize *a_this) -+{ -+ g_return_val_if_fail (a_this, CR_BAD_PARAM_ERROR) ; -+ -+ cr_font_size_clear (a_this) ; -+ a_this->type = INHERITED_FONT_SIZE ; -+ -+ return CR_OK ; -+} -+ -+/** -+ * cr_font_size_is_set_to_inherit: -+ * @a_this: the current instance of #CRFontSize. -+ * -+ * Returns TRUE if the current instance is set to 'inherit'. -+ */ -+gboolean -+cr_font_size_is_set_to_inherit (CRFontSize const *a_this) -+{ -+ g_return_val_if_fail (a_this, FALSE) ; -+ -+ return a_this->type == INHERITED_FONT_SIZE ; -+} -+ -+/** -+ * cr_font_size_to_string: -+ * @a_this: the current instance of #CRFontSize -+ * -+ * Returns the serialized form of #CRFontSize. The returned string -+ * has to bee freed using g_free(). -+ */ -+gchar * -+cr_font_size_to_string (CRFontSize const * a_this) -+{ -+ gchar *str = NULL; -+ -+ if (!a_this) { -+ str = g_strdup ("NULL"); -+ g_return_val_if_fail (str, NULL); -+ return str; -+ } -+ switch (a_this->type) { -+ case PREDEFINED_ABSOLUTE_FONT_SIZE: -+ str = g_strdup (cr_predefined_absolute_font_size_to_string -+ (a_this->value.predefined)); -+ break; -+ case ABSOLUTE_FONT_SIZE: -+ str = (gchar *) cr_num_to_string (&a_this->value.absolute); -+ break; -+ case RELATIVE_FONT_SIZE: -+ str = g_strdup (cr_relative_font_size_to_string -+ (a_this->value.relative)); -+ break; -+ case INHERITED_FONT_SIZE: -+ str = g_strdup ("inherit"); -+ break; -+ default: -+ break; -+ } -+ return str; -+} -+ -+/** -+ * cr_font_size_get_smaller_predefined: -+ * @a_font_size: the font size to consider. -+ * @a_smaller_size: out parameter. The a smaller value than @a_font_size. -+ */ -+void -+cr_font_size_get_smaller_predefined_font_size -+ (enum CRPredefinedAbsoluteFontSize a_font_size, -+ enum CRPredefinedAbsoluteFontSize *a_smaller_size) -+{ -+ enum CRPredefinedAbsoluteFontSize result = FONT_SIZE_MEDIUM ; -+ -+ g_return_if_fail (a_smaller_size) ; -+ g_return_if_fail (a_font_size < NB_PREDEFINED_ABSOLUTE_FONT_SIZES -+ && a_font_size >= FONT_SIZE_XX_SMALL) ; -+ -+ switch (a_font_size) { -+ case FONT_SIZE_XX_SMALL: -+ result = FONT_SIZE_XX_SMALL ; -+ break ; -+ case FONT_SIZE_X_SMALL: -+ result = FONT_SIZE_XX_SMALL ; -+ break ; -+ case FONT_SIZE_SMALL: -+ result = FONT_SIZE_X_SMALL; -+ break ; -+ case FONT_SIZE_MEDIUM: -+ result = FONT_SIZE_SMALL; -+ break ; -+ case FONT_SIZE_LARGE: -+ result = FONT_SIZE_MEDIUM; -+ break ; -+ case FONT_SIZE_X_LARGE: -+ result = FONT_SIZE_LARGE; -+ break ; -+ case FONT_SIZE_XX_LARGE: -+ result = FONT_SIZE_XX_LARGE; -+ break ; -+ case FONT_SIZE_INHERIT: -+ cr_utils_trace_info ("can't return a smaller size for FONT_SIZE_INHERIT") ; -+ result = FONT_SIZE_MEDIUM ; -+ break ; -+ default: -+ cr_utils_trace_info ("Unknown FONT_SIZE") ; -+ result = FONT_SIZE_MEDIUM ; -+ break ; -+ } -+ *a_smaller_size = result ; -+} -+ -+ -+/** -+ * cr_font_size_get_larger_predefined_font_size: -+ * @a_font_size: the font size to consider. -+ * @a_larger_size: out parameter. the font size considered larger than -+ * @a_font_size. -+ * -+ */ -+void -+cr_font_size_get_larger_predefined_font_size -+ (enum CRPredefinedAbsoluteFontSize a_font_size, -+ enum CRPredefinedAbsoluteFontSize *a_larger_size) -+{ -+ enum CRPredefinedAbsoluteFontSize result = FONT_SIZE_MEDIUM ; -+ -+ g_return_if_fail (a_larger_size) ; -+ g_return_if_fail (a_font_size >= FONT_SIZE_XX_SMALL -+ && a_font_size < NB_PREDEFINED_ABSOLUTE_FONT_SIZES) ; -+ -+ switch (a_font_size) { -+ case FONT_SIZE_XX_SMALL: -+ result = FONT_SIZE_X_SMALL ; -+ break ; -+ case FONT_SIZE_X_SMALL: -+ result = FONT_SIZE_SMALL ; -+ break ; -+ case FONT_SIZE_SMALL: -+ result = FONT_SIZE_MEDIUM; -+ break ; -+ case FONT_SIZE_MEDIUM: -+ result = FONT_SIZE_LARGE; -+ break ; -+ case FONT_SIZE_LARGE: -+ result = FONT_SIZE_X_LARGE; -+ break ; -+ case FONT_SIZE_X_LARGE: -+ result = FONT_SIZE_XX_LARGE ; -+ break ; -+ case FONT_SIZE_XX_LARGE: -+ result = FONT_SIZE_XX_LARGE; -+ break ; -+ case FONT_SIZE_INHERIT: -+ cr_utils_trace_info ("can't return a bigger size for FONT_SIZE_INHERIT") ; -+ result = FONT_SIZE_MEDIUM ; -+ break ; -+ default: -+ cr_utils_trace_info ("Unknown FONT_SIZE") ; -+ result = FONT_SIZE_MEDIUM ; -+ break ; -+ } -+ *a_larger_size = result ; -+} -+ -+/** -+ * cr_font_size_is_predefined_absolute_font_size: -+ * @a_font_size: the font size to consider. -+ * -+ * Returns TRUE if the instance is an predefined absolute font size, FALSE -+ * otherwise. -+ */ -+gboolean -+cr_font_size_is_predefined_absolute_font_size -+ (enum CRPredefinedAbsoluteFontSize a_font_size) -+{ -+ if (a_font_size >= FONT_SIZE_XX_SMALL -+ && a_font_size < NB_PREDEFINED_ABSOLUTE_FONT_SIZES) { -+ return TRUE ; -+ } else { -+ return FALSE ; -+ } -+} -+ -+/** -+ * cr_font_size_adjust_to_string: -+ * @a_this: the instance of #CRFontSizeAdjust. -+ * -+ * Returns the serialized form of #CRFontSizeAdjust -+ */ -+gchar * -+cr_font_size_adjust_to_string (CRFontSizeAdjust const * a_this) -+{ -+ gchar *str = NULL; -+ -+ if (!a_this) { -+ str = g_strdup ("NULL"); -+ g_return_val_if_fail (str, NULL); -+ return str; -+ } -+ -+ switch (a_this->type) { -+ case FONT_SIZE_ADJUST_NONE: -+ str = g_strdup ("none"); -+ break; -+ case FONT_SIZE_ADJUST_NUMBER: -+ if (a_this->num) -+ str = (gchar *) cr_num_to_string (a_this->num); -+ else -+ str = g_strdup ("unknown font-size-adjust property value"); /* Should raise an error no?*/ -+ break; -+ case FONT_SIZE_ADJUST_INHERIT: -+ str = g_strdup ("inherit"); -+ } -+ return str; -+} -+ -+/** -+ * cr_font_style_to_string: -+ * @a_code: the current instance of #CRFontStyle . -+ * -+ * Returns the serialized #CRFontStyle. The caller must free the returned -+ * string using g_free(). -+ */ -+const gchar * -+cr_font_style_to_string (enum CRFontStyle a_code) -+{ -+ gchar *str = NULL; -+ -+ switch (a_code) { -+ case FONT_STYLE_NORMAL: -+ str = (gchar *) "normal"; -+ break; -+ case FONT_STYLE_ITALIC: -+ str = (gchar *) "italic"; -+ break; -+ case FONT_STYLE_OBLIQUE: -+ str = (gchar *) "oblique"; -+ break; -+ case FONT_STYLE_INHERIT: -+ str = (gchar *) "inherit"; -+ break; -+ default: -+ str = (gchar *) "unknown font style value"; -+ break; -+ } -+ return str; -+} -+ -+/** -+ * cr_font_variant_to_string: -+ * @a_code: the current instance of #CRFontVariant. -+ * -+ * Returns the serialized form of #CRFontVariant. The caller has -+ * to free the returned string using g_free(). -+ */ -+const gchar * -+cr_font_variant_to_string (enum CRFontVariant a_code) -+{ -+ gchar *str = NULL; -+ -+ switch (a_code) { -+ case FONT_VARIANT_NORMAL: -+ str = (gchar *) "normal"; -+ break; -+ case FONT_VARIANT_SMALL_CAPS: -+ str = (gchar *) "small-caps"; -+ break; -+ case FONT_VARIANT_INHERIT: -+ str = (gchar *) "inherit"; -+ break; -+ } -+ return str; -+} -+ -+/** -+ * cr_font_weight_get_bolder: -+ * @a_weight: the #CRFontWeight to consider. -+ * -+ * Returns a font weight bolder than @a_weight -+ */ -+enum CRFontWeight -+cr_font_weight_get_bolder (enum CRFontWeight a_weight) -+{ -+ if (a_weight == FONT_WEIGHT_INHERIT) { -+ cr_utils_trace_info ("can't return a bolder weight for FONT_WEIGHT_INHERIT") ; -+ return a_weight; -+ } else if (a_weight >= FONT_WEIGHT_900) { -+ return FONT_WEIGHT_900 ; -+ } else if (a_weight < FONT_WEIGHT_NORMAL) { -+ return FONT_WEIGHT_NORMAL ; -+ } else if (a_weight == FONT_WEIGHT_BOLDER -+ || a_weight == FONT_WEIGHT_LIGHTER) { -+ cr_utils_trace_info ("FONT_WEIGHT_BOLDER or FONT_WEIGHT_LIGHTER should not appear here") ; -+ return FONT_WEIGHT_NORMAL ; -+ } else { -+ return a_weight << 1 ; -+ } -+} -+ -+/** -+ * cr_font_weight_to_string: -+ * @a_code: the font weight to consider. -+ * -+ * Returns the serialized form of #CRFontWeight. -+ */ -+const gchar * -+cr_font_weight_to_string (enum CRFontWeight a_code) -+{ -+ gchar *str = NULL; -+ -+ switch (a_code) { -+ case FONT_WEIGHT_NORMAL: -+ str = (gchar *) "normal"; -+ break; -+ case FONT_WEIGHT_BOLD: -+ str = (gchar *) "bold"; -+ break; -+ case FONT_WEIGHT_BOLDER: -+ str = (gchar *) "bolder"; -+ break; -+ case FONT_WEIGHT_LIGHTER: -+ str = (gchar *) "lighter"; -+ break; -+ case FONT_WEIGHT_100: -+ str = (gchar *) "100"; -+ break; -+ case FONT_WEIGHT_200: -+ str = (gchar *) "200"; -+ break; -+ case FONT_WEIGHT_300: -+ str = (gchar *) "300"; -+ break; -+ case FONT_WEIGHT_400: -+ str = (gchar *) "400"; -+ break; -+ case FONT_WEIGHT_500: -+ str = (gchar *) "500"; -+ break; -+ case FONT_WEIGHT_600: -+ str = (gchar *) "600"; -+ break; -+ case FONT_WEIGHT_700: -+ str = (gchar *) "700"; -+ break; -+ case FONT_WEIGHT_800: -+ str = (gchar *) "800"; -+ break; -+ case FONT_WEIGHT_900: -+ str = (gchar *) "900"; -+ break; -+ case FONT_WEIGHT_INHERIT: -+ str = (gchar *) "inherit"; -+ break; -+ default: -+ str = (gchar *) "unknown font-weight property value"; -+ break; -+ } -+ return str; -+} -+ -+/** -+ * cr_font_stretch_to_string: -+ * @a_code: the instance of #CRFontStretch to consider. -+ * -+ * Returns the serialized form of #CRFontStretch. -+ */ -+const gchar * -+cr_font_stretch_to_string (enum CRFontStretch a_code) -+{ -+ gchar *str = NULL; -+ -+ switch (a_code) { -+ case FONT_STRETCH_NORMAL: -+ str = (gchar *) "normal"; -+ break; -+ case FONT_STRETCH_WIDER: -+ str = (gchar *) "wider"; -+ break; -+ case FONT_STRETCH_NARROWER: -+ str = (gchar *) "narrower"; -+ break; -+ case FONT_STRETCH_ULTRA_CONDENSED: -+ str = (gchar *) "ultra-condensed"; -+ break; -+ case FONT_STRETCH_EXTRA_CONDENSED: -+ str = (gchar *) "extra-condensed"; -+ break; -+ case FONT_STRETCH_CONDENSED: -+ str = (gchar *) "condensed"; -+ break; -+ case FONT_STRETCH_SEMI_CONDENSED: -+ str = (gchar *) "semi-condensed"; -+ break; -+ case FONT_STRETCH_SEMI_EXPANDED: -+ str = (gchar *) "semi-expanded"; -+ break; -+ case FONT_STRETCH_EXPANDED: -+ str = (gchar *) "expanded"; -+ break; -+ case FONT_STRETCH_EXTRA_EXPANDED: -+ str = (gchar *) "extra-expaned"; -+ break; -+ case FONT_STRETCH_ULTRA_EXPANDED: -+ str = (gchar *) "ultra-expanded"; -+ break; -+ case FONT_STRETCH_INHERIT: -+ str = (gchar *) "inherit"; -+ break; -+ } -+ return str; -+} -+ -+/** -+ * cr_font_size_destroy: -+ * @a_font_size: the font size to destroy -+ * -+ */ -+void -+cr_font_size_destroy (CRFontSize * a_font_size) -+{ -+ g_return_if_fail (a_font_size); -+ -+ g_free (a_font_size) ; -+} -+ -+/******************************************************* -+ *'font-size-adjust' manipulation function definition -+ *******************************************************/ -+ -+/** -+ * cr_font_size_adjust_new: -+ * -+ * Returns a newly built instance of #CRFontSizeAdjust -+ */ -+CRFontSizeAdjust * -+cr_font_size_adjust_new (void) -+{ -+ CRFontSizeAdjust *result = NULL; -+ -+ result = g_try_malloc (sizeof (CRFontSizeAdjust)); -+ if (!result) { -+ cr_utils_trace_info ("Out of memory"); -+ return NULL; -+ } -+ memset (result, 0, sizeof (CRFontSizeAdjust)); -+ -+ return result; -+} -+ -+/** -+ * cr_font_size_adjust_destroy: -+ * @a_this: the current instance of #CRFontSizeAdjust. -+ * -+ */ -+void -+cr_font_size_adjust_destroy (CRFontSizeAdjust * a_this) -+{ -+ g_return_if_fail (a_this); -+ -+ if (a_this->type == FONT_SIZE_ADJUST_NUMBER && a_this->num) { -+ cr_num_destroy (a_this->num); -+ a_this->num = NULL; -+ } -+} -diff --git a/src/st/croco/cr-fonts.h b/src/st/croco/cr-fonts.h -new file mode 100644 -index 000000000..9eaeeeb98 ---- /dev/null -+++ b/src/st/croco/cr-fonts.h -@@ -0,0 +1,315 @@ -+/* -*- Mode: C; indent-tabs-mode:nil; c-basic-offset: 8-*- */ -+ -+/* -+ * This file is part of The Croco Library -+ * -+ * 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 -+ * See COPYRIGHTS file for copyright information. -+ */ -+ -+#ifndef __CR_FONTS_H__ -+#define __CR_FONTS_H__ -+ -+#include "cr-utils.h" -+#include "cr-num.h" -+ -+/** -+ *@file -+ *Various type declarations about font selection related -+ *properties. -+ */ -+G_BEGIN_DECLS -+ -+ -+enum CRFontFamilyType -+{ -+ FONT_FAMILY_SANS_SERIF, -+ FONT_FAMILY_SERIF, -+ FONT_FAMILY_CURSIVE, -+ FONT_FAMILY_FANTASY, -+ FONT_FAMILY_MONOSPACE, -+ FONT_FAMILY_NON_GENERIC, -+ FONT_FAMILY_INHERIT, -+ /**/ -+ NB_FONT_FAMILIE_TYPES -+} ; -+ -+typedef struct _CRFontFamily CRFontFamily ; -+ -+struct _CRFontFamily -+{ -+ enum CRFontFamilyType type ; -+ -+ /* -+ *The name of the font family, in case -+ *it is non generic. -+ *Is set only if the type is FONT_FAMILY_NON_GENERIC. -+ */ -+ guchar *name ; -+ -+ CRFontFamily *next ; -+ CRFontFamily *prev ; -+} ; -+ -+ -+/** -+ *The different types -+ *of absolute font size. -+ *This is used by the 'font-size' -+ *property defined in css2 spec -+ *in chapter 15.2.4 . -+ *These values a indexes of -+ *table of size so please, do not -+ *change their definition order unless -+ *you know what you are doing. -+ */ -+enum CRPredefinedAbsoluteFontSize -+{ -+ FONT_SIZE_XX_SMALL=0, -+ FONT_SIZE_X_SMALL, -+ FONT_SIZE_SMALL, -+ FONT_SIZE_MEDIUM, -+ FONT_SIZE_LARGE, -+ FONT_SIZE_X_LARGE, -+ FONT_SIZE_XX_LARGE, -+ FONT_SIZE_INHERIT, -+ NB_PREDEFINED_ABSOLUTE_FONT_SIZES -+} ; -+ -+/** -+ *The different types -+ *of relative font size. -+ *This is used by the 'font-size' -+ *property defined in css2 spec -+ *in chapter 15.2.4 . -+ *These values a indexes of -+ *table of size so please, do not -+ *change their definition order unless -+ *you know what you are doing. -+ */ -+enum CRRelativeFontSize -+{ -+ FONT_SIZE_LARGER, -+ FONT_SIZE_SMALLER, -+ NB_RELATIVE_FONT_SIZE -+} ; -+ -+/** -+ *The type of font-size property. -+ *Used to define the type of #CRFontSize . -+ *See css2 spec chapter 15.2.4 to understand. -+ */ -+enum CRFontSizeType { -+ /** -+ *If the type of #CRFontSize is -+ *PREDEFINED_ABSOLUTE_FONT_SIZE, -+ *the CRFontSize::value.predefined_absolute -+ *field will be defined. -+ */ -+ PREDEFINED_ABSOLUTE_FONT_SIZE, -+ -+ /** -+ *If the type of #CRFontSize is -+ *ABSOLUTE_FONT_SIZE, -+ *the CRFontSize::value.absolute -+ *field will be defined. -+ */ -+ ABSOLUTE_FONT_SIZE, -+ -+ /** -+ *If the type of #CRFontSize is -+ *RELATIVE_FONT_SIZE, -+ *the CRFontSize::value.relative -+ *field will be defined. -+ */ -+ RELATIVE_FONT_SIZE, -+ -+ /** -+ *If the type of #CRFontSize is -+ *INHERITED_FONT_SIZE, -+ *the None of the field of the CRFontSize::value enum -+ *will be defined. -+ */ -+ INHERITED_FONT_SIZE, -+ -+ NB_FONT_SIZE_TYPE -+} ; -+ -+typedef struct _CRFontSize CRFontSize ; -+struct _CRFontSize { -+ enum CRFontSizeType type ; -+ union { -+ enum CRPredefinedAbsoluteFontSize predefined ; -+ enum CRRelativeFontSize relative ; -+ CRNum absolute ; -+ } value; -+} ; -+ -+enum CRFontSizeAdjustType -+{ -+ FONT_SIZE_ADJUST_NONE = 0, -+ FONT_SIZE_ADJUST_NUMBER, -+ FONT_SIZE_ADJUST_INHERIT -+} ; -+typedef struct _CRFontSizeAdjust CRFontSizeAdjust ; -+struct _CRFontSizeAdjust -+{ -+ enum CRFontSizeAdjustType type ; -+ CRNum *num ; -+} ; -+ -+enum CRFontStyle -+{ -+ FONT_STYLE_NORMAL=0, -+ FONT_STYLE_ITALIC, -+ FONT_STYLE_OBLIQUE, -+ FONT_STYLE_INHERIT -+} ; -+ -+enum CRFontVariant -+{ -+ FONT_VARIANT_NORMAL=0, -+ FONT_VARIANT_SMALL_CAPS, -+ FONT_VARIANT_INHERIT -+} ; -+ -+enum CRFontWeight -+{ -+ FONT_WEIGHT_NORMAL = 1, -+ FONT_WEIGHT_BOLD = 1<<1, -+ FONT_WEIGHT_BOLDER = 1<<2, -+ FONT_WEIGHT_LIGHTER = 1<<3, -+ FONT_WEIGHT_100 = 1<<4, -+ FONT_WEIGHT_200 = 1<<5, -+ FONT_WEIGHT_300 = 1<<6, -+ FONT_WEIGHT_400 = 1<<7, -+ FONT_WEIGHT_500 = 1<<8, -+ FONT_WEIGHT_600 = 1<<9, -+ FONT_WEIGHT_700 = 1<<10, -+ FONT_WEIGHT_800 = 1<<11, -+ FONT_WEIGHT_900 = 1<<12, -+ FONT_WEIGHT_INHERIT = 1<<13, -+ NB_FONT_WEIGHTS -+} ; -+ -+enum CRFontStretch -+{ -+ FONT_STRETCH_NORMAL=0, -+ FONT_STRETCH_WIDER, -+ FONT_STRETCH_NARROWER, -+ FONT_STRETCH_ULTRA_CONDENSED, -+ FONT_STRETCH_EXTRA_CONDENSED, -+ FONT_STRETCH_CONDENSED, -+ FONT_STRETCH_SEMI_CONDENSED, -+ FONT_STRETCH_SEMI_EXPANDED, -+ FONT_STRETCH_EXPANDED, -+ FONT_STRETCH_EXTRA_EXPANDED, -+ FONT_STRETCH_ULTRA_EXPANDED, -+ FONT_STRETCH_INHERIT -+} ; -+ -+/************************************** -+ *'font-family' manipulation functions -+ ***************************************/ -+CRFontFamily * -+cr_font_family_new (enum CRFontFamilyType a_type, guchar *a_name) ; -+ -+CRFontFamily * -+cr_font_family_append (CRFontFamily *a_this, -+ CRFontFamily *a_family_to_append) ; -+ -+guchar * -+cr_font_family_to_string (CRFontFamily const *a_this, -+ gboolean a_walk_font_family_list) ; -+ -+CRFontFamily * -+cr_font_family_prepend (CRFontFamily *a_this, -+ CRFontFamily *a_family_to_prepend); -+ -+enum CRStatus -+cr_font_family_destroy (CRFontFamily *a_this) ; -+ -+enum CRStatus -+cr_font_family_set_name (CRFontFamily *a_this, guchar *a_name) ; -+ -+ -+/************************************ -+ *'font-size' manipulation functions -+ ***********************************/ -+ -+CRFontSize * cr_font_size_new (void) ; -+ -+enum CRStatus cr_font_size_clear (CRFontSize *a_this) ; -+ -+enum CRStatus cr_font_size_copy (CRFontSize *a_dst, -+ CRFontSize const *a_src) ; -+enum CRStatus cr_font_size_set_predefined_absolute_font_size (CRFontSize *a_this, -+ enum CRPredefinedAbsoluteFontSize a_predefined) ; -+enum CRStatus cr_font_size_set_relative_font_size (CRFontSize *a_this, -+ enum CRRelativeFontSize a_relative) ; -+ -+enum CRStatus cr_font_size_set_absolute_font_size (CRFontSize *a_this, -+ enum CRNumType a_num_type, -+ gdouble a_value) ; -+ -+enum CRStatus cr_font_size_set_to_inherit (CRFontSize *a_this) ; -+ -+gboolean cr_font_size_is_set_to_inherit (CRFontSize const *a_this) ; -+ -+gchar* cr_font_size_to_string (CRFontSize const *a_this) ; -+ -+void cr_font_size_destroy (CRFontSize *a_font_size) ; -+ -+/******************************************************* -+ *'font-size-adjust' manipulation function declarations -+ *******************************************************/ -+ -+CRFontSizeAdjust * cr_font_size_adjust_new (void) ; -+ -+gchar * cr_font_size_adjust_to_string (CRFontSizeAdjust const *a_this) ; -+ -+void cr_font_size_adjust_destroy (CRFontSizeAdjust *a_this) ; -+ -+void -+cr_font_size_get_smaller_predefined_font_size (enum CRPredefinedAbsoluteFontSize a_font_size, -+ enum CRPredefinedAbsoluteFontSize *a_smaller_size) ; -+void -+cr_font_size_get_larger_predefined_font_size (enum CRPredefinedAbsoluteFontSize a_font_size, -+ enum CRPredefinedAbsoluteFontSize *a_larger_size) ; -+ -+gboolean -+cr_font_size_is_predefined_absolute_font_size (enum CRPredefinedAbsoluteFontSize a_font_size) ; -+ -+/*********************************** -+ *various other font related functions -+ ***********************************/ -+const gchar * cr_font_style_to_string (enum CRFontStyle a_code) ; -+ -+const gchar * cr_font_weight_to_string (enum CRFontWeight a_code) ; -+ -+enum CRFontWeight -+cr_font_weight_get_bolder (enum CRFontWeight a_weight) ; -+ -+const gchar * cr_font_variant_to_string (enum CRFontVariant a_code) ; -+ -+const gchar * cr_font_stretch_to_string (enum CRFontStretch a_code) ; -+ -+G_END_DECLS -+ -+#endif -diff --git a/src/st/croco/cr-input.c b/src/st/croco/cr-input.c -new file mode 100644 -index 000000000..3b63a88ee ---- /dev/null -+++ b/src/st/croco/cr-input.c -@@ -0,0 +1,1191 @@ -+/* -*- Mode: C; indent-tabs-mode: nil; c-basic-offset: 8-*- */ -+ -+/* -+ * This file is part of The Croco Library -+ * -+ * 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 -+ * See COPYRIGHTS file for copyright information. -+ */ -+ -+#include "stdio.h" -+#include -+#include "cr-input.h" -+#include "cr-enc-handler.h" -+ -+/** -+ *@CRInput: -+ * -+ *The definition of the #CRInput class. -+ */ -+ -+/******************* -+ *Private type defs -+ *******************/ -+ -+/** -+ *The private attributes of -+ *the #CRInputPriv class. -+ */ -+struct _CRInputPriv { -+ /* -+ *The input buffer -+ */ -+ guchar *in_buf; -+ gulong in_buf_size; -+ -+ gulong nb_bytes; -+ -+ /* -+ *The index of the next byte -+ *to be read. -+ */ -+ gulong next_byte_index; -+ -+ /* -+ *The current line number -+ */ -+ gulong line; -+ -+ /* -+ *The current col number -+ */ -+ gulong col; -+ -+ gboolean end_of_line; -+ gboolean end_of_input; -+ -+ /* -+ *the reference count of this -+ *instance. -+ */ -+ guint ref_count; -+ gboolean free_in_buf; -+}; -+ -+#define PRIVATE(object) (object)->priv -+ -+/*************************** -+ *private constants -+ **************************/ -+#define CR_INPUT_MEM_CHUNK_SIZE 1024 * 4 -+ -+static CRInput *cr_input_new_real (void); -+ -+static CRInput * -+cr_input_new_real (void) -+{ -+ CRInput *result = NULL; -+ -+ result = g_try_malloc (sizeof (CRInput)); -+ if (!result) { -+ cr_utils_trace_info ("Out of memory"); -+ return NULL; -+ } -+ memset (result, 0, sizeof (CRInput)); -+ -+ PRIVATE (result) = g_try_malloc (sizeof (CRInputPriv)); -+ if (!PRIVATE (result)) { -+ cr_utils_trace_info ("Out of memory"); -+ g_free (result); -+ return NULL; -+ } -+ memset (PRIVATE (result), 0, sizeof (CRInputPriv)); -+ PRIVATE (result)->free_in_buf = TRUE; -+ return result; -+} -+ -+/**************** -+ *Public methods -+ ***************/ -+ -+/** -+ * cr_input_new_from_buf: -+ *@a_buf: the memory buffer to create the input stream from. -+ *The #CRInput keeps this pointer so user should not free it !. -+ *@a_len: the size of the input buffer. -+ *@a_enc: the buffer's encoding. -+ *@a_free_buf: if set to TRUE, this a_buf will be freed -+ *at the destruction of this instance. If set to false, it is up -+ *to the caller to free it. -+ * -+ *Creates a new input stream from a memory buffer. -+ *Returns the newly built instance of #CRInput. -+ */ -+CRInput * -+cr_input_new_from_buf (guchar * a_buf, -+ gulong a_len, -+ enum CREncoding a_enc, -+ gboolean a_free_buf) -+{ -+ CRInput *result = NULL; -+ enum CRStatus status = CR_OK; -+ CREncHandler *enc_handler = NULL; -+ gulong len = a_len; -+ -+ g_return_val_if_fail (a_buf, NULL); -+ -+ result = cr_input_new_real (); -+ g_return_val_if_fail (result, NULL); -+ -+ /*transform the encoding in utf8 */ -+ if (a_enc != CR_UTF_8) { -+ enc_handler = cr_enc_handler_get_instance (a_enc); -+ if (!enc_handler) { -+ goto error; -+ } -+ -+ status = cr_enc_handler_convert_input -+ (enc_handler, a_buf, &len, -+ &PRIVATE (result)->in_buf, -+ &PRIVATE (result)->in_buf_size); -+ if (status != CR_OK) -+ goto error; -+ PRIVATE (result)->free_in_buf = TRUE; -+ if (a_free_buf == TRUE && a_buf) { -+ g_free (a_buf) ; -+ a_buf = NULL ; -+ } -+ PRIVATE (result)->nb_bytes = PRIVATE (result)->in_buf_size; -+ } else { -+ PRIVATE (result)->in_buf = (guchar *) a_buf; -+ PRIVATE (result)->in_buf_size = a_len; -+ PRIVATE (result)->nb_bytes = a_len; -+ PRIVATE (result)->free_in_buf = a_free_buf; -+ } -+ PRIVATE (result)->line = 1; -+ PRIVATE (result)->col = 0; -+ return result; -+ -+ error: -+ if (result) { -+ cr_input_destroy (result); -+ result = NULL; -+ } -+ -+ return NULL; -+} -+ -+/** -+ * cr_input_new_from_uri: -+ *@a_file_uri: the file to create *the input stream from. -+ *@a_enc: the encoding of the file *to create the input from. -+ * -+ *Creates a new input stream from -+ *a file. -+ * -+ *Returns the newly created input stream if -+ *this method could read the file and create it, -+ *NULL otherwise. -+ */ -+ -+CRInput * -+cr_input_new_from_uri (const gchar * a_file_uri, enum CREncoding a_enc) -+{ -+ CRInput *result = NULL; -+ enum CRStatus status = CR_OK; -+ FILE *file_ptr = NULL; -+ guchar tmp_buf[CR_INPUT_MEM_CHUNK_SIZE] = { 0 }; -+ gulong nb_read = 0, -+ len = 0, -+ buf_size = 0; -+ gboolean loop = TRUE; -+ guchar *buf = NULL; -+ -+ g_return_val_if_fail (a_file_uri, NULL); -+ -+ file_ptr = fopen (a_file_uri, "r"); -+ -+ if (file_ptr == NULL) { -+ -+#ifdef CR_DEBUG -+ cr_utils_trace_debug ("could not open file"); -+#endif -+ g_warning ("Could not open file %s\n", a_file_uri); -+ -+ return NULL; -+ } -+ -+ /*load the file */ -+ while (loop) { -+ nb_read = fread (tmp_buf, 1 /*read bytes */ , -+ CR_INPUT_MEM_CHUNK_SIZE /*nb of bytes */ , -+ file_ptr); -+ -+ if (nb_read != CR_INPUT_MEM_CHUNK_SIZE) { -+ /*we read less chars than we wanted */ -+ if (feof (file_ptr)) { -+ /*we reached eof */ -+ loop = FALSE; -+ } else { -+ /*a pb occurred !! */ -+ cr_utils_trace_debug ("an io error occurred"); -+ status = CR_ERROR; -+ goto cleanup; -+ } -+ } -+ -+ if (status == CR_OK) { -+ /*read went well */ -+ buf = g_realloc (buf, len + CR_INPUT_MEM_CHUNK_SIZE); -+ memcpy (buf + len, tmp_buf, nb_read); -+ len += nb_read; -+ buf_size += CR_INPUT_MEM_CHUNK_SIZE; -+ } -+ } -+ -+ if (status == CR_OK) { -+ result = cr_input_new_from_buf (buf, len, a_enc, TRUE); -+ if (!result) { -+ goto cleanup; -+ } -+ /* -+ *we should free buf here because it's own by CRInput. -+ *(see the last parameter of cr_input_new_from_buf(). -+ */ -+ buf = NULL; -+ } -+ -+ cleanup: -+ if (file_ptr) { -+ fclose (file_ptr); -+ file_ptr = NULL; -+ } -+ -+ if (buf) { -+ g_free (buf); -+ buf = NULL; -+ } -+ -+ return result; -+} -+ -+/** -+ * cr_input_destroy: -+ *@a_this: the current instance of #CRInput. -+ * -+ *The destructor of the #CRInput class. -+ */ -+void -+cr_input_destroy (CRInput * a_this) -+{ -+ if (a_this == NULL) -+ return; -+ -+ if (PRIVATE (a_this)) { -+ if (PRIVATE (a_this)->in_buf && PRIVATE (a_this)->free_in_buf) { -+ g_free (PRIVATE (a_this)->in_buf); -+ PRIVATE (a_this)->in_buf = NULL; -+ } -+ -+ g_free (PRIVATE (a_this)); -+ PRIVATE (a_this) = NULL; -+ } -+ -+ g_free (a_this); -+} -+ -+/** -+ * cr_input_ref: -+ *@a_this: the current instance of #CRInput. -+ * -+ *Increments the reference count of the current -+ *instance of #CRInput. -+ */ -+void -+cr_input_ref (CRInput * a_this) -+{ -+ g_return_if_fail (a_this && PRIVATE (a_this)); -+ -+ PRIVATE (a_this)->ref_count++; -+} -+ -+/** -+ * cr_input_unref: -+ *@a_this: the current instance of #CRInput. -+ * -+ *Decrements the reference count of this instance -+ *of #CRInput. If the reference count goes down to -+ *zero, this instance is destroyed. -+ * -+ * Returns TRUE if the instance of #CRInput got destroyed, false otherwise. -+ */ -+gboolean -+cr_input_unref (CRInput * a_this) -+{ -+ g_return_val_if_fail (a_this && PRIVATE (a_this), FALSE); -+ -+ if (PRIVATE (a_this)->ref_count) { -+ PRIVATE (a_this)->ref_count--; -+ } -+ -+ if (PRIVATE (a_this)->ref_count == 0) { -+ cr_input_destroy (a_this); -+ return TRUE; -+ } -+ return FALSE; -+} -+ -+/** -+ * cr_input_end_of_input: -+ *@a_this: the current instance of #CRInput. -+ *@a_end_of_input: out parameter. Is set to TRUE if -+ *the current instance has reached the end of its input buffer, -+ *FALSE otherwise. -+ * -+ *Tests wether the current instance of -+ *#CRInput has reached its input buffer. -+ * -+ * Returns CR_OK upon successful completion, an error code otherwise. -+ * Note that all the out parameters of this method are valid if -+ * and only if this method returns CR_OK. -+ */ -+enum CRStatus -+cr_input_end_of_input (CRInput const * a_this, gboolean * a_end_of_input) -+{ -+ g_return_val_if_fail (a_this && PRIVATE (a_this) -+ && a_end_of_input, CR_BAD_PARAM_ERROR); -+ -+ *a_end_of_input = (PRIVATE (a_this)->next_byte_index -+ >= PRIVATE (a_this)->in_buf_size) ? TRUE : FALSE; -+ -+ return CR_OK; -+} -+ -+/** -+ * cr_input_get_nb_bytes_left: -+ *@a_this: the current instance of #CRInput. -+ * -+ *Returns the number of bytes left in the input stream -+ *before the end, -1 in case of error. -+ */ -+glong -+cr_input_get_nb_bytes_left (CRInput const * a_this) -+{ -+ g_return_val_if_fail (a_this && PRIVATE (a_this), -1); -+ g_return_val_if_fail (PRIVATE (a_this)->nb_bytes -+ <= PRIVATE (a_this)->in_buf_size, -1); -+ g_return_val_if_fail (PRIVATE (a_this)->next_byte_index -+ <= PRIVATE (a_this)->nb_bytes, -1); -+ -+ if (PRIVATE (a_this)->end_of_input) -+ return 0; -+ -+ return PRIVATE (a_this)->nb_bytes - PRIVATE (a_this)->next_byte_index; -+} -+ -+/** -+ * cr_input_read_byte: -+ *@a_this: the current instance of #CRInput. -+ *@a_byte: out parameter the returned byte. -+ * -+ *Gets the next byte of the input. -+ *Updates the state of the input so that -+ *the next invocation of this method returns -+ *the next coming byte. -+ * -+ *Returns CR_OK upon successful completion, an error code -+ *otherwise. All the out parameters of this method are valid if -+ *and only if this method returns CR_OK. -+ */ -+enum CRStatus -+cr_input_read_byte (CRInput * a_this, guchar * a_byte) -+{ -+ gulong nb_bytes_left = 0; -+ -+ g_return_val_if_fail (a_this && PRIVATE (a_this) -+ && a_byte, CR_BAD_PARAM_ERROR); -+ -+ g_return_val_if_fail (PRIVATE (a_this)->next_byte_index <= -+ PRIVATE (a_this)->nb_bytes, CR_BAD_PARAM_ERROR); -+ -+ if (PRIVATE (a_this)->end_of_input == TRUE) -+ return CR_END_OF_INPUT_ERROR; -+ -+ nb_bytes_left = cr_input_get_nb_bytes_left (a_this); -+ -+ if (nb_bytes_left < 1) { -+ return CR_END_OF_INPUT_ERROR; -+ } -+ -+ *a_byte = PRIVATE (a_this)->in_buf[PRIVATE (a_this)->next_byte_index]; -+ -+ if (PRIVATE (a_this)->nb_bytes - -+ PRIVATE (a_this)->next_byte_index < 2) { -+ PRIVATE (a_this)->end_of_input = TRUE; -+ } else { -+ PRIVATE (a_this)->next_byte_index++; -+ } -+ -+ return CR_OK; -+} -+ -+/** -+ * cr_input_read_char: -+ *@a_this: the current instance of CRInput. -+ *@a_char: out parameter. The read character. -+ * -+ *Reads an unicode character from the current instance of -+ *#CRInput. -+ * -+ *Returns CR_OK upon successful completion, an error code -+ *otherwise. -+ */ -+enum CRStatus -+cr_input_read_char (CRInput * a_this, guint32 * a_char) -+{ -+ enum CRStatus status = CR_OK; -+ gulong consumed = 0, -+ nb_bytes_left = 0; -+ -+ g_return_val_if_fail (a_this && PRIVATE (a_this) && a_char, -+ CR_BAD_PARAM_ERROR); -+ -+ if (PRIVATE (a_this)->end_of_input == TRUE) -+ return CR_END_OF_INPUT_ERROR; -+ -+ nb_bytes_left = cr_input_get_nb_bytes_left (a_this); -+ -+ if (nb_bytes_left < 1) { -+ return CR_END_OF_INPUT_ERROR; -+ } -+ -+ status = cr_utils_read_char_from_utf8_buf -+ (PRIVATE (a_this)->in_buf -+ + -+ PRIVATE (a_this)->next_byte_index, -+ nb_bytes_left, a_char, &consumed); -+ -+ if (status == CR_OK) { -+ /*update next byte index */ -+ PRIVATE (a_this)->next_byte_index += consumed; -+ -+ /*update line and column number */ -+ if (PRIVATE (a_this)->end_of_line == TRUE) { -+ PRIVATE (a_this)->col = 1; -+ PRIVATE (a_this)->line++; -+ PRIVATE (a_this)->end_of_line = FALSE; -+ } else if (*a_char != '\n') { -+ PRIVATE (a_this)->col++; -+ } -+ -+ if (*a_char == '\n') { -+ PRIVATE (a_this)->end_of_line = TRUE; -+ } -+ } -+ -+ return status; -+} -+ -+/** -+ * cr_input_set_line_num: -+ *@a_this: the "this pointer" of the current instance of #CRInput. -+ *@a_line_num: the new line number. -+ * -+ *Setter of the current line number. -+ * -+ *Return CR_OK upon successful completion, an error code otherwise. -+ */ -+enum CRStatus -+cr_input_set_line_num (CRInput * a_this, glong a_line_num) -+{ -+ g_return_val_if_fail (a_this && PRIVATE (a_this), CR_BAD_PARAM_ERROR); -+ -+ PRIVATE (a_this)->line = a_line_num; -+ -+ return CR_OK; -+} -+ -+/** -+ * cr_input_get_line_num: -+ *@a_this: the "this pointer" of the current instance of #CRInput. -+ *@a_line_num: the returned line number. -+ * -+ *Getter of the current line number. -+ * -+ *Returns CR_OK upon successful completion, an error code otherwise. -+ */ -+enum CRStatus -+cr_input_get_line_num (CRInput const * a_this, glong * a_line_num) -+{ -+ g_return_val_if_fail (a_this && PRIVATE (a_this) -+ && a_line_num, CR_BAD_PARAM_ERROR); -+ -+ *a_line_num = PRIVATE (a_this)->line; -+ -+ return CR_OK; -+} -+ -+/** -+ * cr_input_set_column_num: -+ *@a_this: the "this pointer" of the current instance of #CRInput. -+ *@a_col: the new column number. -+ * -+ *Setter of the current column number. -+ * -+ *Returns CR_OK upon successful completion, an error code otherwise. -+ */ -+enum CRStatus -+cr_input_set_column_num (CRInput * a_this, glong a_col) -+{ -+ g_return_val_if_fail (a_this && PRIVATE (a_this), CR_BAD_PARAM_ERROR); -+ -+ PRIVATE (a_this)->col = a_col; -+ -+ return CR_OK; -+} -+ -+/** -+ * cr_input_get_column_num: -+ *@a_this: the "this pointer" of the current instance of #CRInput. -+ *@a_col: out parameter -+ * -+ *Getter of the current column number. -+ * -+ *Returns CR_OK upon successful completion, an error code otherwise. -+ */ -+enum CRStatus -+cr_input_get_column_num (CRInput const * a_this, glong * a_col) -+{ -+ g_return_val_if_fail (a_this && PRIVATE (a_this) && a_col, -+ CR_BAD_PARAM_ERROR); -+ -+ *a_col = PRIVATE (a_this)->col; -+ -+ return CR_OK; -+} -+ -+/** -+ * cr_input_increment_line_num: -+ *@a_this: the "this pointer" of the current instance of #CRInput. -+ *@a_increment: the increment to add to the line number. -+ * -+ *Increments the current line number. -+ * -+ *Returns CR_OK upon successful completion, an error code otherwise. -+ */ -+enum CRStatus -+cr_input_increment_line_num (CRInput * a_this, glong a_increment) -+{ -+ g_return_val_if_fail (a_this && PRIVATE (a_this), CR_BAD_PARAM_ERROR); -+ -+ PRIVATE (a_this)->line += a_increment; -+ -+ return CR_OK; -+} -+ -+/** -+ * cr_input_increment_col_num: -+ *@a_this: the "this pointer" of the current instance of #CRInput. -+ *@a_increment: the increment to add to the column number. -+ * -+ *Increments the current column number. -+ * -+ *Returns CR_OK upon successful completion, an error code otherwise. -+ */ -+enum CRStatus -+cr_input_increment_col_num (CRInput * a_this, glong a_increment) -+{ -+ g_return_val_if_fail (a_this && PRIVATE (a_this), CR_BAD_PARAM_ERROR); -+ -+ PRIVATE (a_this)->col += a_increment; -+ -+ return CR_OK; -+} -+ -+/** -+ * cr_input_consume_char: -+ *@a_this: the this pointer. -+ *@a_char: the character to consume. If set to zero, -+ *consumes any character. -+ * -+ *Consumes the next character of the input stream if -+ *and only if that character equals a_char. -+ * -+ *Returns CR_OK upon successful completion, CR_PARSING_ERROR if -+ *next char is different from a_char, an other error code otherwise -+ */ -+enum CRStatus -+cr_input_consume_char (CRInput * a_this, guint32 a_char) -+{ -+ guint32 c; -+ enum CRStatus status; -+ -+ g_return_val_if_fail (a_this && PRIVATE (a_this), CR_BAD_PARAM_ERROR); -+ -+ if ((status = cr_input_peek_char (a_this, &c)) != CR_OK) { -+ return status; -+ } -+ -+ if (c == a_char || a_char == 0) { -+ status = cr_input_read_char (a_this, &c); -+ } else { -+ return CR_PARSING_ERROR; -+ } -+ -+ return status; -+} -+ -+/** -+ * cr_input_consume_chars: -+ *@a_this: the this pointer of the current instance of #CRInput. -+ *@a_char: the character to consume. -+ *@a_nb_char: in/out parameter. The number of characters to consume. -+ *If set to a negative value, the function will consume all the occurences -+ *of a_char found. -+ *After return, if the return value equals CR_OK, this variable contains -+ *the number of characters actually consumed. -+ * -+ *Consumes up to a_nb_char occurences of the next contiguous characters -+ *which equal a_char. Note that the next character of the input stream -+ **MUST* equal a_char to trigger the consumption, or else, the error -+ *code CR_PARSING_ERROR is returned. -+ *If the number of contiguous characters that equals a_char is less than -+ *a_nb_char, then this function consumes all the characters it can consume. -+ * -+ *Returns CR_OK if at least one character has been consumed, an error code -+ *otherwise. -+ */ -+enum CRStatus -+cr_input_consume_chars (CRInput * a_this, guint32 a_char, gulong * a_nb_char) -+{ -+ enum CRStatus status = CR_OK; -+ gulong nb_consumed = 0; -+ -+ g_return_val_if_fail (a_this && PRIVATE (a_this) && a_nb_char, -+ CR_BAD_PARAM_ERROR); -+ -+ g_return_val_if_fail (a_char != 0 || a_nb_char != NULL, -+ CR_BAD_PARAM_ERROR); -+ -+ for (nb_consumed = 0; ((status == CR_OK) -+ && (*a_nb_char > 0 -+ && nb_consumed < *a_nb_char)); -+ nb_consumed++) { -+ status = cr_input_consume_char (a_this, a_char); -+ } -+ -+ *a_nb_char = nb_consumed; -+ -+ if ((nb_consumed > 0) -+ && ((status == CR_PARSING_ERROR) -+ || (status == CR_END_OF_INPUT_ERROR))) { -+ status = CR_OK; -+ } -+ -+ return status; -+} -+ -+/** -+ * cr_input_consume_white_spaces: -+ *@a_this: the "this pointer" of the current instance of #CRInput. -+ *@a_nb_chars: in/out parameter. The number of white spaces to -+ *consume. After return, holds the number of white spaces actually consumed. -+ * -+ *Same as cr_input_consume_chars() but this one consumes white -+ *spaces. -+ * -+ *Returns CR_OK upon successful completion, an error code otherwise. -+ */ -+enum CRStatus -+cr_input_consume_white_spaces (CRInput * a_this, gulong * a_nb_chars) -+{ -+ enum CRStatus status = CR_OK; -+ guint32 cur_char = 0, -+ nb_consumed = 0; -+ -+ g_return_val_if_fail (a_this && PRIVATE (a_this) && a_nb_chars, -+ CR_BAD_PARAM_ERROR); -+ -+ for (nb_consumed = 0; -+ ((*a_nb_chars > 0) && (nb_consumed < *a_nb_chars)); -+ nb_consumed++) { -+ status = cr_input_peek_char (a_this, &cur_char); -+ if (status != CR_OK) -+ break; -+ -+ /*if the next char is a white space, consume it ! */ -+ if (cr_utils_is_white_space (cur_char) == TRUE) { -+ status = cr_input_read_char (a_this, &cur_char); -+ if (status != CR_OK) -+ break; -+ continue; -+ } -+ -+ break; -+ -+ } -+ -+ *a_nb_chars = (gulong) nb_consumed; -+ -+ if (nb_consumed && status == CR_END_OF_INPUT_ERROR) { -+ status = CR_OK; -+ } -+ -+ return status; -+} -+ -+/** -+ * cr_input_peek_char: -+ *@a_this: the current instance of #CRInput. -+ *@a_char: out parameter. The returned character. -+ * -+ *Same as cr_input_read_char() but does not update the -+ *internal state of the input stream. The next call -+ *to cr_input_peek_char() or cr_input_read_char() will thus -+ *return the same character as the current one. -+ * -+ *Returns CR_OK upon successful completion, an error code -+ *otherwise. -+ */ -+enum CRStatus -+cr_input_peek_char (CRInput const * a_this, guint32 * a_char) -+{ -+ enum CRStatus status = CR_OK; -+ gulong consumed = 0, -+ nb_bytes_left = 0; -+ -+ g_return_val_if_fail (a_this && PRIVATE (a_this) -+ && a_char, CR_BAD_PARAM_ERROR); -+ -+ if (PRIVATE (a_this)->next_byte_index >= -+ PRIVATE (a_this)->in_buf_size) { -+ return CR_END_OF_INPUT_ERROR; -+ } -+ -+ nb_bytes_left = cr_input_get_nb_bytes_left (a_this); -+ -+ if (nb_bytes_left < 1) { -+ return CR_END_OF_INPUT_ERROR; -+ } -+ -+ status = cr_utils_read_char_from_utf8_buf -+ (PRIVATE (a_this)->in_buf + -+ PRIVATE (a_this)->next_byte_index, -+ nb_bytes_left, a_char, &consumed); -+ -+ return status; -+} -+ -+/** -+ * cr_input_peek_byte: -+ *@a_this: the current instance of #CRInput. -+ *@a_origin: the origin to consider in the calculation -+ *of the position of the byte to peek. -+ *@a_offset: the offset of the byte to peek, starting from -+ *the origin specified by a_origin. -+ *@a_byte: out parameter the peeked byte. -+ * -+ *Gets a byte from the input stream, -+ *starting from the current position in the input stream. -+ *Unlike cr_input_peek_next_byte() this method -+ *does not update the state of the current input stream. -+ *Subsequent calls to cr_input_peek_byte with the same arguments -+ *will return the same byte. -+ * -+ *Returns CR_OK upon successful completion or, -+ *CR_BAD_PARAM_ERROR if at least one of the parameters is invalid; -+ *CR_OUT_OF_BOUNDS_ERROR if the indexed byte is out of bounds. -+ */ -+enum CRStatus -+cr_input_peek_byte (CRInput const * a_this, enum CRSeekPos a_origin, -+ gulong a_offset, guchar * a_byte) -+{ -+ gulong abs_offset = 0; -+ -+ g_return_val_if_fail (a_this && PRIVATE (a_this) -+ && a_byte, CR_BAD_PARAM_ERROR); -+ -+ switch (a_origin) { -+ -+ case CR_SEEK_CUR: -+ abs_offset = PRIVATE (a_this)->next_byte_index - 1 + a_offset; -+ break; -+ -+ case CR_SEEK_BEGIN: -+ abs_offset = a_offset; -+ break; -+ -+ case CR_SEEK_END: -+ abs_offset = PRIVATE (a_this)->in_buf_size - 1 - a_offset; -+ break; -+ -+ default: -+ return CR_BAD_PARAM_ERROR; -+ } -+ -+ if (abs_offset < PRIVATE (a_this)->in_buf_size) { -+ -+ *a_byte = PRIVATE (a_this)->in_buf[abs_offset]; -+ -+ return CR_OK; -+ -+ } else { -+ return CR_END_OF_INPUT_ERROR; -+ } -+} -+ -+/** -+ * cr_input_peek_byte2: -+ *@a_this: the current byte input stream. -+ *@a_offset: the offset of the byte to peek, starting -+ *from the current input position pointer. -+ *@a_eof: out parameter. Is set to true is we reach end of -+ *stream. If set to NULL by the caller, this parameter is not taken -+ *in account. -+ * -+ *Same as cr_input_peek_byte() but with a simplified -+ *interface. -+ * -+ *Returns the read byte or 0 if something bad happened. -+ */ -+guchar -+cr_input_peek_byte2 (CRInput const * a_this, gulong a_offset, gboolean * a_eof) -+{ -+ guchar result = 0; -+ enum CRStatus status = CR_ERROR; -+ -+ g_return_val_if_fail (a_this && PRIVATE (a_this), 0); -+ -+ if (a_eof) -+ *a_eof = FALSE; -+ -+ status = cr_input_peek_byte (a_this, CR_SEEK_CUR, a_offset, &result); -+ -+ if ((status == CR_END_OF_INPUT_ERROR) -+ && a_eof) -+ *a_eof = TRUE; -+ -+ return result; -+} -+ -+/** -+ * cr_input_get_byte_addr: -+ *@a_this: the current instance of #CRInput. -+ *@a_offset: the offset of the byte in the input stream starting -+ *from the beginning of the stream. -+ * -+ *Gets the memory address of the byte located at a given offset -+ *in the input stream. -+ * -+ *Returns the address, otherwise NULL if an error occurred. -+ */ -+guchar * -+cr_input_get_byte_addr (CRInput * a_this, gulong a_offset) -+{ -+ g_return_val_if_fail (a_this && PRIVATE (a_this), NULL); -+ -+ if (a_offset >= PRIVATE (a_this)->nb_bytes) { -+ return NULL; -+ } -+ -+ return &PRIVATE (a_this)->in_buf[a_offset]; -+} -+ -+/** -+ * cr_input_get_cur_byte_addr: -+ *@a_this: the current input stream -+ *@a_offset: out parameter. The returned address. -+ * -+ *Gets the address of the current character pointer. -+ * -+ *Returns CR_OK upon successful completion, an error code otherwise. -+ */ -+enum CRStatus -+cr_input_get_cur_byte_addr (CRInput * a_this, guchar ** a_offset) -+{ -+ g_return_val_if_fail (a_this && PRIVATE (a_this) && a_offset, -+ CR_BAD_PARAM_ERROR); -+ -+ if (!PRIVATE (a_this)->next_byte_index) { -+ return CR_START_OF_INPUT_ERROR; -+ } -+ -+ *a_offset = cr_input_get_byte_addr -+ (a_this, PRIVATE (a_this)->next_byte_index - 1); -+ -+ return CR_OK; -+} -+ -+/** -+ * cr_input_seek_index: -+ *@a_this: the current instance of #CRInput. -+ *@a_origin: the origin to consider during the calculation -+ *of the absolute position of the new "current byte index". -+ *@a_pos: the relative offset of the new "current byte index." -+ *This offset is relative to the origin a_origin. -+ * -+ *Sets the "current byte index" of the current instance -+ *of #CRInput. Next call to cr_input_get_byte() will return -+ *the byte next after the new "current byte index". -+ * -+ *Returns CR_OK upon successful completion otherwise returns -+ *CR_BAD_PARAM_ERROR if at least one of the parameters is not valid -+ *or CR_OUT_BOUNDS_ERROR in case of error. -+ */ -+enum CRStatus -+cr_input_seek_index (CRInput * a_this, enum CRSeekPos a_origin, gint a_pos) -+{ -+ -+ glong abs_offset = 0; -+ -+ g_return_val_if_fail (a_this && PRIVATE (a_this), CR_BAD_PARAM_ERROR); -+ -+ switch (a_origin) { -+ -+ case CR_SEEK_CUR: -+ abs_offset = PRIVATE (a_this)->next_byte_index - 1 + a_pos; -+ break; -+ -+ case CR_SEEK_BEGIN: -+ abs_offset = a_pos; -+ break; -+ -+ case CR_SEEK_END: -+ abs_offset = PRIVATE (a_this)->in_buf_size - 1 - a_pos; -+ break; -+ -+ default: -+ return CR_BAD_PARAM_ERROR; -+ } -+ -+ if ((abs_offset > 0) -+ && (gulong) abs_offset < PRIVATE (a_this)->nb_bytes) { -+ -+ /*update the input stream's internal state */ -+ PRIVATE (a_this)->next_byte_index = abs_offset + 1; -+ -+ return CR_OK; -+ } -+ -+ return CR_OUT_OF_BOUNDS_ERROR; -+} -+ -+/** -+ * cr_input_get_cur_pos: -+ *@a_this: the current instance of #CRInput. -+ *@a_pos: out parameter. The returned position. -+ * -+ *Gets the position of the "current byte index" which -+ *is basically the position of the last returned byte in the -+ *input stream. -+ * -+ *Returns CR_OK upon successful completion. Otherwise, -+ *CR_BAD_PARAMETER_ERROR if at least one of the arguments is invalid. -+ *CR_START_OF_INPUT if no call to either cr_input_read_byte() -+ *or cr_input_seek_index() have been issued before calling -+ *cr_input_get_cur_pos() -+ *Note that the out parameters of this function are valid if and only if this -+ *function returns CR_OK. -+ */ -+enum CRStatus -+cr_input_get_cur_pos (CRInput const * a_this, CRInputPos * a_pos) -+{ -+ g_return_val_if_fail (a_this && PRIVATE (a_this) && a_pos, -+ CR_BAD_PARAM_ERROR); -+ -+ a_pos->next_byte_index = PRIVATE (a_this)->next_byte_index; -+ a_pos->line = PRIVATE (a_this)->line; -+ a_pos->col = PRIVATE (a_this)->col; -+ a_pos->end_of_line = PRIVATE (a_this)->end_of_line; -+ a_pos->end_of_file = PRIVATE (a_this)->end_of_input; -+ -+ return CR_OK; -+} -+ -+/** -+ * cr_input_get_parsing_location: -+ *@a_this: the current instance of #CRInput -+ *@a_loc: the set parsing location. -+ * -+ *Gets the current parsing location. -+ *The Parsing location is a public datastructure that -+ *represents the current line/column/byte offset/ in the input -+ *stream. -+ * -+ *Returns CR_OK upon successful completion, an error -+ *code otherwise. -+ */ -+enum CRStatus -+cr_input_get_parsing_location (CRInput const *a_this, -+ CRParsingLocation *a_loc) -+{ -+ g_return_val_if_fail (a_this -+ && PRIVATE (a_this) -+ && a_loc, -+ CR_BAD_PARAM_ERROR) ; -+ -+ a_loc->line = PRIVATE (a_this)->line ; -+ a_loc->column = PRIVATE (a_this)->col ; -+ if (PRIVATE (a_this)->next_byte_index) { -+ a_loc->byte_offset = PRIVATE (a_this)->next_byte_index - 1 ; -+ } else { -+ a_loc->byte_offset = PRIVATE (a_this)->next_byte_index ; -+ } -+ return CR_OK ; -+} -+ -+/** -+ * cr_input_get_cur_index: -+ *@a_this: the "this pointer" of the current instance of -+ *#CRInput -+ *@a_index: out parameter. The returned index. -+ * -+ *Getter of the next byte index. -+ *It actually returns the index of the -+ *next byte to be read. -+ * -+ *Returns CR_OK upon successful completion, an error code -+ *otherwise. -+ */ -+enum CRStatus -+cr_input_get_cur_index (CRInput const * a_this, glong * a_index) -+{ -+ g_return_val_if_fail (a_this && PRIVATE (a_this) -+ && a_index, CR_BAD_PARAM_ERROR); -+ -+ *a_index = PRIVATE (a_this)->next_byte_index; -+ -+ return CR_OK; -+} -+ -+/** -+ * cr_input_set_cur_index: -+ *@a_this: the "this pointer" of the current instance -+ *of #CRInput . -+ *@a_index: the new index to set. -+ * -+ *Setter of the next byte index. -+ *It sets the index of the next byte to be read. -+ * -+ *Returns CR_OK upon successful completion, an error code otherwise. -+ */ -+enum CRStatus -+cr_input_set_cur_index (CRInput * a_this, glong a_index) -+{ -+ g_return_val_if_fail (a_this && PRIVATE (a_this), CR_BAD_PARAM_ERROR); -+ -+ PRIVATE (a_this)->next_byte_index = a_index; -+ -+ return CR_OK; -+} -+ -+/** -+ * cr_input_set_end_of_file: -+ *@a_this: the current instance of #CRInput. -+ *@a_eof: the new end of file flag. -+ * -+ *Sets the end of file flag. -+ * -+ *Returns CR_OK upon successful completion, an error code otherwise. -+ */ -+enum CRStatus -+cr_input_set_end_of_file (CRInput * a_this, gboolean a_eof) -+{ -+ g_return_val_if_fail (a_this && PRIVATE (a_this), CR_BAD_PARAM_ERROR); -+ -+ PRIVATE (a_this)->end_of_input = a_eof; -+ -+ return CR_OK; -+} -+ -+/** -+ * cr_input_get_end_of_file: -+ *@a_this: the current instance of #CRInput. -+ *@a_eof: out parameter the place to put the end of -+ *file flag. -+ * -+ *Gets the end of file flag. -+ * -+ *Returns CR_OK upon successful completion, an error code otherwise. -+ */ -+enum CRStatus -+cr_input_get_end_of_file (CRInput const * a_this, gboolean * a_eof) -+{ -+ g_return_val_if_fail (a_this && PRIVATE (a_this) -+ && a_eof, CR_BAD_PARAM_ERROR); -+ -+ *a_eof = PRIVATE (a_this)->end_of_input; -+ -+ return CR_OK; -+} -+ -+/** -+ * cr_input_set_end_of_line: -+ *@a_this: the current instance of #CRInput. -+ *@a_eol: the new end of line flag. -+ * -+ *Sets the end of line flag. -+ * -+ *Returns CR_OK upon successful completion, an error code -+ *otherwise. -+ */ -+enum CRStatus -+cr_input_set_end_of_line (CRInput * a_this, gboolean a_eol) -+{ -+ g_return_val_if_fail (a_this && PRIVATE (a_this), CR_BAD_PARAM_ERROR); -+ -+ PRIVATE (a_this)->end_of_line = a_eol; -+ -+ return CR_OK; -+} -+ -+/** -+ * cr_input_get_end_of_line: -+ *@a_this: the current instance of #CRInput -+ *@a_eol: out parameter. The place to put -+ *the returned flag -+ * -+ *Gets the end of line flag of the current input. -+ * -+ *Returns CR_OK upon successful completion, an error code -+ *otherwise. -+ */ -+enum CRStatus -+cr_input_get_end_of_line (CRInput const * a_this, gboolean * a_eol) -+{ -+ g_return_val_if_fail (a_this && PRIVATE (a_this) -+ && a_eol, CR_BAD_PARAM_ERROR); -+ -+ *a_eol = PRIVATE (a_this)->end_of_line; -+ -+ return CR_OK; -+} -+ -+/** -+ * cr_input_set_cur_pos: -+ *@a_this: the "this pointer" of the current instance of -+ *#CRInput. -+ *@a_pos: the new position. -+ * -+ *Sets the current position in the input stream. -+ * -+ * Returns CR_OK upon successful completion, an error code otherwise. -+ */ -+enum CRStatus -+cr_input_set_cur_pos (CRInput * a_this, CRInputPos const * a_pos) -+{ -+ g_return_val_if_fail (a_this && PRIVATE (a_this) && a_pos, -+ CR_BAD_PARAM_ERROR); -+ -+ cr_input_set_column_num (a_this, a_pos->col); -+ cr_input_set_line_num (a_this, a_pos->line); -+ cr_input_set_cur_index (a_this, a_pos->next_byte_index); -+ cr_input_set_end_of_line (a_this, a_pos->end_of_line); -+ cr_input_set_end_of_file (a_this, a_pos->end_of_file); -+ -+ return CR_OK; -+} -diff --git a/src/st/croco/cr-input.h b/src/st/croco/cr-input.h -new file mode 100644 -index 000000000..9eb402a87 ---- /dev/null -+++ b/src/st/croco/cr-input.h -@@ -0,0 +1,174 @@ -+/* -*- Mode: C; indent-tabs-mode:nil; c-basic-offset:8 -*- */ -+ -+/* -+ * This file is part of The Croco Library -+ * -+ * 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 -+ * See the COPYRIGHTS file for copyrights information. -+ */ -+ -+#ifndef __CR_INPUT_SRC_H__ -+#define __CR_INPUT_SRC_H__ -+ -+ -+#include -+#include "cr-utils.h" -+#include "cr-parsing-location.h" -+ -+G_BEGIN_DECLS -+ -+/** -+ *@file -+ *The libcroco basic input stream class -+ *declaration file. -+ */ -+ -+typedef struct _CRInput CRInput ; -+typedef struct _CRInputPriv CRInputPriv ; -+ -+/** -+ *The #CRInput class provides the abstraction of -+ *an utf8-encoded character stream. -+ */ -+struct _CRInput -+{ -+ CRInputPriv *priv ; -+} ; -+ -+typedef struct _CRInputPos CRInputPos ; -+ -+struct _CRInputPos -+{ -+ glong line ; -+ glong col ; -+ gboolean end_of_file ; -+ gboolean end_of_line ; -+ glong next_byte_index ; -+} ; -+ -+CRInput * -+cr_input_new_from_buf (guchar *a_buf, gulong a_len, -+ enum CREncoding a_enc, gboolean a_free_buf) ; -+CRInput * -+cr_input_new_from_uri (const gchar *a_file_uri, -+ enum CREncoding a_enc) ; -+ -+void -+cr_input_destroy (CRInput *a_this) ; -+ -+void -+cr_input_ref (CRInput *a_this) ; -+ -+gboolean -+cr_input_unref (CRInput *a_this) ; -+ -+enum CRStatus -+cr_input_read_byte (CRInput *a_this, guchar *a_byte) ; -+ -+enum CRStatus -+cr_input_read_char (CRInput *a_this, guint32 *a_char) ; -+ -+enum CRStatus -+cr_input_consume_chars (CRInput *a_this, guint32 a_char, -+ gulong *a_nb_char) ; -+ -+enum CRStatus -+cr_input_consume_char (CRInput *a_this, guint32 a_char) ; -+ -+enum CRStatus -+cr_input_consume_white_spaces (CRInput *a_this, gulong *a_nb_chars) ; -+ -+enum CRStatus -+cr_input_peek_byte (CRInput const *a_this, enum CRSeekPos a_origin, -+ gulong a_offset, guchar *a_byte) ; -+ -+guchar -+cr_input_peek_byte2 (CRInput const *a_this, gulong a_offset, -+ gboolean *a_eof) ; -+ -+enum CRStatus -+cr_input_peek_char (CRInput const *a_this, guint32 *a_char) ; -+ -+guchar * -+cr_input_get_byte_addr (CRInput *a_this, -+ gulong a_offset) ; -+ -+enum CRStatus -+cr_input_get_cur_byte_addr (CRInput *a_this, guchar ** a_offset) ; -+ -+enum CRStatus -+cr_input_seek_index (CRInput *a_this, -+ enum CRSeekPos a_origin, gint a_pos) ; -+ -+enum CRStatus -+cr_input_get_cur_index (CRInput const *a_this, glong *a_index) ; -+ -+enum CRStatus -+cr_input_set_cur_index (CRInput *a_this, glong a_index) ; -+ -+enum CRStatus -+cr_input_get_cur_pos (CRInput const *a_this, CRInputPos * a_pos) ; -+ -+enum CRStatus -+cr_input_set_cur_pos (CRInput *a_this, CRInputPos const *a_pos) ; -+ -+enum CRStatus -+cr_input_get_parsing_location (CRInput const *a_this, -+ CRParsingLocation *a_loc) ; -+ -+enum CRStatus -+cr_input_get_end_of_line (CRInput const *a_this, gboolean *a_eol) ; -+ -+enum CRStatus -+cr_input_set_end_of_line (CRInput *a_this, gboolean a_eol) ; -+ -+enum CRStatus -+cr_input_get_end_of_file (CRInput const *a_this, gboolean *a_eof) ; -+ -+enum CRStatus -+cr_input_set_end_of_file (CRInput *a_this, gboolean a_eof) ; -+ -+enum CRStatus -+cr_input_set_line_num (CRInput *a_this, glong a_line_num) ; -+ -+enum CRStatus -+cr_input_get_line_num (CRInput const *a_this, glong *a_line_num) ; -+ -+enum CRStatus -+cr_input_set_column_num (CRInput *a_this, glong a_col) ; -+ -+enum CRStatus -+cr_input_get_column_num (CRInput const *a_this, glong *a_col) ; -+ -+enum CRStatus -+cr_input_increment_line_num (CRInput *a_this, -+ glong a_increment) ; -+ -+enum CRStatus -+cr_input_increment_col_num (CRInput *a_this, -+ glong a_increment) ; -+ -+glong -+cr_input_get_nb_bytes_left (CRInput const *a_this) ; -+ -+enum CRStatus -+cr_input_end_of_input (CRInput const *a_this, gboolean *a_end_of_input) ; -+ -+G_END_DECLS -+ -+#endif /*__CR_INPUT_SRC_H__*/ -+ -diff --git a/src/st/croco/cr-num.c b/src/st/croco/cr-num.c -new file mode 100644 -index 000000000..d5dbd5fb0 ---- /dev/null -+++ b/src/st/croco/cr-num.c -@@ -0,0 +1,313 @@ -+/* -*- Mode: C; indent-tabs-mode:nil; c-basic-offset: 8-*- */ -+ -+/* -+ * This file is part of The Croco Library -+ * -+ * -+ * 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 -+ * See COPYRIGHTS file for copyrights information. -+ */ -+ -+/** -+ *@CRNum: -+ * -+ *The definition -+ *of the #CRNum class. -+ */ -+ -+#include "cr-num.h" -+#include "string.h" -+ -+/** -+ * cr_num_new: -+ * -+ *#CRNum. -+ * -+ *Returns the newly built instance of -+ *#CRNum. -+ */ -+CRNum * -+cr_num_new (void) -+{ -+ CRNum *result = NULL; -+ -+ result = g_try_malloc (sizeof (CRNum)); -+ -+ if (result == NULL) { -+ cr_utils_trace_info ("Out of memory"); -+ return NULL; -+ } -+ -+ memset (result, 0, sizeof (CRNum)); -+ -+ return result; -+} -+ -+/** -+ * cr_num_new_with_val: -+ * @a_val: the numerical value of the number. -+ * @a_type: the type of number. -+ * -+ * A constructor of #CRNum. -+ * -+ * Returns the newly built instance of #CRNum or -+ * NULL if an error arises. -+ */ -+CRNum * -+cr_num_new_with_val (gdouble a_val, enum CRNumType a_type) -+{ -+ CRNum *result = NULL; -+ -+ result = cr_num_new (); -+ -+ g_return_val_if_fail (result, NULL); -+ -+ result->val = a_val; -+ result->type = a_type; -+ -+ return result; -+} -+ -+/** -+ * cr_num_to_string: -+ *@a_this: the current instance of #CRNum. -+ * -+ *Returns the newly built string representation -+ *of the current instance of #CRNum. The returned -+ *string is NULL terminated. The caller *must* -+ *free the returned string. -+ */ -+guchar * -+cr_num_to_string (CRNum const * a_this) -+{ -+ gdouble test_val = 0.0; -+ -+ guchar *tmp_char1 = NULL, -+ *tmp_char2 = NULL, -+ *result = NULL; -+ -+ g_return_val_if_fail (a_this, NULL); -+ -+ test_val = a_this->val - (glong) a_this->val; -+ -+ if (!test_val) { -+ tmp_char1 = (guchar *) g_strdup_printf ("%ld", (glong) a_this->val); -+ } else { -+ tmp_char1 = (guchar *) g_new0 (char, G_ASCII_DTOSTR_BUF_SIZE + 1); -+ if (tmp_char1 != NULL) -+ g_ascii_dtostr ((gchar *) tmp_char1, G_ASCII_DTOSTR_BUF_SIZE, a_this->val); -+ } -+ -+ g_return_val_if_fail (tmp_char1, NULL); -+ -+ switch (a_this->type) { -+ case NUM_LENGTH_EM: -+ tmp_char2 = (guchar *) "em"; -+ break; -+ -+ case NUM_LENGTH_EX: -+ tmp_char2 = (guchar *) "ex"; -+ break; -+ -+ case NUM_LENGTH_PX: -+ tmp_char2 = (guchar *) "px"; -+ break; -+ -+ case NUM_LENGTH_IN: -+ tmp_char2 = (guchar *) "in"; -+ break; -+ -+ case NUM_LENGTH_CM: -+ tmp_char2 = (guchar *) "cm"; -+ break; -+ -+ case NUM_LENGTH_MM: -+ tmp_char2 = (guchar *) "mm"; -+ break; -+ -+ case NUM_LENGTH_PT: -+ tmp_char2 = (guchar *) "pt"; -+ break; -+ -+ case NUM_LENGTH_PC: -+ tmp_char2 = (guchar *) "pc"; -+ break; -+ -+ case NUM_ANGLE_DEG: -+ tmp_char2 = (guchar *) "deg"; -+ break; -+ -+ case NUM_ANGLE_RAD: -+ tmp_char2 = (guchar *) "rad"; -+ break; -+ -+ case NUM_ANGLE_GRAD: -+ tmp_char2 = (guchar *) "grad"; -+ break; -+ -+ case NUM_TIME_MS: -+ tmp_char2 = (guchar *) "ms"; -+ break; -+ -+ case NUM_TIME_S: -+ tmp_char2 = (guchar *) "s"; -+ break; -+ -+ case NUM_FREQ_HZ: -+ tmp_char2 = (guchar *) "Hz"; -+ break; -+ -+ case NUM_FREQ_KHZ: -+ tmp_char2 = (guchar *) "KHz"; -+ break; -+ -+ case NUM_PERCENTAGE: -+ tmp_char2 = (guchar *) "%"; -+ break; -+ case NUM_INHERIT: -+ tmp_char2 = (guchar *) "inherit"; -+ break ; -+ case NUM_AUTO: -+ tmp_char2 = (guchar *) "auto"; -+ break ; -+ case NUM_GENERIC: -+ tmp_char2 = NULL ; -+ break ; -+ default: -+ tmp_char2 = (guchar *) "unknown"; -+ break; -+ } -+ -+ if (tmp_char2) { -+ result = (guchar *) g_strconcat ((gchar *) tmp_char1, tmp_char2, NULL); -+ g_free (tmp_char1); -+ } else { -+ result = tmp_char1; -+ } -+ -+ return result; -+} -+ -+/** -+ * cr_num_copy: -+ *@a_src: the instance of #CRNum to copy. -+ *Must be non NULL. -+ *@a_dest: the destination of the copy. -+ *Must be non NULL -+ * -+ *Copies an instance of #CRNum. -+ * -+ *Returns CR_OK upon successful completion, an -+ *error code otherwise. -+ */ -+enum CRStatus -+cr_num_copy (CRNum * a_dest, CRNum const * a_src) -+{ -+ g_return_val_if_fail (a_dest && a_src, CR_BAD_PARAM_ERROR); -+ -+ memcpy (a_dest, a_src, sizeof (CRNum)); -+ -+ return CR_OK; -+} -+ -+/** -+ * cr_num_dup: -+ *@a_this: the instance of #CRNum to duplicate. -+ * -+ *Duplicates an instance of #CRNum -+ * -+ *Returns the newly created (duplicated) instance of #CRNum. -+ *Must be freed by cr_num_destroy(). -+ */ -+CRNum * -+cr_num_dup (CRNum const * a_this) -+{ -+ CRNum *result = NULL; -+ enum CRStatus status = CR_OK; -+ -+ g_return_val_if_fail (a_this, NULL); -+ -+ result = cr_num_new (); -+ g_return_val_if_fail (result, NULL); -+ -+ status = cr_num_copy (result, a_this); -+ g_return_val_if_fail (status == CR_OK, NULL); -+ -+ return result; -+} -+ -+/** -+ * cr_num_set: -+ *Sets an instance of #CRNum. -+ *@a_this: the current instance of #CRNum to be set. -+ *@a_val: the new numerical value to be hold by the current -+ *instance of #CRNum -+ *@a_type: the new type of #CRNum. -+ * -+ * Returns CR_OK upon succesful completion, an error code otherwise. -+ */ -+enum CRStatus -+cr_num_set (CRNum * a_this, gdouble a_val, enum CRNumType a_type) -+{ -+ g_return_val_if_fail (a_this, CR_BAD_PARAM_ERROR); -+ -+ a_this->val = a_val; -+ a_this->type = a_type; -+ -+ return CR_OK; -+} -+ -+/** -+ * cr_num_is_fixed_length: -+ * @a_this: the current instance of #CRNum . -+ * -+ *Tests if the current instance of #CRNum is a fixed -+ *length value or not. Typically a fixed length value -+ *is anything from NUM_LENGTH_EM to NUM_LENGTH_PC. -+ *See the definition of #CRNumType to see what we mean. -+ * -+ *Returns TRUE if the instance of #CRNum is a fixed length number, -+ *FALSE otherwise. -+ */ -+gboolean -+cr_num_is_fixed_length (CRNum const * a_this) -+{ -+ gboolean result = FALSE; -+ -+ g_return_val_if_fail (a_this, FALSE); -+ -+ if (a_this->type >= NUM_LENGTH_EM -+ && a_this->type <= NUM_LENGTH_PC) { -+ result = TRUE ; -+ } -+ return result ; -+} -+ -+/** -+ * cr_num_destroy: -+ *@a_this: the this pointer of -+ *the current instance of #CRNum. -+ * -+ *The destructor of #CRNum. -+ */ -+void -+cr_num_destroy (CRNum * a_this) -+{ -+ g_return_if_fail (a_this); -+ -+ g_free (a_this); -+} -diff --git a/src/st/croco/cr-num.h b/src/st/croco/cr-num.h -new file mode 100644 -index 000000000..2b73aaf79 ---- /dev/null -+++ b/src/st/croco/cr-num.h -@@ -0,0 +1,127 @@ -+/* -*- Mode: C; indent-tabs-mode:nil; c-basic-offset: 8-*- */ -+ -+/* -+ * This file is part of The Croco Library -+ * -+ * 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 -+ * See COPYRIGHTS file for copyright information -+ */ -+ -+ -+/** -+ *@file -+ *The declaration -+ *of the #CRNum class. -+ */ -+ -+#ifndef __CR_NUM_H__ -+#define __CR_NUM_H__ -+ -+#include -+#include "cr-utils.h" -+#include "cr-parsing-location.h" -+ -+G_BEGIN_DECLS -+ -+/** -+ *@file -+ *The declaration of the #CRNum class. -+ * -+ */ -+ -+/** -+ *The different types -+ *of numbers. -+ *Please, do not modify -+ *the declaration order of the enum -+ *members, unless you know -+ *what you are doing. -+ */ -+enum CRNumType -+{ -+ NUM_AUTO = 0, -+ NUM_GENERIC, -+ NUM_LENGTH_EM, -+ NUM_LENGTH_EX, -+ NUM_LENGTH_PX, -+ NUM_LENGTH_IN, -+ NUM_LENGTH_CM, -+ NUM_LENGTH_MM, -+ NUM_LENGTH_PT, -+ NUM_LENGTH_PC, -+ NUM_ANGLE_DEG, -+ NUM_ANGLE_RAD, -+ NUM_ANGLE_GRAD, -+ NUM_TIME_MS, -+ NUM_TIME_S, -+ NUM_FREQ_HZ, -+ NUM_FREQ_KHZ, -+ NUM_PERCENTAGE, -+ NUM_INHERIT, -+ NUM_UNKNOWN_TYPE, -+ NB_NUM_TYPE -+} ; -+ -+ -+/** -+ *An abstraction of a number (num) -+ *as defined in the css2 spec. -+ */ -+typedef struct _CRNum CRNum ; -+ -+/** -+ *An abstraction of a number (num) -+ *as defined in the css2 spec. -+ */ -+struct _CRNum -+{ -+ enum CRNumType type ; -+ gdouble val ; -+ CRParsingLocation location ; -+} ; -+ -+CRNum * -+cr_num_new (void) ; -+ -+CRNum * -+cr_num_new_with_val (gdouble a_val, -+ enum CRNumType a_type) ; -+ -+CRNum * -+cr_num_dup (CRNum const *a_this) ; -+ -+guchar * -+cr_num_to_string (CRNum const *a_this) ; -+ -+enum CRStatus -+cr_num_copy (CRNum *a_dest, CRNum const *a_src) ; -+ -+enum CRStatus -+cr_num_set (CRNum *a_this, gdouble a_val, -+ enum CRNumType a_type) ; -+ -+gboolean -+cr_num_is_fixed_length (CRNum const *a_this) ; -+ -+void -+cr_num_destroy (CRNum *a_this) ; -+ -+ -+G_END_DECLS -+ -+ -+#endif /*__CR_NUM_H__*/ -diff --git a/src/st/croco/cr-om-parser.c b/src/st/croco/cr-om-parser.c -new file mode 100644 -index 000000000..ccc45b3e9 ---- /dev/null -+++ b/src/st/croco/cr-om-parser.c -@@ -0,0 +1,1142 @@ -+/* -*- Mode: C; indent-tabs-mode:nil; c-basic-offset: 8-*- */ -+ -+/* -+ * This file is part of The Croco Library -+ * -+ * 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 -+ * See COPYRIGHTS file for copyright information. -+ */ -+ -+#include -+#include "cr-utils.h" -+#include "cr-om-parser.h" -+ -+/** -+ *@CROMParser: -+ * -+ *The definition of the CSS Object Model Parser. -+ *This parser uses (and sits) the SAC api of libcroco defined -+ *in cr-parser.h and cr-doc-handler.h -+ */ -+ -+struct _CROMParserPriv { -+ CRParser *parser; -+}; -+ -+#define PRIVATE(a_this) ((a_this)->priv) -+ -+/* -+ *Forward declaration of a type defined later -+ *in this file. -+ */ -+struct _ParsingContext; -+typedef struct _ParsingContext ParsingContext; -+ -+static ParsingContext *new_parsing_context (void); -+ -+static void destroy_context (ParsingContext * a_ctxt); -+ -+static void unrecoverable_error (CRDocHandler * a_this); -+ -+static void error (CRDocHandler * a_this); -+ -+static void property (CRDocHandler * a_this, -+ CRString * a_name, -+ CRTerm * a_expression, -+ gboolean a_important); -+ -+static void end_selector (CRDocHandler * a_this, -+ CRSelector * a_selector_list); -+ -+static void start_selector (CRDocHandler * a_this, -+ CRSelector * a_selector_list); -+ -+static void start_font_face (CRDocHandler * a_this, -+ CRParsingLocation *a_location); -+ -+static void end_font_face (CRDocHandler * a_this); -+ -+static void end_document (CRDocHandler * a_this); -+ -+static void start_document (CRDocHandler * a_this); -+ -+static void charset (CRDocHandler * a_this, -+ CRString * a_charset, -+ CRParsingLocation *a_location); -+ -+static void start_page (CRDocHandler * a_this, CRString * a_page, -+ CRString * a_pseudo_page, -+ CRParsingLocation *a_location); -+ -+static void end_page (CRDocHandler * a_this, CRString * a_page, -+ CRString * a_pseudo_page); -+ -+static void start_media (CRDocHandler * a_this, -+ GList * a_media_list, -+ CRParsingLocation *a_location); -+ -+static void end_media (CRDocHandler * a_this, -+ GList * a_media_list); -+ -+static void import_style (CRDocHandler * a_this, -+ GList * a_media_list, -+ CRString * a_uri, -+ CRString * a_uri_default_ns, -+ CRParsingLocation *a_location); -+ -+struct _ParsingContext { -+ CRStyleSheet *stylesheet; -+ CRStatement *cur_stmt; -+ CRStatement *cur_media_stmt; -+}; -+ -+/******************************************** -+ *Private methods -+ ********************************************/ -+ -+static ParsingContext * -+new_parsing_context (void) -+{ -+ ParsingContext *result = NULL; -+ -+ result = g_try_malloc (sizeof (ParsingContext)); -+ if (!result) { -+ cr_utils_trace_info ("Out of Memory"); -+ return NULL; -+ } -+ memset (result, 0, sizeof (ParsingContext)); -+ return result; -+} -+ -+static void -+destroy_context (ParsingContext * a_ctxt) -+{ -+ g_return_if_fail (a_ctxt); -+ -+ if (a_ctxt->stylesheet) { -+ cr_stylesheet_destroy (a_ctxt->stylesheet); -+ a_ctxt->stylesheet = NULL; -+ } -+ if (a_ctxt->cur_stmt) { -+ cr_statement_destroy (a_ctxt->cur_stmt); -+ a_ctxt->cur_stmt = NULL; -+ } -+ g_free (a_ctxt); -+} -+ -+static enum CRStatus -+cr_om_parser_init_default_sac_handler (CROMParser * a_this) -+{ -+ CRDocHandler *sac_handler = NULL; -+ gboolean created_handler = FALSE; -+ enum CRStatus status = CR_OK; -+ -+ g_return_val_if_fail (a_this && PRIVATE (a_this) -+ && PRIVATE (a_this)->parser, -+ CR_BAD_PARAM_ERROR); -+ -+ status = cr_parser_get_sac_handler (PRIVATE (a_this)->parser, -+ &sac_handler); -+ g_return_val_if_fail (status == CR_OK, status); -+ -+ if (!sac_handler) { -+ sac_handler = cr_doc_handler_new (); -+ created_handler = TRUE; -+ } -+ -+ /* -+ *initialyze here the sac handler. -+ */ -+ sac_handler->start_document = start_document; -+ sac_handler->end_document = end_document; -+ sac_handler->start_selector = start_selector; -+ sac_handler->end_selector = end_selector; -+ sac_handler->property = property; -+ sac_handler->start_font_face = start_font_face; -+ sac_handler->end_font_face = end_font_face; -+ sac_handler->error = error; -+ sac_handler->unrecoverable_error = unrecoverable_error; -+ sac_handler->charset = charset; -+ sac_handler->start_page = start_page; -+ sac_handler->end_page = end_page; -+ sac_handler->start_media = start_media; -+ sac_handler->end_media = end_media; -+ sac_handler->import_style = import_style; -+ -+ if (created_handler) { -+ status = cr_parser_set_sac_handler (PRIVATE (a_this)->parser, -+ sac_handler); -+ cr_doc_handler_unref (sac_handler); -+ } -+ -+ return status; -+ -+} -+ -+static void -+start_document (CRDocHandler * a_this) -+{ -+ ParsingContext *ctxt = NULL; -+ CRStyleSheet *stylesheet = NULL; -+ -+ g_return_if_fail (a_this); -+ -+ ctxt = new_parsing_context (); -+ g_return_if_fail (ctxt); -+ -+ stylesheet = cr_stylesheet_new (NULL); -+ ctxt->stylesheet = stylesheet; -+ cr_doc_handler_set_ctxt (a_this, ctxt); -+} -+ -+static void -+start_font_face (CRDocHandler * a_this, -+ CRParsingLocation *a_location) -+{ -+ enum CRStatus status = CR_OK; -+ ParsingContext *ctxt = NULL; -+ ParsingContext **ctxtptr = NULL; -+ -+ g_return_if_fail (a_this); -+ -+ g_return_if_fail (a_this); -+ ctxtptr = &ctxt; -+ status = cr_doc_handler_get_ctxt (a_this, (gpointer *) ctxtptr); -+ g_return_if_fail (status == CR_OK && ctxt); -+ g_return_if_fail (ctxt->cur_stmt == NULL); -+ -+ ctxt->cur_stmt = -+ cr_statement_new_at_font_face_rule (ctxt->stylesheet, NULL); -+ -+ g_return_if_fail (ctxt->cur_stmt); -+} -+ -+static void -+end_font_face (CRDocHandler * a_this) -+{ -+ enum CRStatus status = CR_OK; -+ ParsingContext *ctxt = NULL; -+ ParsingContext **ctxtptr = NULL; -+ CRStatement *stmts = NULL; -+ -+ g_return_if_fail (a_this); -+ -+ g_return_if_fail (a_this); -+ ctxtptr = &ctxt; -+ status = cr_doc_handler_get_ctxt (a_this, (gpointer *) ctxtptr); -+ g_return_if_fail (status == CR_OK && ctxt); -+ g_return_if_fail -+ (ctxt->cur_stmt -+ && ctxt->cur_stmt->type == AT_FONT_FACE_RULE_STMT -+ && ctxt->stylesheet); -+ -+ stmts = cr_statement_append (ctxt->stylesheet->statements, -+ ctxt->cur_stmt); -+ if (!stmts) -+ goto error; -+ -+ ctxt->stylesheet->statements = stmts; -+ stmts = NULL; -+ ctxt->cur_stmt = NULL; -+ -+ return; -+ -+ error: -+ -+ if (ctxt->cur_stmt) { -+ cr_statement_destroy (ctxt->cur_stmt); -+ ctxt->cur_stmt = NULL; -+ } -+ -+ if (!stmts) { -+ cr_statement_destroy (stmts); -+ stmts = NULL; -+ } -+} -+ -+static void -+end_document (CRDocHandler * a_this) -+{ -+ enum CRStatus status = CR_OK; -+ ParsingContext *ctxt = NULL; -+ ParsingContext **ctxtptr = NULL; -+ -+ g_return_if_fail (a_this); -+ ctxtptr = &ctxt; -+ status = cr_doc_handler_get_ctxt (a_this, (gpointer *) ctxtptr); -+ g_return_if_fail (status == CR_OK && ctxt); -+ -+ if (!ctxt->stylesheet || ctxt->cur_stmt) -+ goto error; -+ -+ status = cr_doc_handler_set_result (a_this, ctxt->stylesheet); -+ g_return_if_fail (status == CR_OK); -+ -+ ctxt->stylesheet = NULL; -+ destroy_context (ctxt); -+ cr_doc_handler_set_ctxt (a_this, NULL); -+ -+ return; -+ -+ error: -+ if (ctxt) { -+ destroy_context (ctxt); -+ } -+} -+ -+static void -+charset (CRDocHandler * a_this, CRString * a_charset, -+ CRParsingLocation *a_location) -+{ -+ enum CRStatus status = CR_OK; -+ CRStatement *stmt = NULL, -+ *stmt2 = NULL; -+ CRString *charset = NULL; -+ -+ ParsingContext *ctxt = NULL; -+ ParsingContext **ctxtptr = NULL; -+ -+ g_return_if_fail (a_this); -+ ctxtptr = &ctxt; -+ status = cr_doc_handler_get_ctxt (a_this, (gpointer *) ctxtptr); -+ g_return_if_fail (status == CR_OK && ctxt); -+ g_return_if_fail (ctxt->stylesheet); -+ -+ charset = cr_string_dup (a_charset) ; -+ stmt = cr_statement_new_at_charset_rule (ctxt->stylesheet, charset); -+ g_return_if_fail (stmt); -+ stmt2 = cr_statement_append (ctxt->stylesheet->statements, stmt); -+ if (!stmt2) { -+ if (stmt) { -+ cr_statement_destroy (stmt); -+ stmt = NULL; -+ } -+ if (charset) { -+ cr_string_destroy (charset); -+ } -+ return; -+ } -+ ctxt->stylesheet->statements = stmt2; -+ stmt2 = NULL; -+} -+ -+static void -+start_page (CRDocHandler * a_this, -+ CRString * a_page, -+ CRString * a_pseudo, -+ CRParsingLocation *a_location) -+{ -+ enum CRStatus status = CR_OK; -+ ParsingContext *ctxt = NULL; -+ ParsingContext **ctxtptr = NULL; -+ -+ g_return_if_fail (a_this); -+ ctxtptr = &ctxt; -+ status = cr_doc_handler_get_ctxt (a_this, (gpointer *) ctxtptr); -+ g_return_if_fail (status == CR_OK && ctxt); -+ g_return_if_fail (ctxt->cur_stmt == NULL); -+ -+ ctxt->cur_stmt = cr_statement_new_at_page_rule -+ (ctxt->stylesheet, NULL, NULL, NULL); -+ if (a_page) { -+ ctxt->cur_stmt->kind.page_rule->name = -+ cr_string_dup (a_page) ; -+ -+ if (!ctxt->cur_stmt->kind.page_rule->name) { -+ goto error; -+ } -+ } -+ if (a_pseudo) { -+ ctxt->cur_stmt->kind.page_rule->pseudo = -+ cr_string_dup (a_pseudo) ; -+ if (!ctxt->cur_stmt->kind.page_rule->pseudo) { -+ goto error; -+ } -+ } -+ return; -+ -+ error: -+ if (ctxt->cur_stmt) { -+ cr_statement_destroy (ctxt->cur_stmt); -+ ctxt->cur_stmt = NULL; -+ } -+} -+ -+static void -+end_page (CRDocHandler * a_this, -+ CRString * a_page, -+ CRString * a_pseudo_page) -+{ -+ enum CRStatus status = CR_OK; -+ ParsingContext *ctxt = NULL; -+ ParsingContext **ctxtptr = NULL; -+ CRStatement *stmt = NULL; -+ -+ (void) a_page; -+ (void) a_pseudo_page; -+ -+ g_return_if_fail (a_this); -+ -+ ctxtptr = &ctxt; -+ status = cr_doc_handler_get_ctxt (a_this, (gpointer *) ctxtptr); -+ -+ g_return_if_fail (status == CR_OK && ctxt); -+ -+ g_return_if_fail (ctxt->cur_stmt -+ && ctxt->cur_stmt->type == AT_PAGE_RULE_STMT -+ && ctxt->stylesheet); -+ -+ stmt = cr_statement_append (ctxt->stylesheet->statements, -+ ctxt->cur_stmt); -+ -+ if (stmt) { -+ ctxt->stylesheet->statements = stmt; -+ stmt = NULL; -+ ctxt->cur_stmt = NULL; -+ } -+ -+ if (ctxt->cur_stmt) { -+ cr_statement_destroy (ctxt->cur_stmt); -+ ctxt->cur_stmt = NULL; -+ } -+ a_page = NULL; /*keep compiler happy */ -+ a_pseudo_page = NULL; /*keep compiler happy */ -+} -+ -+static void -+start_media (CRDocHandler * a_this, -+ GList * a_media_list, -+ CRParsingLocation *a_location) -+{ -+ enum CRStatus status = CR_OK; -+ ParsingContext *ctxt = NULL; -+ ParsingContext **ctxtptr = NULL; -+ GList *media_list = NULL; -+ -+ g_return_if_fail (a_this); -+ ctxtptr = &ctxt; -+ status = cr_doc_handler_get_ctxt (a_this, (gpointer *) ctxtptr); -+ g_return_if_fail (status == CR_OK && ctxt); -+ -+ g_return_if_fail (ctxt -+ && ctxt->cur_stmt == NULL -+ && ctxt->cur_media_stmt == NULL -+ && ctxt->stylesheet); -+ if (a_media_list) { -+ /*duplicate the media_list */ -+ media_list = cr_utils_dup_glist_of_cr_string -+ (a_media_list); -+ } -+ ctxt->cur_media_stmt = -+ cr_statement_new_at_media_rule -+ (ctxt->stylesheet, NULL, media_list); -+ -+} -+ -+static void -+end_media (CRDocHandler * a_this, GList * a_media_list) -+{ -+ enum CRStatus status = CR_OK; -+ ParsingContext *ctxt = NULL; -+ ParsingContext **ctxtptr = NULL; -+ CRStatement *stmts = NULL; -+ -+ (void) a_media_list; -+ -+ g_return_if_fail (a_this); -+ -+ ctxtptr = &ctxt; -+ status = cr_doc_handler_get_ctxt (a_this, (gpointer *) ctxtptr); -+ -+ g_return_if_fail (status == CR_OK && ctxt); -+ -+ g_return_if_fail (ctxt -+ && ctxt->cur_media_stmt -+ && ctxt->cur_media_stmt->type == AT_MEDIA_RULE_STMT -+ && ctxt->stylesheet); -+ -+ stmts = cr_statement_append (ctxt->stylesheet->statements, -+ ctxt->cur_media_stmt); -+ -+ if (!stmts) { -+ cr_statement_destroy (ctxt->cur_media_stmt); -+ ctxt->cur_media_stmt = NULL; -+ } -+ -+ ctxt->stylesheet->statements = stmts; -+ stmts = NULL; -+ -+ ctxt->cur_stmt = NULL ; -+ ctxt->cur_media_stmt = NULL ; -+ a_media_list = NULL; -+} -+ -+static void -+import_style (CRDocHandler * a_this, -+ GList * a_media_list, -+ CRString * a_uri, -+ CRString * a_uri_default_ns, -+ CRParsingLocation *a_location) -+{ -+ enum CRStatus status = CR_OK; -+ CRString *uri = NULL; -+ CRStatement *stmt = NULL, -+ *stmt2 = NULL; -+ ParsingContext *ctxt = NULL; -+ ParsingContext **ctxtptr = NULL; -+ GList *media_list = NULL ; -+ -+ (void) a_uri_default_ns; -+ -+ g_return_if_fail (a_this); -+ -+ ctxtptr = &ctxt; -+ status = cr_doc_handler_get_ctxt (a_this, (gpointer *) ctxtptr); -+ -+ g_return_if_fail (status == CR_OK && ctxt); -+ -+ g_return_if_fail (ctxt->stylesheet); -+ -+ uri = cr_string_dup (a_uri) ; -+ -+ if (a_media_list) -+ media_list = cr_utils_dup_glist_of_cr_string (a_media_list) ; -+ -+ stmt = cr_statement_new_at_import_rule -+ (ctxt->stylesheet, uri, media_list, NULL); -+ -+ if (!stmt) -+ goto error; -+ -+ if (ctxt->cur_stmt) { -+ stmt2 = cr_statement_append (ctxt->cur_stmt, stmt); -+ if (!stmt2) -+ goto error; -+ ctxt->cur_stmt = stmt2; -+ stmt2 = NULL; -+ stmt = NULL; -+ } else { -+ stmt2 = cr_statement_append (ctxt->stylesheet->statements, -+ stmt); -+ if (!stmt2) -+ goto error; -+ ctxt->stylesheet->statements = stmt2; -+ stmt2 = NULL; -+ stmt = NULL; -+ } -+ -+ return; -+ -+ error: -+ if (uri) { -+ cr_string_destroy (uri); -+ } -+ -+ if (stmt) { -+ cr_statement_destroy (stmt); -+ stmt = NULL; -+ } -+ a_uri_default_ns = NULL; /*keep compiler happy */ -+} -+ -+static void -+start_selector (CRDocHandler * a_this, CRSelector * a_selector_list) -+{ -+ enum CRStatus status = CR_OK ; -+ ParsingContext *ctxt = NULL; -+ ParsingContext **ctxtptr = NULL; -+ -+ g_return_if_fail (a_this); -+ ctxtptr = &ctxt; -+ status = cr_doc_handler_get_ctxt (a_this, (gpointer *) ctxtptr); -+ g_return_if_fail (status == CR_OK && ctxt); -+ if (ctxt->cur_stmt) { -+ /*hmm, this should be NULL so free it */ -+ cr_statement_destroy (ctxt->cur_stmt); -+ ctxt->cur_stmt = NULL; -+ } -+ -+ ctxt->cur_stmt = cr_statement_new_ruleset -+ (ctxt->stylesheet, a_selector_list, NULL, NULL); -+} -+ -+static void -+end_selector (CRDocHandler * a_this, CRSelector * a_selector_list) -+{ -+ enum CRStatus status = CR_OK; -+ ParsingContext *ctxt = NULL; -+ ParsingContext **ctxtptr = NULL; -+ -+ (void) a_selector_list; -+ -+ g_return_if_fail (a_this); -+ -+ ctxtptr = &ctxt; -+ status = cr_doc_handler_get_ctxt (a_this, (gpointer *) ctxtptr); -+ -+ g_return_if_fail (status == CR_OK && ctxt); -+ -+ g_return_if_fail (ctxt->cur_stmt && ctxt->stylesheet); -+ -+ if (ctxt->cur_stmt) { -+ CRStatement *stmts = NULL; -+ -+ if (ctxt->cur_media_stmt) { -+ CRAtMediaRule *media_rule = NULL; -+ -+ media_rule = ctxt->cur_media_stmt->kind.media_rule; -+ -+ stmts = cr_statement_append -+ (media_rule->rulesets, ctxt->cur_stmt); -+ -+ if (!stmts) { -+ cr_utils_trace_info -+ ("Could not append a new statement"); -+ cr_statement_destroy (media_rule->rulesets); -+ ctxt->cur_media_stmt-> -+ kind.media_rule->rulesets = NULL; -+ return; -+ } -+ media_rule->rulesets = stmts; -+ ctxt->cur_stmt = NULL; -+ } else { -+ stmts = cr_statement_append -+ (ctxt->stylesheet->statements, -+ ctxt->cur_stmt); -+ if (!stmts) { -+ cr_utils_trace_info -+ ("Could not append a new statement"); -+ cr_statement_destroy (ctxt->cur_stmt); -+ ctxt->cur_stmt = NULL; -+ return; -+ } -+ ctxt->stylesheet->statements = stmts; -+ ctxt->cur_stmt = NULL; -+ } -+ -+ } -+ -+ a_selector_list = NULL; /*keep compiler happy */ -+} -+ -+static void -+property (CRDocHandler * a_this, -+ CRString * a_name, -+ CRTerm * a_expression, -+ gboolean a_important) -+{ -+ enum CRStatus status = CR_OK; -+ ParsingContext *ctxt = NULL; -+ ParsingContext **ctxtptr = NULL; -+ CRDeclaration *decl = NULL, -+ *decl2 = NULL; -+ CRString *str = NULL; -+ -+ g_return_if_fail (a_this); -+ ctxtptr = &ctxt; -+ status = cr_doc_handler_get_ctxt (a_this, (gpointer *) ctxtptr); -+ g_return_if_fail (status == CR_OK && ctxt); -+ -+ /* -+ *make sure a current ruleset statement has been allocated -+ *already. -+ */ -+ g_return_if_fail -+ (ctxt->cur_stmt -+ && -+ (ctxt->cur_stmt->type == RULESET_STMT -+ || ctxt->cur_stmt->type == AT_FONT_FACE_RULE_STMT -+ || ctxt->cur_stmt->type == AT_PAGE_RULE_STMT)); -+ -+ if (a_name) { -+ str = cr_string_dup (a_name); -+ g_return_if_fail (str); -+ } -+ -+ /*instanciates a new declaration */ -+ decl = cr_declaration_new (ctxt->cur_stmt, str, a_expression); -+ g_return_if_fail (decl); -+ str = NULL; -+ decl->important = a_important; -+ /* -+ *add the new declaration to the current statement -+ *being build. -+ */ -+ switch (ctxt->cur_stmt->type) { -+ case RULESET_STMT: -+ decl2 = cr_declaration_append -+ (ctxt->cur_stmt->kind.ruleset->decl_list, decl); -+ if (!decl2) { -+ cr_declaration_destroy (decl); -+ cr_utils_trace_info -+ ("Could not append decl to ruleset"); -+ goto error; -+ } -+ ctxt->cur_stmt->kind.ruleset->decl_list = decl2; -+ decl = NULL; -+ decl2 = NULL; -+ break; -+ -+ case AT_FONT_FACE_RULE_STMT: -+ decl2 = cr_declaration_append -+ (ctxt->cur_stmt->kind.font_face_rule->decl_list, -+ decl); -+ if (!decl2) { -+ cr_declaration_destroy (decl); -+ cr_utils_trace_info -+ ("Could not append decl to ruleset"); -+ goto error; -+ } -+ ctxt->cur_stmt->kind.font_face_rule->decl_list = decl2; -+ decl = NULL; -+ decl2 = NULL; -+ break; -+ case AT_PAGE_RULE_STMT: -+ decl2 = cr_declaration_append -+ (ctxt->cur_stmt->kind.page_rule->decl_list, decl); -+ if (!decl2) { -+ cr_declaration_destroy (decl); -+ cr_utils_trace_info -+ ("Could not append decl to ruleset"); -+ goto error; -+ } -+ ctxt->cur_stmt->kind.page_rule->decl_list = decl2; -+ decl = NULL; -+ decl2 = NULL; -+ break; -+ -+ default: -+ goto error; -+ break; -+ } -+ -+ return; -+ -+ error: -+ if (str) { -+ g_free (str); -+ str = NULL; -+ } -+ -+ if (decl) { -+ cr_declaration_destroy (decl); -+ decl = NULL; -+ } -+} -+ -+static void -+error (CRDocHandler * a_this) -+{ -+ enum CRStatus status = CR_OK; -+ ParsingContext *ctxt = NULL; -+ ParsingContext **ctxtptr = NULL; -+ -+ g_return_if_fail (a_this); -+ ctxtptr = &ctxt; -+ status = cr_doc_handler_get_ctxt (a_this, (gpointer *) ctxtptr); -+ g_return_if_fail (status == CR_OK && ctxt); -+ -+ if (ctxt->cur_stmt) { -+ cr_statement_destroy (ctxt->cur_stmt); -+ ctxt->cur_stmt = NULL; -+ } -+} -+ -+static void -+unrecoverable_error (CRDocHandler * a_this) -+{ -+ enum CRStatus status = CR_OK; -+ ParsingContext *ctxt = NULL; -+ ParsingContext **ctxtptr = NULL; -+ -+ ctxtptr = &ctxt; -+ status = cr_doc_handler_get_ctxt (a_this, (gpointer *) ctxtptr); -+ g_return_if_fail (status == CR_OK); -+ -+ if (ctxt) { -+ if (ctxt->stylesheet) { -+ status = cr_doc_handler_set_result -+ (a_this, ctxt->stylesheet); -+ g_return_if_fail (status == CR_OK); -+ } -+ g_free (ctxt); -+ cr_doc_handler_set_ctxt (a_this, NULL); -+ } -+} -+ -+/******************************************** -+ *Public methods -+ ********************************************/ -+ -+/** -+ * cr_om_parser_new: -+ *@a_input: the input stream. -+ * -+ *Constructor of the CROMParser. -+ *Returns the newly built instance of #CROMParser. -+ */ -+CROMParser * -+cr_om_parser_new (CRInput * a_input) -+{ -+ CROMParser *result = NULL; -+ enum CRStatus status = CR_OK; -+ -+ result = g_try_malloc (sizeof (CROMParser)); -+ -+ if (!result) { -+ cr_utils_trace_info ("Out of memory"); -+ return NULL; -+ } -+ -+ memset (result, 0, sizeof (CROMParser)); -+ PRIVATE (result) = g_try_malloc (sizeof (CROMParserPriv)); -+ -+ if (!PRIVATE (result)) { -+ cr_utils_trace_info ("Out of memory"); -+ goto error; -+ } -+ -+ memset (PRIVATE (result), 0, sizeof (CROMParserPriv)); -+ -+ PRIVATE (result)->parser = cr_parser_new_from_input (a_input); -+ -+ if (!PRIVATE (result)->parser) { -+ cr_utils_trace_info ("parsing instantiation failed"); -+ goto error; -+ } -+ -+ status = cr_om_parser_init_default_sac_handler (result); -+ -+ if (status != CR_OK) { -+ goto error; -+ } -+ -+ return result; -+ -+ error: -+ -+ if (result) { -+ cr_om_parser_destroy (result); -+ } -+ -+ return NULL; -+} -+ -+/** -+ * cr_om_parser_parse_buf: -+ *@a_this: the current instance of #CROMParser. -+ *@a_buf: the in memory buffer to parse. -+ *@a_len: the length of the in memory buffer in number of bytes. -+ *@a_enc: the encoding of the in memory buffer. -+ *@a_result: out parameter the resulting style sheet -+ * -+ *Parses the content of an in memory buffer. -+ * -+ *Returns CR_OK upon successfull completion, an error code otherwise. -+ */ -+enum CRStatus -+cr_om_parser_parse_buf (CROMParser * a_this, -+ const guchar * a_buf, -+ gulong a_len, -+ enum CREncoding a_enc, CRStyleSheet ** a_result) -+{ -+ -+ enum CRStatus status = CR_OK; -+ -+ g_return_val_if_fail (a_this && a_result, CR_BAD_PARAM_ERROR); -+ -+ if (!PRIVATE (a_this)->parser) { -+ PRIVATE (a_this)->parser = cr_parser_new (NULL); -+ } -+ -+ status = cr_parser_parse_buf (PRIVATE (a_this)->parser, -+ a_buf, a_len, a_enc); -+ -+ if (status == CR_OK) { -+ CRStyleSheet *result = NULL; -+ CRStyleSheet **resultptr = NULL; -+ CRDocHandler *sac_handler = NULL; -+ -+ cr_parser_get_sac_handler (PRIVATE (a_this)->parser, -+ &sac_handler); -+ g_return_val_if_fail (sac_handler, CR_ERROR); -+ resultptr = &result; -+ status = cr_doc_handler_get_result (sac_handler, -+ (gpointer *) resultptr); -+ g_return_val_if_fail (status == CR_OK, status); -+ -+ if (result) -+ *a_result = result; -+ } -+ -+ return status; -+} -+ -+/** -+ * cr_om_parser_simply_parse_buf: -+ *@a_buf: the css2 in memory buffer. -+ *@a_len: the length of the in memory buffer. -+ *@a_enc: the encoding of the in memory buffer. -+ *@a_result: out parameter. The resulting css2 style sheet. -+ * -+ *The simpler way to parse an in memory css2 buffer. -+ * -+ *Returns CR_OK upon successfull completion, an error code otherwise. -+ */ -+enum CRStatus -+cr_om_parser_simply_parse_buf (const guchar * a_buf, -+ gulong a_len, -+ enum CREncoding a_enc, -+ CRStyleSheet ** a_result) -+{ -+ CROMParser *parser = NULL; -+ enum CRStatus status = CR_OK; -+ -+ parser = cr_om_parser_new (NULL); -+ if (!parser) { -+ cr_utils_trace_info ("Could not create om parser"); -+ cr_utils_trace_info ("System possibly out of memory"); -+ return CR_ERROR; -+ } -+ -+ status = cr_om_parser_parse_buf (parser, a_buf, a_len, -+ a_enc, a_result); -+ -+ if (parser) { -+ cr_om_parser_destroy (parser); -+ parser = NULL; -+ } -+ -+ return status; -+} -+ -+/** -+ * cr_om_parser_parse_file: -+ *@a_this: the current instance of the cssom parser. -+ *@a_file_uri: the uri of the file. -+ *(only local file paths are suppported so far) -+ *@a_enc: the encoding of the file. -+ *@a_result: out parameter. A pointer -+ *the build css object model. -+ * -+ *Parses a css2 stylesheet contained -+ *in a file. -+ * -+ * Returns CR_OK upon succesful completion, an error code otherwise. -+ */ -+enum CRStatus -+cr_om_parser_parse_file (CROMParser * a_this, -+ const guchar * a_file_uri, -+ enum CREncoding a_enc, CRStyleSheet ** a_result) -+{ -+ enum CRStatus status = CR_OK; -+ -+ g_return_val_if_fail (a_this && a_file_uri && a_result, -+ CR_BAD_PARAM_ERROR); -+ -+ if (!PRIVATE (a_this)->parser) { -+ PRIVATE (a_this)->parser = cr_parser_new_from_file -+ (a_file_uri, a_enc); -+ } -+ -+ status = cr_parser_parse_file (PRIVATE (a_this)->parser, -+ a_file_uri, a_enc); -+ -+ if (status == CR_OK) { -+ CRStyleSheet *result = NULL; -+ CRStyleSheet **resultptr = NULL; -+ CRDocHandler *sac_handler = NULL; -+ -+ cr_parser_get_sac_handler (PRIVATE (a_this)->parser, -+ &sac_handler); -+ g_return_val_if_fail (sac_handler, CR_ERROR); -+ resultptr = &result; -+ status = cr_doc_handler_get_result -+ (sac_handler, (gpointer *) resultptr); -+ g_return_val_if_fail (status == CR_OK, status); -+ if (result) -+ *a_result = result; -+ } -+ -+ return status; -+} -+ -+/** -+ * cr_om_parser_simply_parse_file: -+ *@a_file_path: the css2 local file path. -+ *@a_enc: the file encoding. -+ *@a_result: out parameter. The returned css stylesheet. -+ *Must be freed by the caller using cr_stylesheet_destroy. -+ * -+ *The simpler method to parse a css2 file. -+ * -+ *Returns CR_OK upon successfull completion, an error code otherwise. -+ *Note that this method uses cr_om_parser_parse_file() so both methods -+ *have the same return values. -+ */ -+enum CRStatus -+cr_om_parser_simply_parse_file (const guchar * a_file_path, -+ enum CREncoding a_enc, -+ CRStyleSheet ** a_result) -+{ -+ CROMParser *parser = NULL; -+ enum CRStatus status = CR_OK; -+ -+ parser = cr_om_parser_new (NULL); -+ if (!parser) { -+ cr_utils_trace_info ("Could not allocate om parser"); -+ cr_utils_trace_info ("System may be out of memory"); -+ return CR_ERROR; -+ } -+ -+ status = cr_om_parser_parse_file (parser, a_file_path, -+ a_enc, a_result); -+ if (parser) { -+ cr_om_parser_destroy (parser); -+ parser = NULL; -+ } -+ -+ return status; -+} -+ -+/** -+ * cr_om_parser_parse_paths_to_cascade: -+ *@a_this: the current instance of #CROMParser -+ *@a_author_path: the path to the author stylesheet -+ *@a_user_path: the path to the user stylesheet -+ *@a_ua_path: the path to the User Agent stylesheet -+ *@a_encoding: the encoding of the sheets. -+ *@a_result: out parameter. The resulting cascade if the parsing -+ *was okay -+ * -+ *Parses three sheets located by their paths and build a cascade -+ * -+ *Returns CR_OK upon successful completion, an error code otherwise -+ */ -+enum CRStatus -+cr_om_parser_parse_paths_to_cascade (CROMParser * a_this, -+ const guchar * a_author_path, -+ const guchar * a_user_path, -+ const guchar * a_ua_path, -+ enum CREncoding a_encoding, -+ CRCascade ** a_result) -+{ -+ enum CRStatus status = CR_OK; -+ -+ /*0->author sheet, 1->user sheet, 2->UA sheet */ -+ CRStyleSheet *sheets[3]; -+ guchar *paths[3]; -+ CRCascade *result = NULL; -+ gint i = 0; -+ -+ g_return_val_if_fail (a_this, CR_BAD_PARAM_ERROR); -+ -+ memset (sheets, 0, sizeof (CRStyleSheet*) * 3); -+ paths[0] = (guchar *) a_author_path; -+ paths[1] = (guchar *) a_user_path; -+ paths[2] = (guchar *) a_ua_path; -+ -+ for (i = 0; i < 3; i++) { -+ status = cr_om_parser_parse_file (a_this, paths[i], -+ a_encoding, &sheets[i]); -+ if (status != CR_OK) { -+ if (sheets[i]) { -+ cr_stylesheet_unref (sheets[i]); -+ sheets[i] = NULL; -+ } -+ continue; -+ } -+ } -+ result = cr_cascade_new (sheets[0], sheets[1], sheets[2]); -+ if (!result) { -+ for (i = 0; i < 3; i++) { -+ cr_stylesheet_unref (sheets[i]); -+ sheets[i] = 0; -+ } -+ return CR_ERROR; -+ } -+ *a_result = result; -+ return CR_OK; -+} -+ -+/** -+ * cr_om_parser_simply_parse_paths_to_cascade: -+ *@a_author_path: the path to the author stylesheet -+ *@a_user_path: the path to the user stylesheet -+ *@a_ua_path: the path to the User Agent stylesheet -+ *@a_encoding: the encoding of the sheets. -+ *@a_result: out parameter. The resulting cascade if the parsing -+ *was okay -+ * -+ *Parses three sheets located by their paths and build a cascade -+ * -+ *Returns CR_OK upon successful completion, an error code otherwise -+ */ -+enum CRStatus -+cr_om_parser_simply_parse_paths_to_cascade (const guchar * a_author_path, -+ const guchar * a_user_path, -+ const guchar * a_ua_path, -+ enum CREncoding a_encoding, -+ CRCascade ** a_result) -+{ -+ enum CRStatus status = CR_OK; -+ CROMParser *parser = NULL; -+ -+ parser = cr_om_parser_new (NULL); -+ if (!parser) { -+ cr_utils_trace_info ("could not allocated om parser"); -+ cr_utils_trace_info ("System may be out of memory"); -+ return CR_ERROR; -+ } -+ status = cr_om_parser_parse_paths_to_cascade (parser, -+ a_author_path, -+ a_user_path, -+ a_ua_path, -+ a_encoding, a_result); -+ if (parser) { -+ cr_om_parser_destroy (parser); -+ parser = NULL; -+ } -+ return status; -+} -+ -+/** -+ * cr_om_parser_destroy: -+ *@a_this: the current instance of #CROMParser. -+ * -+ *Destructor of the #CROMParser. -+ */ -+void -+cr_om_parser_destroy (CROMParser * a_this) -+{ -+ g_return_if_fail (a_this && PRIVATE (a_this)); -+ -+ if (PRIVATE (a_this)->parser) { -+ cr_parser_destroy (PRIVATE (a_this)->parser); -+ PRIVATE (a_this)->parser = NULL; -+ } -+ -+ if (PRIVATE (a_this)) { -+ g_free (PRIVATE (a_this)); -+ PRIVATE (a_this) = NULL; -+ } -+ -+ if (a_this) { -+ g_free (a_this); -+ a_this = NULL; -+ } -+} -diff --git a/src/st/croco/cr-om-parser.h b/src/st/croco/cr-om-parser.h -new file mode 100644 -index 000000000..13d35b1cd ---- /dev/null -+++ b/src/st/croco/cr-om-parser.h -@@ -0,0 +1,98 @@ -+/* -*- Mode: C; indent-tabs-mode:nil; c-basic-offset: 8-*- */ -+ -+/* -+ * This file is part of The Croco Library -+ * -+ * Copyright (C) 2002-2003 Dodji Seketeli -+ * -+ * 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 -+ */ -+ -+/* -+ *$Id$ -+ */ -+ -+#ifndef __CR_OM_PARSER_H__ -+#define __CR_OM_PARSER_H__ -+ -+#include "cr-parser.h" -+#include "cr-cascade.h" -+ -+ -+/** -+ *@file -+ *The definition of the CSS Object Model Parser. -+ *This parser uses (and sits) the SAC api of libcroco defined -+ *in cr-parser.h and cr-doc-handler.h -+ */ -+ -+G_BEGIN_DECLS -+ -+typedef struct _CROMParser CROMParser ; -+typedef struct _CROMParserPriv CROMParserPriv ; -+ -+/** -+ *The Object model parser. -+ *Can parse a css file and build a css object model. -+ *This parser uses an instance of #CRParser and defines -+ *a set of SAC callbacks to build the Object Model. -+ */ -+struct _CROMParser -+{ -+ CROMParserPriv *priv ; -+} ; -+ -+CROMParser * cr_om_parser_new (CRInput *a_input) ; -+ -+ -+enum CRStatus cr_om_parser_simply_parse_file (const guchar *a_file_path, -+ enum CREncoding a_enc, -+ CRStyleSheet **a_result) ; -+ -+enum CRStatus cr_om_parser_parse_file (CROMParser *a_this, -+ const guchar *a_file_uri, -+ enum CREncoding a_enc, -+ CRStyleSheet **a_result) ; -+ -+enum CRStatus cr_om_parser_simply_parse_buf (const guchar *a_buf, -+ gulong a_len, -+ enum CREncoding a_enc, -+ CRStyleSheet **a_result) ; -+ -+enum CRStatus cr_om_parser_parse_buf (CROMParser *a_this, -+ const guchar *a_buf, -+ gulong a_len, -+ enum CREncoding a_enc, -+ CRStyleSheet **a_result) ; -+ -+enum CRStatus cr_om_parser_parse_paths_to_cascade (CROMParser *a_this, -+ const guchar *a_author_path, -+ const guchar *a_user_path, -+ const guchar *a_ua_path, -+ enum CREncoding a_encoding, -+ CRCascade ** a_result) ; -+ -+enum CRStatus cr_om_parser_simply_parse_paths_to_cascade (const guchar *a_author_path, -+ const guchar *a_user_path, -+ const guchar *a_ua_path, -+ enum CREncoding a_encoding, -+ CRCascade ** a_result) ; -+ -+void cr_om_parser_destroy (CROMParser *a_this) ; -+ -+G_END_DECLS -+ -+#endif /*__CR_OM_PARSER_H__*/ -diff --git a/src/st/croco/cr-parser.c b/src/st/croco/cr-parser.c -new file mode 100644 -index 000000000..07f4ed9e8 ---- /dev/null -+++ b/src/st/croco/cr-parser.c -@@ -0,0 +1,4525 @@ -+/* -*- Mode: C; indent-tabs-mode:nil; c-basic-offset: 8-*- */ -+ -+/* -+ * This file is part of The Croco Library -+ * -+ * -+ * 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 -+ * See COPYRIGHTS file for copyrights information. -+ */ -+ -+/** -+ *@CRParser: -+ * -+ *The definition of the #CRParser class. -+ */ -+ -+#include "string.h" -+#include "cr-parser.h" -+#include "cr-num.h" -+#include "cr-term.h" -+#include "cr-simple-sel.h" -+#include "cr-attr-sel.h" -+ -+/* -+ *Random notes: -+ *CSS core syntax vs CSS level 2 syntax -+ *===================================== -+ * -+ *One must keep in mind -+ *that css UA must comply with two syntaxes. -+ * -+ *1/the specific syntax that defines the css language -+ *for a given level of specificatin (e.g css2 syntax -+ *defined in appendix D.1 of the css2 spec) -+ * -+ *2/the core (general) syntax that is there to allow -+ *UAs to parse style sheets written in levels of CSS that -+ *didn't exist at the time the UAs were created. -+ * -+ *the name of parsing functions (or methods) contained in this file -+ *follows the following scheme: cr_parser_parse_ (...) ; -+ *where is the name -+ *of a production of the css2 language. -+ *When a given production is -+ *defined by the css2 level grammar *and* by the -+ *css core syntax, there will be two functions to parse that production: -+ *one will parse the production defined by the css2 level grammar and the -+ *other will parse the production defined by the css core grammar. -+ *The css2 level grammar related parsing function will be called: -+ *cr_parser_parse_ (...) ; -+ *Then css core grammar related parsing function will be called: -+ *cr_parser_parse__core (...) ; -+ * -+ *If a production is defined only by the css core grammar, then -+ *it will be named: -+ *cr_parser_parse__core (...) ; -+ */ -+ -+typedef struct _CRParserError CRParserError; -+ -+/** -+ *An abstraction of an error reported by by the -+ *parsing routines. -+ */ -+struct _CRParserError { -+ guchar *msg; -+ enum CRStatus status; -+ glong line; -+ glong column; -+ glong byte_num; -+}; -+ -+enum CRParserState { -+ READY_STATE = 0, -+ TRY_PARSE_CHARSET_STATE, -+ CHARSET_PARSED_STATE, -+ TRY_PARSE_IMPORT_STATE, -+ IMPORT_PARSED_STATE, -+ TRY_PARSE_RULESET_STATE, -+ RULESET_PARSED_STATE, -+ TRY_PARSE_MEDIA_STATE, -+ MEDIA_PARSED_STATE, -+ TRY_PARSE_PAGE_STATE, -+ PAGE_PARSED_STATE, -+ TRY_PARSE_FONT_FACE_STATE, -+ FONT_FACE_PARSED_STATE -+} ; -+ -+/** -+ *The private attributes of -+ *#CRParser. -+ */ -+struct _CRParserPriv { -+ /** -+ *The tokenizer -+ */ -+ CRTknzr *tknzr; -+ -+ /** -+ *The sac handlers to call -+ *to notify the parsing of -+ *the css2 constructions. -+ */ -+ CRDocHandler *sac_handler; -+ -+ /** -+ *A stack of errors reported -+ *by the parsing routines. -+ *Contains instance of #CRParserError. -+ *This pointer is the top of the stack. -+ */ -+ GList *err_stack; -+ -+ enum CRParserState state; -+ gboolean resolve_import; -+ gboolean is_case_sensitive; -+ gboolean use_core_grammar; -+}; -+ -+#define PRIVATE(obj) ((obj)->priv) -+ -+#define CHARS_TAB_SIZE 12 -+ -+/** -+ * IS_NUM: -+ *@a_char: the char to test. -+ *return TRUE if the character is a number ([0-9]), FALSE otherwise -+ */ -+#define IS_NUM(a_char) (((a_char) >= '0' && (a_char) <= '9')?TRUE:FALSE) -+ -+/** -+ *Checks if 'status' equals CR_OK. If not, goto the 'error' label. -+ * -+ *@param status the status (of type enum CRStatus) to test. -+ *@param is_exception if set to FALSE, the final status returned -+ *by the current function will be CR_PARSING_ERROR. If set to TRUE, the -+ *current status will be the current value of the 'status' variable. -+ * -+ */ -+#define CHECK_PARSING_STATUS(status, is_exception) \ -+if ((status) != CR_OK) \ -+{ \ -+ if (is_exception == FALSE) \ -+ { \ -+ status = CR_PARSING_ERROR ; \ -+ } \ -+ goto error ; \ -+} -+ -+/** -+ * CHECK_PARSING_STATUS_ERR: -+ *@a_this: the current instance of #CRParser . -+ *@a_status: the status to check. Is of type enum #CRStatus. -+ *@a_is_exception: in case of error, if is TRUE, the status -+ *is set to CR_PARSING_ERROR before goto error. If is false, the -+ *real low level status is kept and will be returned by the -+ *upper level function that called this macro. Usally,this must -+ *be set to FALSE. -+ * -+ *same as CHECK_PARSING_STATUS() but this one pushes an error -+ *on the parser error stack when an error arises. -+ * -+ */ -+#define CHECK_PARSING_STATUS_ERR(a_this, a_status, a_is_exception,\ -+ a_err_msg, a_err_status) \ -+if ((a_status) != CR_OK) \ -+{ \ -+ if (a_is_exception == FALSE) a_status = CR_PARSING_ERROR ; \ -+ cr_parser_push_error (a_this, a_err_msg, a_err_status) ; \ -+ goto error ; \ -+} -+ -+/** -+ *Peeks the next char from the input stream of the current parser -+ *by invoking cr_tknzr_input_peek_char(). -+ *invokes CHECK_PARSING_STATUS on the status returned by -+ *cr_tknzr_peek_char(). -+ * -+ *@param a_this the current instance of #CRParser. -+ *@param a_to_char a pointer to the char where to store the -+ *char peeked. -+ */ -+#define PEEK_NEXT_CHAR(a_this, a_to_char) \ -+{\ -+status = cr_tknzr_peek_char (PRIVATE (a_this)->tknzr, a_to_char) ; \ -+CHECK_PARSING_STATUS (status, TRUE) \ -+} -+ -+/** -+ *Reads the next char from the input stream of the current parser. -+ *In case of error, jumps to the "error:" label located in the -+ *function where this macro is called. -+ *@param a_this the curent instance of #CRParser -+ *@param to_char a pointer to the guint32 char where to store -+ *the character read. -+ */ -+#define READ_NEXT_CHAR(a_this, a_to_char) \ -+status = cr_tknzr_read_char (PRIVATE (a_this)->tknzr, a_to_char) ; \ -+CHECK_PARSING_STATUS (status, TRUE) -+ -+/** -+ *Gets information about the current position in -+ *the input of the parser. -+ *In case of failure, this macro returns from the -+ *calling function and -+ *returns a status code of type enum #CRStatus. -+ *@param a_this the current instance of #CRParser. -+ *@param a_pos out parameter. A pointer to the position -+ *inside the current parser input. Must -+ */ -+#define RECORD_INITIAL_POS(a_this, a_pos) \ -+status = cr_tknzr_get_cur_pos (PRIVATE \ -+(a_this)->tknzr, a_pos) ; \ -+g_return_val_if_fail (status == CR_OK, status) -+ -+/** -+ *Gets the address of the current byte inside the -+ *parser input. -+ *@param parser the current instance of #CRParser. -+ *@param addr out parameter a pointer (guchar*) -+ *to where the address must be put. -+ */ -+#define RECORD_CUR_BYTE_ADDR(a_this, a_addr) \ -+status = cr_tknzr_get_cur_byte_addr \ -+ (PRIVATE (a_this)->tknzr, a_addr) ; \ -+CHECK_PARSING_STATUS (status, TRUE) -+ -+/** -+ *Peeks a byte from the topmost parser input at -+ *a given offset from the current position. -+ *If it fails, goto the "error:" label. -+ * -+ *@param a_parser the current instance of #CRParser. -+ *@param a_offset the offset of the byte to peek, the -+ *current byte having the offset '0'. -+ *@param a_byte_ptr out parameter a pointer (guchar*) to -+ *where the peeked char is to be stored. -+ */ -+#define PEEK_BYTE(a_parser, a_offset, a_byte_ptr) \ -+status = cr_tknzr_peek_byte (PRIVATE (a_this)->tknzr, \ -+ a_offset, \ -+ a_byte_ptr) ; \ -+CHECK_PARSING_STATUS (status, TRUE) ; -+ -+#define BYTE(a_parser, a_offset, a_eof) \ -+cr_tknzr_peek_byte2 (PRIVATE (a_this)->tknzr, a_offset, a_eof) -+ -+/** -+ *Reads a byte from the topmost parser input -+ *steam. -+ *If it fails, goto the "error" label. -+ *@param a_this the current instance of #CRParser. -+ *@param a_byte_ptr the guchar * where to put the read char. -+ */ -+#define READ_NEXT_BYTE(a_this, a_byte_ptr) \ -+status = cr_tknzr_read_byte (PRIVATE (a_this)->tknzr, a_byte_ptr) ; \ -+CHECK_PARSING_STATUS (status, TRUE) ; -+ -+/** -+ *Skips a given number of byte in the topmost -+ *parser input. Don't update line and column number. -+ *In case of error, jumps to the "error:" label -+ *of the surrounding function. -+ *@param a_parser the current instance of #CRParser. -+ *@param a_nb_bytes the number of bytes to skip. -+ */ -+#define SKIP_BYTES(a_this, a_nb_bytes) \ -+status = cr_tknzr_seek_index (PRIVATE (a_this)->tknzr, \ -+ CR_SEEK_CUR, a_nb_bytes) ; \ -+CHECK_PARSING_STATUS (status, TRUE) ; -+ -+/** -+ *Skip utf8 encoded characters. -+ *Updates line and column numbers. -+ *@param a_parser the current instance of #CRParser. -+ *@param a_nb_chars the number of chars to skip. Must be of -+ *type glong. -+ */ -+#define SKIP_CHARS(a_parser, a_nb_chars) \ -+{ \ -+glong nb_chars = a_nb_chars ; \ -+status = cr_tknzr_consume_chars \ -+ (PRIVATE (a_parser)->tknzr,0, &nb_chars) ; \ -+CHECK_PARSING_STATUS (status, TRUE) ; \ -+} -+ -+/** -+ *Tests the condition and if it is false, sets -+ *status to "CR_PARSING_ERROR" and goto the 'error' -+ *label. -+ *@param condition the condition to test. -+ */ -+#define ENSURE_PARSING_COND(condition) \ -+if (! (condition)) {status = CR_PARSING_ERROR; goto error ;} -+ -+#define ENSURE_PARSING_COND_ERR(a_this, a_condition, \ -+ a_err_msg, a_err_status) \ -+if (! (a_condition)) \ -+{ \ -+ status = CR_PARSING_ERROR; \ -+ cr_parser_push_error (a_this, a_err_msg, a_err_status) ; \ -+ goto error ; \ -+} -+ -+#define GET_NEXT_TOKEN(a_this, a_token_ptr) \ -+status = cr_tknzr_get_next_token (PRIVATE (a_this)->tknzr, \ -+ a_token_ptr) ; \ -+ENSURE_PARSING_COND (status == CR_OK) ; -+ -+#ifdef WITH_UNICODE_ESCAPE_AND_RANGE -+static enum CRStatus cr_parser_parse_unicode_escape (CRParser * a_this, -+ guint32 * a_unicode); -+static enum CRStatus cr_parser_parse_escape (CRParser * a_this, -+ guint32 * a_esc_code); -+ -+static enum CRStatus cr_parser_parse_unicode_range (CRParser * a_this, -+ CRString ** a_inf, -+ CRString ** a_sup); -+#endif -+ -+static enum CRStatus cr_parser_parse_stylesheet_core (CRParser * a_this); -+ -+static enum CRStatus cr_parser_parse_atrule_core (CRParser * a_this); -+ -+static enum CRStatus cr_parser_parse_ruleset_core (CRParser * a_this); -+ -+static enum CRStatus cr_parser_parse_selector_core (CRParser * a_this); -+ -+static enum CRStatus cr_parser_parse_declaration_core (CRParser * a_this); -+ -+static enum CRStatus cr_parser_parse_any_core (CRParser * a_this); -+ -+static enum CRStatus cr_parser_parse_block_core (CRParser * a_this); -+ -+static enum CRStatus cr_parser_parse_value_core (CRParser * a_this); -+ -+static enum CRStatus cr_parser_parse_string (CRParser * a_this, -+ CRString ** a_str); -+ -+static enum CRStatus cr_parser_parse_ident (CRParser * a_this, -+ CRString ** a_str); -+ -+static enum CRStatus cr_parser_parse_uri (CRParser * a_this, -+ CRString ** a_str); -+ -+static enum CRStatus cr_parser_parse_function (CRParser * a_this, -+ CRString ** a_func_name, -+ CRTerm ** a_expr); -+static enum CRStatus cr_parser_parse_property (CRParser * a_this, -+ CRString ** a_property); -+ -+static enum CRStatus cr_parser_parse_attribute_selector (CRParser * a_this, -+ CRAttrSel ** a_sel); -+ -+static enum CRStatus cr_parser_parse_simple_selector (CRParser * a_this, -+ CRSimpleSel ** a_sel); -+ -+static enum CRStatus cr_parser_parse_simple_sels (CRParser * a_this, -+ CRSimpleSel ** a_sel); -+ -+static CRParserError *cr_parser_error_new (const guchar * a_msg, -+ enum CRStatus); -+ -+static void cr_parser_error_set_msg (CRParserError * a_this, -+ const guchar * a_msg); -+ -+static void cr_parser_error_dump (CRParserError * a_this); -+ -+static void cr_parser_error_set_status (CRParserError * a_this, -+ enum CRStatus a_status); -+ -+static void cr_parser_error_set_pos (CRParserError * a_this, -+ glong a_line, -+ glong a_column, glong a_byte_num); -+static void -+ cr_parser_error_destroy (CRParserError * a_this); -+ -+static enum CRStatus cr_parser_push_error (CRParser * a_this, -+ const guchar * a_msg, -+ enum CRStatus a_status); -+ -+static enum CRStatus cr_parser_dump_err_stack (CRParser * a_this, -+ gboolean a_clear_errs); -+static enum CRStatus -+ cr_parser_clear_errors (CRParser * a_this); -+ -+/***************************** -+ *error managemet methods -+ *****************************/ -+ -+/** -+ *Constructor of #CRParserError class. -+ *@param a_msg the brute error message. -+ *@param a_status the error status. -+ *@return the newly built instance of #CRParserError. -+ */ -+static CRParserError * -+cr_parser_error_new (const guchar * a_msg, enum CRStatus a_status) -+{ -+ CRParserError *result = NULL; -+ -+ result = g_try_malloc (sizeof (CRParserError)); -+ -+ if (result == NULL) { -+ cr_utils_trace_info ("Out of memory"); -+ return NULL; -+ } -+ -+ memset (result, 0, sizeof (CRParserError)); -+ -+ cr_parser_error_set_msg (result, a_msg); -+ cr_parser_error_set_status (result, a_status); -+ -+ return result; -+} -+ -+/** -+ *Sets the message associated to this instance of #CRError. -+ *@param a_this the current instance of #CRParserError. -+ *@param a_msg the new message. -+ */ -+static void -+cr_parser_error_set_msg (CRParserError * a_this, const guchar * a_msg) -+{ -+ g_return_if_fail (a_this); -+ -+ if (a_this->msg) { -+ g_free (a_this->msg); -+ } -+ -+ a_this->msg = (guchar *) g_strdup ((const gchar *) a_msg); -+} -+ -+/** -+ *Sets the error status. -+ *@param a_this the current instance of #CRParserError. -+ *@param a_status the new error status. -+ * -+ */ -+static void -+cr_parser_error_set_status (CRParserError * a_this, enum CRStatus a_status) -+{ -+ g_return_if_fail (a_this); -+ -+ a_this->status = a_status; -+} -+ -+/** -+ *Sets the position of the parser error. -+ *@param a_this the current instance of #CRParserError. -+ *@param a_line the line number. -+ *@param a_column the column number. -+ *@param a_byte_num the byte number. -+ */ -+static void -+cr_parser_error_set_pos (CRParserError * a_this, -+ glong a_line, glong a_column, glong a_byte_num) -+{ -+ g_return_if_fail (a_this); -+ -+ a_this->line = a_line; -+ a_this->column = a_column; -+ a_this->byte_num = a_byte_num; -+} -+ -+static void -+cr_parser_error_dump (CRParserError * a_this) -+{ -+ g_return_if_fail (a_this); -+ -+ g_printerr ("parsing error: %ld:%ld:", a_this->line, a_this->column); -+ -+ g_printerr ("%s\n", a_this->msg); -+} -+ -+/** -+ *The destructor of #CRParserError. -+ *@param a_this the current instance of #CRParserError. -+ */ -+static void -+cr_parser_error_destroy (CRParserError * a_this) -+{ -+ g_return_if_fail (a_this); -+ -+ if (a_this->msg) { -+ g_free (a_this->msg); -+ a_this->msg = NULL; -+ } -+ -+ g_free (a_this); -+} -+ -+/** -+ *Pushes an error on the parser error stack. -+ *@param a_this the current instance of #CRParser. -+ *@param a_msg the error message. -+ *@param a_status the error status. -+ *@return CR_OK upon successfull completion, an error code otherwise. -+ */ -+static enum CRStatus -+cr_parser_push_error (CRParser * a_this, -+ const guchar * a_msg, enum CRStatus a_status) -+{ -+ enum CRStatus status = CR_OK; -+ -+ CRParserError *error = NULL; -+ CRInputPos pos; -+ -+ g_return_val_if_fail (a_this && PRIVATE (a_this) -+ && a_msg, CR_BAD_PARAM_ERROR); -+ -+ error = cr_parser_error_new (a_msg, a_status); -+ -+ g_return_val_if_fail (error, CR_ERROR); -+ -+ RECORD_INITIAL_POS (a_this, &pos); -+ -+ cr_parser_error_set_pos -+ (error, pos.line, pos.col, pos.next_byte_index - 1); -+ -+ PRIVATE (a_this)->err_stack = -+ g_list_prepend (PRIVATE (a_this)->err_stack, error); -+ -+ if (PRIVATE (a_this)->err_stack == NULL) -+ goto error; -+ -+ return CR_OK; -+ -+ error: -+ -+ if (error) { -+ cr_parser_error_destroy (error); -+ error = NULL; -+ } -+ -+ return status; -+} -+ -+/** -+ *Dumps the error stack on stdout. -+ *@param a_this the current instance of #CRParser. -+ *@param a_clear_errs whether to clear the error stack -+ *after the dump or not. -+ *@return CR_OK upon successfull completion, an error code -+ *otherwise. -+ */ -+static enum CRStatus -+cr_parser_dump_err_stack (CRParser * a_this, gboolean a_clear_errs) -+{ -+ GList *cur = NULL; -+ -+ g_return_val_if_fail (a_this && PRIVATE (a_this), CR_BAD_PARAM_ERROR); -+ -+ if (PRIVATE (a_this)->err_stack == NULL) -+ return CR_OK; -+ -+ for (cur = PRIVATE (a_this)->err_stack; cur; cur = cur->next) { -+ cr_parser_error_dump ((CRParserError *) cur->data); -+ } -+ -+ if (a_clear_errs == TRUE) { -+ cr_parser_clear_errors (a_this); -+ } -+ -+ return CR_OK; -+} -+ -+/** -+ *Clears all the errors contained in the parser error stack. -+ *Frees all the errors, and the stack that contains'em. -+ *@param a_this the current instance of #CRParser. -+ */ -+static enum CRStatus -+cr_parser_clear_errors (CRParser * a_this) -+{ -+ GList *cur = NULL; -+ -+ g_return_val_if_fail (a_this && PRIVATE (a_this), CR_BAD_PARAM_ERROR); -+ -+ for (cur = PRIVATE (a_this)->err_stack; cur; cur = cur->next) { -+ if (cur->data) { -+ cr_parser_error_destroy ((CRParserError *) -+ cur->data); -+ } -+ } -+ -+ if (PRIVATE (a_this)->err_stack) { -+ g_list_free (PRIVATE (a_this)->err_stack); -+ PRIVATE (a_this)->err_stack = NULL; -+ } -+ -+ return CR_OK; -+} -+ -+/** -+ * cr_parser_try_to_skip_spaces_and_comments: -+ *@a_this: the current instance of #CRParser. -+ * -+ *Same as cr_parser_try_to_skip_spaces() but this one skips -+ *spaces and comments. -+ * -+ *Returns CR_OK upon successfull completion, an error code otherwise. -+ */ -+enum CRStatus -+cr_parser_try_to_skip_spaces_and_comments (CRParser * a_this) -+{ -+ enum CRStatus status = CR_ERROR; -+ CRToken *token = NULL; -+ -+ g_return_val_if_fail (a_this && PRIVATE (a_this) -+ && PRIVATE (a_this)->tknzr, CR_BAD_PARAM_ERROR); -+ do { -+ if (token) { -+ cr_token_destroy (token); -+ token = NULL; -+ } -+ -+ status = cr_tknzr_get_next_token (PRIVATE (a_this)->tknzr, -+ &token); -+ if (status != CR_OK) -+ goto error; -+ } -+ while ((token != NULL) -+ && (token->type == COMMENT_TK || token->type == S_TK)); -+ -+ cr_tknzr_unget_token (PRIVATE (a_this)->tknzr, token); -+ -+ return status; -+ -+ error: -+ -+ if (token) { -+ cr_token_destroy (token); -+ token = NULL; -+ } -+ -+ return status; -+} -+ -+/*************************************** -+ *End of Parser input handling routines -+ ***************************************/ -+ -+ -+/************************************* -+ *Non trivial terminal productions -+ *parsing routines -+ *************************************/ -+ -+/** -+ *Parses a css stylesheet following the core css grammar. -+ *This is mainly done for test purposes. -+ *During the parsing, no callback is called. This is just -+ *to validate that the stylesheet is well formed according to the -+ *css core syntax. -+ *stylesheet : [ CDO | CDC | S | statement ]*; -+ *@param a_this the current instance of #CRParser. -+ *@return CR_OK upon successful completion, an error code otherwise. -+ */ -+static enum CRStatus -+cr_parser_parse_stylesheet_core (CRParser * a_this) -+{ -+ CRToken *token = NULL; -+ CRInputPos init_pos; -+ enum CRStatus status = CR_ERROR; -+ -+ g_return_val_if_fail (a_this && PRIVATE (a_this), CR_BAD_PARAM_ERROR); -+ -+ RECORD_INITIAL_POS (a_this, &init_pos); -+ -+ continue_parsing: -+ -+ if (token) { -+ cr_token_destroy (token); -+ token = NULL; -+ } -+ -+ cr_parser_try_to_skip_spaces_and_comments (a_this); -+ status = cr_tknzr_get_next_token (PRIVATE (a_this)->tknzr, &token); -+ if (status == CR_END_OF_INPUT_ERROR) { -+ status = CR_OK; -+ goto done; -+ } else if (status != CR_OK) { -+ goto error; -+ } -+ -+ switch (token->type) { -+ -+ case CDO_TK: -+ case CDC_TK: -+ goto continue_parsing; -+ break; -+ default: -+ status = cr_tknzr_unget_token (PRIVATE (a_this)->tknzr, -+ token); -+ CHECK_PARSING_STATUS (status, TRUE); -+ token = NULL; -+ status = cr_parser_parse_statement_core (a_this); -+ cr_parser_clear_errors (a_this); -+ if (status == CR_OK) { -+ goto continue_parsing; -+ } else if (status == CR_END_OF_INPUT_ERROR) { -+ goto done; -+ } else { -+ goto error; -+ } -+ } -+ -+ done: -+ if (token) { -+ cr_token_destroy (token); -+ token = NULL; -+ } -+ -+ cr_parser_clear_errors (a_this); -+ return CR_OK; -+ -+ error: -+ cr_parser_push_error -+ (a_this, (const guchar *) "could not recognize next production", CR_ERROR); -+ -+ cr_parser_dump_err_stack (a_this, TRUE); -+ -+ if (token) { -+ cr_token_destroy (token); -+ token = NULL; -+ } -+ -+ cr_tknzr_set_cur_pos (PRIVATE (a_this)->tknzr, &init_pos); -+ -+ return status; -+} -+ -+/** -+ *Parses an at-rule as defined by the css core grammar -+ *in chapter 4.1 in the css2 spec. -+ *at-rule : ATKEYWORD S* any* [ block | ';' S* ]; -+ *@param a_this the current instance of #CRParser. -+ *@return CR_OK upon successfull completion, an error code -+ *otherwise. -+ */ -+static enum CRStatus -+cr_parser_parse_atrule_core (CRParser * a_this) -+{ -+ CRToken *token = NULL; -+ CRInputPos init_pos; -+ enum CRStatus status = CR_ERROR; -+ -+ g_return_val_if_fail (a_this && PRIVATE (a_this), CR_BAD_PARAM_ERROR); -+ -+ RECORD_INITIAL_POS (a_this, &init_pos); -+ -+ status = cr_tknzr_get_next_token (PRIVATE (a_this)->tknzr, -+ &token); -+ ENSURE_PARSING_COND (status == CR_OK -+ && token -+ && -+ (token->type == ATKEYWORD_TK -+ || token->type == IMPORT_SYM_TK -+ || token->type == PAGE_SYM_TK -+ || token->type == MEDIA_SYM_TK -+ || token->type == FONT_FACE_SYM_TK -+ || token->type == CHARSET_SYM_TK)); -+ -+ cr_token_destroy (token); -+ token = NULL; -+ -+ cr_parser_try_to_skip_spaces_and_comments (a_this); -+ -+ do { -+ status = cr_parser_parse_any_core (a_this); -+ } while (status == CR_OK); -+ -+ status = cr_tknzr_get_next_token (PRIVATE (a_this)->tknzr, -+ &token); -+ ENSURE_PARSING_COND (status == CR_OK && token); -+ -+ if (token->type == CBO_TK) { -+ cr_tknzr_unget_token (PRIVATE (a_this)->tknzr, -+ token); -+ token = NULL; -+ status = cr_parser_parse_block_core (a_this); -+ CHECK_PARSING_STATUS (status, -+ FALSE); -+ goto done; -+ } else if (token->type == SEMICOLON_TK) { -+ goto done; -+ } else { -+ status = CR_PARSING_ERROR ; -+ goto error; -+ } -+ -+ done: -+ if (token) { -+ cr_token_destroy (token); -+ token = NULL; -+ } -+ return CR_OK; -+ -+ error: -+ if (token) { -+ cr_token_destroy (token); -+ token = NULL; -+ } -+ cr_tknzr_set_cur_pos (PRIVATE (a_this)->tknzr, -+ &init_pos); -+ return status; -+} -+ -+/** -+ *Parses a ruleset as defined by the css core grammar in chapter -+ *4.1 of the css2 spec. -+ *ruleset ::= selector? '{' S* declaration? [ ';' S* declaration? ]* '}' S*; -+ *@param a_this the current instance of #CRParser. -+ *@return CR_OK upon successfull completion, an error code otherwise. -+ */ -+static enum CRStatus -+cr_parser_parse_ruleset_core (CRParser * a_this) -+{ -+ CRToken *token = NULL; -+ CRInputPos init_pos; -+ enum CRStatus status = CR_ERROR; -+ -+ g_return_val_if_fail (a_this && PRIVATE (a_this), CR_BAD_PARAM_ERROR); -+ RECORD_INITIAL_POS (a_this, &init_pos); -+ -+ status = cr_parser_parse_selector_core (a_this); -+ -+ ENSURE_PARSING_COND (status == CR_OK -+ || status == CR_PARSING_ERROR -+ || status == CR_END_OF_INPUT_ERROR); -+ -+ status = cr_tknzr_get_next_token (PRIVATE (a_this)->tknzr, &token); -+ ENSURE_PARSING_COND (status == CR_OK && token -+ && token->type == CBO_TK); -+ cr_token_destroy (token); -+ token = NULL; -+ -+ cr_parser_try_to_skip_spaces_and_comments (a_this); -+ status = cr_parser_parse_declaration_core (a_this); -+ -+ parse_declaration_list: -+ if (token) { -+ cr_token_destroy (token); -+ token = NULL; -+ } -+ -+ status = cr_tknzr_get_next_token (PRIVATE (a_this)->tknzr, &token); -+ ENSURE_PARSING_COND (status == CR_OK && token); -+ if (token->type == CBC_TK) { -+ goto done; -+ } -+ -+ ENSURE_PARSING_COND (status == CR_OK -+ && token && token->type == SEMICOLON_TK); -+ -+ cr_token_destroy (token); -+ token = NULL; -+ cr_parser_try_to_skip_spaces_and_comments (a_this); -+ status = cr_parser_parse_declaration_core (a_this); -+ cr_parser_clear_errors (a_this); -+ ENSURE_PARSING_COND (status == CR_OK || status == CR_PARSING_ERROR); -+ status = cr_tknzr_get_next_token (PRIVATE (a_this)->tknzr, &token); -+ ENSURE_PARSING_COND (status == CR_OK && token); -+ if (token->type == CBC_TK) { -+ cr_token_destroy (token); -+ token = NULL; -+ cr_parser_try_to_skip_spaces_and_comments (a_this); -+ goto done; -+ } else { -+ status = cr_tknzr_unget_token (PRIVATE (a_this)->tknzr, -+ token); -+ token = NULL; -+ goto parse_declaration_list; -+ } -+ -+ done: -+ if (token) { -+ cr_token_destroy (token); -+ token = NULL; -+ } -+ -+ if (status == CR_OK) { -+ return CR_OK; -+ } -+ -+ error: -+ if (token) { -+ cr_token_destroy (token); -+ token = NULL; -+ } -+ -+ cr_tknzr_set_cur_pos (PRIVATE (a_this)->tknzr, &init_pos); -+ -+ return status; -+} -+ -+/** -+ *Parses a "selector" as specified by the css core -+ *grammar. -+ *selector : any+; -+ *@param a_this the current instance of #CRParser. -+ *@return CR_OK upon successfull completion, an error code -+ *otherwise. -+ */ -+static enum CRStatus -+cr_parser_parse_selector_core (CRParser * a_this) -+{ -+ CRToken *token = NULL; -+ CRInputPos init_pos; -+ enum CRStatus status = CR_ERROR; -+ -+ g_return_val_if_fail (a_this && PRIVATE (a_this), CR_BAD_PARAM_ERROR); -+ -+ RECORD_INITIAL_POS (a_this, &init_pos); -+ -+ status = cr_parser_parse_any_core (a_this); -+ CHECK_PARSING_STATUS (status, FALSE); -+ -+ do { -+ status = cr_parser_parse_any_core (a_this); -+ -+ } while (status == CR_OK); -+ -+ return CR_OK; -+ -+ error: -+ if (token) { -+ cr_token_destroy (token); -+ token = NULL; -+ } -+ -+ cr_tknzr_set_cur_pos (PRIVATE (a_this)->tknzr, &init_pos); -+ -+ return status; -+} -+ -+/** -+ *Parses a "block" as defined in the css core grammar -+ *in chapter 4.1 of the css2 spec. -+ *block ::= '{' S* [ any | block | ATKEYWORD S* | ';' ]* '}' S*; -+ *@param a_this the current instance of #CRParser. -+ *FIXME: code this function. -+ */ -+static enum CRStatus -+cr_parser_parse_block_core (CRParser * a_this) -+{ -+ CRToken *token = NULL; -+ CRInputPos init_pos; -+ enum CRStatus status = CR_ERROR; -+ -+ g_return_val_if_fail (a_this && PRIVATE (a_this), CR_BAD_PARAM_ERROR); -+ -+ RECORD_INITIAL_POS (a_this, &init_pos); -+ -+ status = cr_tknzr_get_next_token (PRIVATE (a_this)->tknzr, &token); -+ ENSURE_PARSING_COND (status == CR_OK && token -+ && token->type == CBO_TK); -+ -+ parse_block_content: -+ -+ if (token) { -+ cr_token_destroy (token); -+ token = NULL; -+ } -+ -+ cr_parser_try_to_skip_spaces_and_comments (a_this); -+ -+ status = cr_tknzr_get_next_token (PRIVATE (a_this)->tknzr, &token); -+ ENSURE_PARSING_COND (status == CR_OK && token); -+ -+ if (token->type == CBC_TK) { -+ cr_parser_try_to_skip_spaces_and_comments (a_this); -+ goto done; -+ } else if (token->type == SEMICOLON_TK) { -+ goto parse_block_content; -+ } else if (token->type == ATKEYWORD_TK) { -+ cr_parser_try_to_skip_spaces_and_comments (a_this); -+ goto parse_block_content; -+ } else if (token->type == CBO_TK) { -+ cr_tknzr_unget_token (PRIVATE (a_this)->tknzr, token); -+ token = NULL; -+ status = cr_parser_parse_block_core (a_this); -+ CHECK_PARSING_STATUS (status, FALSE); -+ goto parse_block_content; -+ } else { -+ cr_tknzr_unget_token (PRIVATE (a_this)->tknzr, token); -+ token = NULL; -+ status = cr_parser_parse_any_core (a_this); -+ CHECK_PARSING_STATUS (status, FALSE); -+ goto parse_block_content; -+ } -+ -+ done: -+ if (token) { -+ cr_token_destroy (token); -+ token = NULL; -+ } -+ -+ if (status == CR_OK) -+ return CR_OK; -+ -+ error: -+ if (token) { -+ cr_token_destroy (token); -+ token = NULL; -+ } -+ -+ cr_tknzr_set_cur_pos (PRIVATE (a_this)->tknzr, &init_pos); -+ -+ return status; -+} -+ -+static enum CRStatus -+cr_parser_parse_declaration_core (CRParser * a_this) -+{ -+ CRToken *token = NULL; -+ CRInputPos init_pos; -+ enum CRStatus status = CR_ERROR; -+ CRString *prop = NULL; -+ -+ g_return_val_if_fail (a_this && PRIVATE (a_this), CR_BAD_PARAM_ERROR); -+ -+ RECORD_INITIAL_POS (a_this, &init_pos); -+ -+ status = cr_parser_parse_property (a_this, &prop); -+ CHECK_PARSING_STATUS (status, FALSE); -+ cr_parser_clear_errors (a_this); -+ ENSURE_PARSING_COND (status == CR_OK && prop); -+ cr_string_destroy (prop); -+ prop = NULL; -+ -+ status = cr_tknzr_get_next_token (PRIVATE (a_this)->tknzr, &token); -+ ENSURE_PARSING_COND (status == CR_OK -+ && token -+ && token->type == DELIM_TK -+ && token->u.unichar == ':'); -+ cr_token_destroy (token); -+ token = NULL; -+ cr_parser_try_to_skip_spaces_and_comments (a_this); -+ status = cr_parser_parse_value_core (a_this); -+ CHECK_PARSING_STATUS (status, FALSE); -+ -+ return CR_OK; -+ -+ error: -+ -+ if (prop) { -+ cr_string_destroy (prop); -+ prop = NULL; -+ } -+ -+ if (token) { -+ cr_token_destroy (token); -+ token = NULL; -+ } -+ -+ cr_tknzr_set_cur_pos (PRIVATE (a_this)->tknzr, &init_pos); -+ -+ return status; -+} -+ -+/** -+ *Parses a "value" production as defined by the css core grammar -+ *in chapter 4.1. -+ *value ::= [ any | block | ATKEYWORD S* ]+; -+ *@param a_this the current instance of #CRParser. -+ *@return CR_OK upon successfull completion, an error code otherwise. -+ */ -+static enum CRStatus -+cr_parser_parse_value_core (CRParser * a_this) -+{ -+ CRToken *token = NULL; -+ CRInputPos init_pos; -+ enum CRStatus status = CR_ERROR; -+ glong ref = 0; -+ -+ g_return_val_if_fail (a_this && PRIVATE (a_this), CR_BAD_PARAM_ERROR); -+ RECORD_INITIAL_POS (a_this, &init_pos); -+ -+ continue_parsing: -+ -+ if (token) { -+ cr_token_destroy (token); -+ token = NULL; -+ } -+ -+ status = cr_tknzr_get_next_token (PRIVATE (a_this)->tknzr, &token); -+ ENSURE_PARSING_COND (status == CR_OK && token); -+ -+ switch (token->type) { -+ case CBO_TK: -+ status = cr_tknzr_unget_token (PRIVATE (a_this)->tknzr, -+ token); -+ token = NULL; -+ status = cr_parser_parse_block_core (a_this); -+ CHECK_PARSING_STATUS (status, FALSE); -+ ref++; -+ goto continue_parsing; -+ -+ case ATKEYWORD_TK: -+ cr_parser_try_to_skip_spaces_and_comments (a_this); -+ ref++; -+ goto continue_parsing; -+ -+ default: -+ status = cr_tknzr_unget_token (PRIVATE (a_this)->tknzr, -+ token); -+ token = NULL; -+ status = cr_parser_parse_any_core (a_this); -+ if (status == CR_OK) { -+ ref++; -+ goto continue_parsing; -+ } else if (status == CR_PARSING_ERROR) { -+ status = CR_OK; -+ goto done; -+ } else { -+ goto error; -+ } -+ } -+ -+ done: -+ if (token) { -+ cr_token_destroy (token); -+ token = NULL; -+ } -+ -+ if (status == CR_OK && ref) -+ return CR_OK; -+ error: -+ if (token) { -+ cr_token_destroy (token); -+ token = NULL; -+ } -+ -+ cr_tknzr_set_cur_pos (PRIVATE (a_this)->tknzr, &init_pos); -+ -+ return status; -+} -+ -+/** -+ *Parses an "any" as defined by the css core grammar in the -+ *css2 spec in chapter 4.1. -+ *any ::= [ IDENT | NUMBER | PERCENTAGE | DIMENSION | STRING -+ * | DELIM | URI | HASH | UNICODE-RANGE | INCLUDES -+ * | FUNCTION | DASHMATCH | '(' any* ')' | '[' any* ']' ] S*; -+ * -+ *@param a_this the current instance of #CRParser. -+ *@return CR_OK upon successfull completion, an error code otherwise. -+ */ -+static enum CRStatus -+cr_parser_parse_any_core (CRParser * a_this) -+{ -+ CRToken *token1 = NULL, -+ *token2 = NULL; -+ CRInputPos init_pos; -+ enum CRStatus status = CR_ERROR; -+ -+ g_return_val_if_fail (a_this, CR_BAD_PARAM_ERROR); -+ -+ RECORD_INITIAL_POS (a_this, &init_pos); -+ -+ status = cr_tknzr_get_next_token (PRIVATE (a_this)->tknzr, &token1); -+ -+ ENSURE_PARSING_COND (status == CR_OK && token1); -+ -+ switch (token1->type) { -+ case IDENT_TK: -+ case NUMBER_TK: -+ case RGB_TK: -+ case PERCENTAGE_TK: -+ case DIMEN_TK: -+ case EMS_TK: -+ case EXS_TK: -+ case LENGTH_TK: -+ case ANGLE_TK: -+ case FREQ_TK: -+ case TIME_TK: -+ case STRING_TK: -+ case DELIM_TK: -+ case URI_TK: -+ case HASH_TK: -+ case UNICODERANGE_TK: -+ case INCLUDES_TK: -+ case DASHMATCH_TK: -+ case S_TK: -+ case COMMENT_TK: -+ case IMPORTANT_SYM_TK: -+ status = CR_OK; -+ break; -+ case FUNCTION_TK: -+ /* -+ *this case isn't specified by the spec but it -+ *does happen. So we have to handle it. -+ *We must consider function with parameters. -+ *We consider parameter as being an "any*" production. -+ */ -+ do { -+ status = cr_parser_parse_any_core (a_this); -+ } while (status == CR_OK); -+ -+ ENSURE_PARSING_COND (status == CR_PARSING_ERROR); -+ status = cr_tknzr_get_next_token (PRIVATE (a_this)->tknzr, -+ &token2); -+ ENSURE_PARSING_COND (status == CR_OK -+ && token2 && token2->type == PC_TK); -+ break; -+ case PO_TK: -+ status = cr_tknzr_get_next_token (PRIVATE (a_this)->tknzr, -+ &token2); -+ ENSURE_PARSING_COND (status == CR_OK && token2); -+ -+ if (token2->type == PC_TK) { -+ cr_token_destroy (token2); -+ token2 = NULL; -+ goto done; -+ } else { -+ status = cr_tknzr_unget_token -+ (PRIVATE (a_this)->tknzr, token2); -+ token2 = NULL; -+ } -+ -+ do { -+ status = cr_parser_parse_any_core (a_this); -+ } while (status == CR_OK); -+ -+ ENSURE_PARSING_COND (status == CR_PARSING_ERROR); -+ -+ status = cr_tknzr_get_next_token (PRIVATE (a_this)->tknzr, -+ &token2); -+ ENSURE_PARSING_COND (status == CR_OK -+ && token2 && token2->type == PC_TK); -+ status = CR_OK; -+ break; -+ -+ case BO_TK: -+ status = cr_tknzr_get_next_token (PRIVATE (a_this)->tknzr, -+ &token2); -+ ENSURE_PARSING_COND (status == CR_OK && token2); -+ -+ if (token2->type == BC_TK) { -+ cr_token_destroy (token2); -+ token2 = NULL; -+ goto done; -+ } else { -+ status = cr_tknzr_unget_token -+ (PRIVATE (a_this)->tknzr, token2); -+ token2 = NULL; -+ } -+ -+ do { -+ status = cr_parser_parse_any_core (a_this); -+ } while (status == CR_OK); -+ -+ ENSURE_PARSING_COND (status == CR_PARSING_ERROR); -+ -+ status = cr_tknzr_get_next_token (PRIVATE (a_this)->tknzr, -+ &token2); -+ ENSURE_PARSING_COND (status == CR_OK -+ && token2 && token2->type == BC_TK); -+ status = CR_OK; -+ break; -+ default: -+ status = CR_PARSING_ERROR; -+ goto error; -+ } -+ -+ done: -+ if (token1) { -+ cr_token_destroy (token1); -+ token1 = NULL; -+ } -+ -+ if (token2) { -+ cr_token_destroy (token2); -+ token2 = NULL; -+ } -+ -+ return CR_OK; -+ -+ error: -+ -+ if (token1) { -+ cr_token_destroy (token1); -+ token1 = NULL; -+ } -+ -+ if (token2) { -+ cr_token_destroy (token2); -+ token2 = NULL; -+ } -+ -+ cr_tknzr_set_cur_pos (PRIVATE (a_this)->tknzr, &init_pos); -+ return status; -+} -+ -+/** -+ *Parses an attribute selector as defined in the css2 spec in -+ *appendix D.1: -+ *attrib ::= '[' S* IDENT S* [ [ '=' | INCLUDES | DASHMATCH ] S* -+ * [ IDENT | STRING ] S* ]? ']' -+ * -+ *@param a_this the "this pointer" of the current instance of -+ *#CRParser . -+ *@param a_sel out parameter. The successfully parsed attribute selector. -+ *@return CR_OK upon successfull completion, an error code otherwise. -+ */ -+static enum CRStatus -+cr_parser_parse_attribute_selector (CRParser * a_this, -+ CRAttrSel ** a_sel) -+{ -+ enum CRStatus status = CR_OK; -+ CRInputPos init_pos; -+ CRToken *token = NULL; -+ CRAttrSel *result = NULL; -+ CRParsingLocation location = {0} ; -+ -+ g_return_val_if_fail (a_this && a_sel, CR_BAD_PARAM_ERROR); -+ -+ RECORD_INITIAL_POS (a_this, &init_pos); -+ -+ status = cr_tknzr_get_next_token (PRIVATE (a_this)->tknzr, &token); -+ ENSURE_PARSING_COND (status == CR_OK && token -+ && token->type == BO_TK); -+ cr_parsing_location_copy -+ (&location, &token->location) ; -+ cr_token_destroy (token); -+ token = NULL; -+ -+ cr_parser_try_to_skip_spaces_and_comments (a_this); -+ -+ result = cr_attr_sel_new (); -+ if (!result) { -+ cr_utils_trace_info ("result failed") ; -+ status = CR_OUT_OF_MEMORY_ERROR ; -+ goto error ; -+ } -+ cr_parsing_location_copy (&result->location, -+ &location) ; -+ status = cr_tknzr_get_next_token (PRIVATE (a_this)->tknzr, &token); -+ ENSURE_PARSING_COND (status == CR_OK -+ && token && token->type == IDENT_TK); -+ -+ result->name = token->u.str; -+ token->u.str = NULL; -+ cr_token_destroy (token); -+ token = NULL; -+ -+ cr_parser_try_to_skip_spaces_and_comments (a_this); -+ -+ status = cr_tknzr_get_next_token (PRIVATE (a_this)->tknzr, &token); -+ ENSURE_PARSING_COND (status == CR_OK && token); -+ -+ if (token->type == INCLUDES_TK) { -+ result->match_way = INCLUDES; -+ goto parse_right_part; -+ } else if (token->type == DASHMATCH_TK) { -+ result->match_way = DASHMATCH; -+ goto parse_right_part; -+ } else if (token->type == DELIM_TK && token->u.unichar == '=') { -+ result->match_way = EQUALS; -+ goto parse_right_part; -+ } else if (token->type == BC_TK) { -+ result->match_way = SET; -+ goto done; -+ } -+ -+ parse_right_part: -+ -+ if (token) { -+ cr_token_destroy (token); -+ token = NULL; -+ } -+ -+ cr_parser_try_to_skip_spaces_and_comments (a_this); -+ -+ status = cr_tknzr_get_next_token (PRIVATE (a_this)->tknzr, &token); -+ ENSURE_PARSING_COND (status == CR_OK && token); -+ -+ if (token->type == IDENT_TK) { -+ result->value = token->u.str; -+ token->u.str = NULL; -+ } else if (token->type == STRING_TK) { -+ result->value = token->u.str; -+ token->u.str = NULL; -+ } else { -+ status = CR_PARSING_ERROR; -+ goto error; -+ } -+ -+ if (token) { -+ cr_token_destroy (token); -+ token = NULL; -+ } -+ -+ cr_parser_try_to_skip_spaces_and_comments (a_this); -+ -+ status = cr_tknzr_get_next_token (PRIVATE (a_this)->tknzr, &token); -+ -+ ENSURE_PARSING_COND (status == CR_OK && token -+ && token->type == BC_TK); -+ done: -+ if (token) { -+ cr_token_destroy (token); -+ token = NULL; -+ } -+ -+ if (*a_sel) { -+ status = cr_attr_sel_append_attr_sel (*a_sel, result); -+ CHECK_PARSING_STATUS (status, FALSE); -+ } else { -+ *a_sel = result; -+ } -+ -+ cr_parser_clear_errors (a_this); -+ return CR_OK; -+ -+ error: -+ -+ if (result) { -+ cr_attr_sel_destroy (result); -+ result = NULL; -+ } -+ -+ if (token) { -+ cr_token_destroy (token); -+ token = NULL; -+ } -+ -+ cr_tknzr_set_cur_pos (PRIVATE (a_this)->tknzr, &init_pos); -+ -+ return status; -+} -+ -+/** -+ *Parses a "property" as specified by the css2 spec at [4.1.1]: -+ *property : IDENT S*; -+ * -+ *@param a_this the "this pointer" of the current instance of #CRParser. -+ *@param GString a_property out parameter. The parsed property without the -+ *trailing spaces. If *a_property is NULL, this function allocates a -+ *new instance of GString and set it content to the parsed property. -+ *If not, the property is just appended to a_property's previous content. -+ *In both cases, it is up to the caller to free a_property. -+ *@return CR_OK upon successfull completion, CR_PARSING_ERROR if the -+ *next construction was not a "property", or an error code. -+ */ -+static enum CRStatus -+cr_parser_parse_property (CRParser * a_this, -+ CRString ** a_property) -+{ -+ enum CRStatus status = CR_OK; -+ CRInputPos init_pos; -+ -+ g_return_val_if_fail (a_this && PRIVATE (a_this) -+ && PRIVATE (a_this)->tknzr -+ && a_property, -+ CR_BAD_PARAM_ERROR); -+ -+ RECORD_INITIAL_POS (a_this, &init_pos); -+ -+ status = cr_parser_parse_ident (a_this, a_property); -+ CHECK_PARSING_STATUS (status, TRUE); -+ -+ cr_parser_try_to_skip_spaces_and_comments (a_this); -+ -+ cr_parser_clear_errors (a_this); -+ return CR_OK; -+ -+ error: -+ -+ cr_tknzr_set_cur_pos (PRIVATE (a_this)->tknzr, &init_pos); -+ -+ return status; -+} -+ -+/** -+ * cr_parser_parse_term: -+ *@a_term: out parameter. The successfully parsed term. -+ * -+ *Parses a "term" as defined in the css2 spec, appendix D.1: -+ *term ::= unary_operator? [NUMBER S* | PERCENTAGE S* | LENGTH S* | -+ *EMS S* | EXS S* | ANGLE S* | TIME S* | FREQ S* | function ] | -+ *STRING S* | IDENT S* | URI S* | RGB S* | UNICODERANGE S* | hexcolor -+ * -+ *TODO: handle parsing of 'RGB' -+ * -+ *Returns CR_OK upon successfull completion, an error code otherwise. -+ */ -+enum CRStatus -+cr_parser_parse_term (CRParser * a_this, CRTerm ** a_term) -+{ -+ enum CRStatus status = CR_PARSING_ERROR; -+ CRInputPos init_pos; -+ CRTerm *result = NULL; -+ CRTerm *param = NULL; -+ CRToken *token = NULL; -+ CRString *func_name = NULL; -+ CRParsingLocation location = {0} ; -+ -+ g_return_val_if_fail (a_this && a_term, CR_BAD_PARAM_ERROR); -+ -+ RECORD_INITIAL_POS (a_this, &init_pos); -+ -+ result = cr_term_new (); -+ -+ status = cr_tknzr_get_next_token (PRIVATE (a_this)->tknzr, -+ &token); -+ if (status != CR_OK || !token) -+ goto error; -+ -+ cr_parsing_location_copy (&location, &token->location) ; -+ if (token->type == DELIM_TK && token->u.unichar == '+') { -+ result->unary_op = PLUS_UOP; -+ cr_token_destroy (token) ; -+ token = NULL ; -+ cr_parser_try_to_skip_spaces_and_comments (a_this); -+ status = cr_tknzr_get_next_token (PRIVATE (a_this)->tknzr, -+ &token); -+ if (status != CR_OK || !token) -+ goto error; -+ } else if (token->type == DELIM_TK && token->u.unichar == '-') { -+ result->unary_op = MINUS_UOP; -+ cr_token_destroy (token) ; -+ token = NULL ; -+ cr_parser_try_to_skip_spaces_and_comments (a_this); -+ status = cr_tknzr_get_next_token (PRIVATE (a_this)->tknzr, -+ &token); -+ if (status != CR_OK || !token) -+ goto error; -+ } -+ -+ if (token->type == EMS_TK -+ || token->type == EXS_TK -+ || token->type == LENGTH_TK -+ || token->type == ANGLE_TK -+ || token->type == TIME_TK -+ || token->type == FREQ_TK -+ || token->type == PERCENTAGE_TK -+ || token->type == NUMBER_TK) { -+ status = cr_term_set_number (result, token->u.num); -+ CHECK_PARSING_STATUS (status, TRUE); -+ token->u.num = NULL; -+ status = CR_OK; -+ } else if (token && token->type == FUNCTION_TK) { -+ status = cr_tknzr_unget_token (PRIVATE (a_this)->tknzr, -+ token); -+ token = NULL; -+ status = cr_parser_parse_function (a_this, &func_name, -+ ¶m); -+ -+ if (status == CR_OK) { -+ status = cr_term_set_function (result, -+ func_name, -+ param); -+ CHECK_PARSING_STATUS (status, TRUE); -+ } -+ } else if (token && token->type == STRING_TK) { -+ status = cr_term_set_string (result, -+ token->u.str); -+ CHECK_PARSING_STATUS (status, TRUE); -+ token->u.str = NULL; -+ } else if (token && token->type == IDENT_TK) { -+ status = cr_term_set_ident (result, token->u.str); -+ CHECK_PARSING_STATUS (status, TRUE); -+ token->u.str = NULL; -+ } else if (token && token->type == URI_TK) { -+ status = cr_term_set_uri (result, token->u.str); -+ CHECK_PARSING_STATUS (status, TRUE); -+ token->u.str = NULL; -+ } else if (token && token->type == RGB_TK) { -+ status = cr_term_set_rgb (result, token->u.rgb); -+ CHECK_PARSING_STATUS (status, TRUE); -+ token->u.rgb = NULL; -+ } else if (token && token->type == UNICODERANGE_TK) { -+ result->type = TERM_UNICODERANGE; -+ status = CR_PARSING_ERROR; -+ } else if (token && token->type == HASH_TK) { -+ status = cr_term_set_hash (result, token->u.str); -+ CHECK_PARSING_STATUS (status, TRUE); -+ token->u.str = NULL; -+ } else { -+ status = CR_PARSING_ERROR; -+ } -+ -+ if (status != CR_OK) { -+ goto error; -+ } -+ cr_parsing_location_copy (&result->location, -+ &location) ; -+ *a_term = cr_term_append_term (*a_term, result); -+ -+ result = NULL; -+ -+ cr_parser_try_to_skip_spaces_and_comments (a_this); -+ -+ if (token) { -+ cr_token_destroy (token); -+ token = NULL; -+ } -+ -+ cr_parser_clear_errors (a_this); -+ return CR_OK; -+ -+ error: -+ -+ if (result) { -+ cr_term_destroy (result); -+ result = NULL; -+ } -+ -+ if (token) { -+ cr_token_destroy (token); -+ token = NULL; -+ } -+ -+ if (param) { -+ cr_term_destroy (param); -+ param = NULL; -+ } -+ -+ if (func_name) { -+ cr_string_destroy (func_name); -+ func_name = NULL; -+ } -+ -+ cr_tknzr_set_cur_pos (PRIVATE (a_this)->tknzr, &init_pos); -+ -+ return status; -+} -+ -+/** -+ * cr_parser_parse_simple_selector: -+ *@a_this: the "this pointer" of the current instance of #CRParser. -+ *@a_sel: out parameter. Is set to the successfully parsed simple -+ *selector. -+ * -+ *Parses a "simple_selector" as defined by the css2 spec in appendix D.1 : -+ *element_name? [ HASH | class | attrib | pseudo ]* S* -+ *and where pseudo is: -+ *pseudo ::= ':' [ IDENT | FUNCTION S* IDENT S* ')' ] -+ * -+ *Returns CR_OK upon successfull completion, an error code otherwise. -+ */ -+static enum CRStatus -+cr_parser_parse_simple_selector (CRParser * a_this, CRSimpleSel ** a_sel) -+{ -+ enum CRStatus status = CR_ERROR; -+ CRInputPos init_pos; -+ CRToken *token = NULL; -+ CRSimpleSel *sel = NULL; -+ CRAdditionalSel *add_sel_list = NULL; -+ gboolean found_sel = FALSE; -+ guint32 cur_char = 0; -+ -+ g_return_val_if_fail (a_this && a_sel, CR_BAD_PARAM_ERROR); -+ -+ RECORD_INITIAL_POS (a_this, &init_pos); -+ -+ status = cr_tknzr_get_next_token (PRIVATE (a_this)->tknzr, &token); -+ if (status != CR_OK) -+ goto error; -+ -+ sel = cr_simple_sel_new (); -+ ENSURE_PARSING_COND (sel); -+ -+ cr_parsing_location_copy -+ (&sel->location, -+ &token->location) ; -+ -+ if (token && token->type == DELIM_TK -+ && token->u.unichar == '*') { -+ sel->type_mask |= UNIVERSAL_SELECTOR; -+ sel->name = cr_string_new_from_string ("*"); -+ found_sel = TRUE; -+ } else if (token && token->type == IDENT_TK) { -+ sel->name = token->u.str; -+ sel->type_mask |= TYPE_SELECTOR; -+ token->u.str = NULL; -+ found_sel = TRUE; -+ } else { -+ status = cr_tknzr_unget_token -+ (PRIVATE (a_this)->tknzr, -+ token); -+ token = NULL; -+ } -+ -+ if (token) { -+ cr_token_destroy (token); -+ token = NULL; -+ } -+ -+ cr_parser_try_to_skip_spaces_and_comments (a_this); -+ -+ for (;;) { -+ if (token) { -+ cr_token_destroy (token); -+ token = NULL; -+ } -+ -+ status = cr_tknzr_get_next_token -+ (PRIVATE (a_this)->tknzr, -+ &token); -+ if (status != CR_OK) -+ goto error; -+ -+ if (token && token->type == HASH_TK) { -+ /*we parsed an attribute id */ -+ CRAdditionalSel *add_sel = NULL; -+ -+ add_sel = cr_additional_sel_new_with_type -+ (ID_ADD_SELECTOR); -+ -+ add_sel->content.id_name = token->u.str; -+ token->u.str = NULL; -+ -+ cr_parsing_location_copy -+ (&add_sel->location, -+ &token->location) ; -+ add_sel_list = -+ cr_additional_sel_append -+ (add_sel_list, add_sel); -+ found_sel = TRUE; -+ } else if (token && (token->type == DELIM_TK) -+ && (token->u.unichar == '.')) { -+ cr_token_destroy (token); -+ token = NULL; -+ -+ status = cr_tknzr_get_next_token -+ (PRIVATE (a_this)->tknzr, &token); -+ if (status != CR_OK) -+ goto error; -+ -+ if (token && token->type == IDENT_TK) { -+ CRAdditionalSel *add_sel = NULL; -+ -+ add_sel = cr_additional_sel_new_with_type -+ (CLASS_ADD_SELECTOR); -+ -+ add_sel->content.class_name = token->u.str; -+ token->u.str = NULL; -+ -+ add_sel_list = -+ cr_additional_sel_append -+ (add_sel_list, add_sel); -+ found_sel = TRUE; -+ -+ cr_parsing_location_copy -+ (&add_sel->location, -+ & token->location) ; -+ } else { -+ status = CR_PARSING_ERROR; -+ goto error; -+ } -+ } else if (token && token->type == BO_TK) { -+ CRAttrSel *attr_sel = NULL; -+ CRAdditionalSel *add_sel = NULL; -+ -+ status = cr_tknzr_unget_token -+ (PRIVATE (a_this)->tknzr, token); -+ if (status != CR_OK) -+ goto error; -+ token = NULL; -+ -+ status = cr_parser_parse_attribute_selector -+ (a_this, &attr_sel); -+ CHECK_PARSING_STATUS (status, FALSE); -+ -+ add_sel = cr_additional_sel_new_with_type -+ (ATTRIBUTE_ADD_SELECTOR); -+ -+ ENSURE_PARSING_COND (add_sel != NULL); -+ -+ add_sel->content.attr_sel = attr_sel; -+ -+ add_sel_list = -+ cr_additional_sel_append -+ (add_sel_list, add_sel); -+ found_sel = TRUE; -+ cr_parsing_location_copy -+ (&add_sel->location, -+ &attr_sel->location) ; -+ } else if (token && (token->type == DELIM_TK) -+ && (token->u.unichar == ':')) { -+ CRPseudo *pseudo = NULL; -+ -+ /*try to parse a pseudo */ -+ -+ if (token) { -+ cr_token_destroy (token); -+ token = NULL; -+ } -+ -+ pseudo = cr_pseudo_new (); -+ -+ status = cr_tknzr_get_next_token -+ (PRIVATE (a_this)->tknzr, &token); -+ ENSURE_PARSING_COND (status == CR_OK && token); -+ -+ cr_parsing_location_copy -+ (&pseudo->location, -+ &token->location) ; -+ -+ if (token->type == IDENT_TK) { -+ pseudo->type = IDENT_PSEUDO; -+ pseudo->name = token->u.str; -+ token->u.str = NULL; -+ found_sel = TRUE; -+ } else if (token->type == FUNCTION_TK) { -+ pseudo->name = token->u.str; -+ token->u.str = NULL; -+ cr_parser_try_to_skip_spaces_and_comments -+ (a_this); -+ status = cr_parser_parse_ident -+ (a_this, &pseudo->extra); -+ -+ ENSURE_PARSING_COND (status == CR_OK); -+ READ_NEXT_CHAR (a_this, &cur_char); -+ ENSURE_PARSING_COND (cur_char == ')'); -+ pseudo->type = FUNCTION_PSEUDO; -+ found_sel = TRUE; -+ } else { -+ status = CR_PARSING_ERROR; -+ goto error; -+ } -+ -+ if (status == CR_OK) { -+ CRAdditionalSel *add_sel = NULL; -+ -+ add_sel = cr_additional_sel_new_with_type -+ (PSEUDO_CLASS_ADD_SELECTOR); -+ -+ add_sel->content.pseudo = pseudo; -+ cr_parsing_location_copy -+ (&add_sel->location, -+ &pseudo->location) ; -+ add_sel_list = -+ cr_additional_sel_append -+ (add_sel_list, add_sel); -+ status = CR_OK; -+ } -+ } else { -+ status = cr_tknzr_unget_token -+ (PRIVATE (a_this)->tknzr, token); -+ token = NULL; -+ break; -+ } -+ } -+ -+ if (status == CR_OK && found_sel == TRUE) { -+ cr_parser_try_to_skip_spaces_and_comments (a_this); -+ -+ sel->add_sel = add_sel_list; -+ add_sel_list = NULL; -+ -+ if (*a_sel == NULL) { -+ *a_sel = sel; -+ } else { -+ cr_simple_sel_append_simple_sel (*a_sel, sel); -+ } -+ -+ sel = NULL; -+ -+ if (token) { -+ cr_token_destroy (token); -+ token = NULL; -+ } -+ -+ cr_parser_clear_errors (a_this); -+ return CR_OK; -+ } else { -+ status = CR_PARSING_ERROR; -+ } -+ -+ error: -+ -+ if (token) { -+ cr_token_destroy (token); -+ token = NULL; -+ } -+ -+ if (add_sel_list) { -+ cr_additional_sel_destroy (add_sel_list); -+ add_sel_list = NULL; -+ } -+ -+ if (sel) { -+ cr_simple_sel_destroy (sel); -+ sel = NULL; -+ } -+ -+ cr_tknzr_set_cur_pos (PRIVATE (a_this)->tknzr, &init_pos); -+ -+ return status; -+ -+} -+ -+/** -+ * cr_parser_parse_simple_sels: -+ *@a_this: the this pointer of the current instance of #CRParser. -+ *@a_start: a pointer to the -+ *first chararcter of the successfully parsed -+ *string. -+ *@a_end: a pointer to the last character of the successfully parsed -+ *string. -+ * -+ *Parses a "selector" as defined by the css2 spec in appendix D.1: -+ *selector ::= simple_selector [ combinator simple_selector ]* -+ * -+ *Returns CR_OK upon successfull completion, an error code otherwise. -+ */ -+static enum CRStatus -+cr_parser_parse_simple_sels (CRParser * a_this, -+ CRSimpleSel ** a_sel) -+{ -+ enum CRStatus status = CR_ERROR; -+ CRInputPos init_pos; -+ CRSimpleSel *sel = NULL; -+ guint32 cur_char = 0; -+ -+ g_return_val_if_fail (a_this -+ && PRIVATE (a_this) -+ && a_sel, -+ CR_BAD_PARAM_ERROR); -+ -+ RECORD_INITIAL_POS (a_this, &init_pos); -+ -+ status = cr_parser_parse_simple_selector (a_this, &sel); -+ CHECK_PARSING_STATUS (status, FALSE); -+ -+ *a_sel = cr_simple_sel_append_simple_sel (*a_sel, sel); -+ -+ for (;;) { -+ guint32 next_char = 0; -+ enum Combinator comb = 0; -+ -+ sel = NULL; -+ -+ PEEK_NEXT_CHAR (a_this, &next_char); -+ -+ if (next_char == '+') { -+ READ_NEXT_CHAR (a_this, &cur_char); -+ comb = COMB_PLUS; -+ cr_parser_try_to_skip_spaces_and_comments (a_this); -+ } else if (next_char == '>') { -+ READ_NEXT_CHAR (a_this, &cur_char); -+ comb = COMB_GT; -+ cr_parser_try_to_skip_spaces_and_comments (a_this); -+ } else { -+ comb = COMB_WS; -+ } -+ -+ status = cr_parser_parse_simple_selector (a_this, &sel); -+ if (status != CR_OK) -+ break; -+ -+ if (comb && sel) { -+ sel->combinator = comb; -+ comb = 0; -+ } -+ if (sel) { -+ *a_sel = cr_simple_sel_append_simple_sel (*a_sel, -+ sel) ; -+ } -+ } -+ cr_parser_clear_errors (a_this); -+ return CR_OK; -+ -+ error: -+ -+ cr_tknzr_set_cur_pos (PRIVATE (a_this)->tknzr, &init_pos); -+ -+ return status; -+} -+ -+/** -+ * cr_parser_parse_selector: -+ *@a_this: the current instance of #CRParser. -+ *@a_selector: the parsed list of comma separated -+ *selectors. -+ * -+ *Parses a comma separated list of selectors. -+ * -+ *Returns CR_OK upon successful completion, an error -+ *code otherwise. -+ */ -+static enum CRStatus -+cr_parser_parse_selector (CRParser * a_this, -+ CRSelector ** a_selector) -+{ -+ enum CRStatus status = CR_OK; -+ CRInputPos init_pos; -+ guint32 cur_char = 0, -+ next_char = 0; -+ CRSimpleSel *simple_sels = NULL; -+ CRSelector *selector = NULL; -+ -+ g_return_val_if_fail (a_this && a_selector, CR_BAD_PARAM_ERROR); -+ -+ RECORD_INITIAL_POS (a_this, &init_pos); -+ -+ status = cr_parser_parse_simple_sels (a_this, &simple_sels); -+ CHECK_PARSING_STATUS (status, FALSE); -+ -+ if (simple_sels) { -+ selector = cr_selector_append_simple_sel -+ (selector, simple_sels); -+ if (selector) { -+ cr_parsing_location_copy -+ (&selector->location, -+ &simple_sels->location) ; -+ } -+ simple_sels = NULL; -+ } else { -+ status = CR_PARSING_ERROR ; -+ goto error ; -+ } -+ -+ status = cr_tknzr_peek_char (PRIVATE (a_this)->tknzr, -+ &next_char); -+ if (status != CR_OK) { -+ if (status == CR_END_OF_INPUT_ERROR) { -+ status = CR_OK; -+ goto okay; -+ } else { -+ goto error; -+ } -+ } -+ -+ if (next_char == ',') { -+ for (;;) { -+ simple_sels = NULL; -+ -+ status = cr_tknzr_peek_char (PRIVATE (a_this)->tknzr, -+ &next_char); -+ if (status != CR_OK) { -+ if (status == CR_END_OF_INPUT_ERROR) { -+ status = CR_OK; -+ break; -+ } else { -+ goto error; -+ } -+ } -+ -+ if (next_char != ',') -+ break; -+ -+ /*consume the ',' char */ -+ READ_NEXT_CHAR (a_this, &cur_char); -+ -+ cr_parser_try_to_skip_spaces_and_comments (a_this); -+ -+ status = cr_parser_parse_simple_sels -+ (a_this, &simple_sels); -+ -+ CHECK_PARSING_STATUS (status, FALSE); -+ -+ if (simple_sels) { -+ selector = -+ cr_selector_append_simple_sel -+ (selector, simple_sels); -+ -+ simple_sels = NULL; -+ } -+ } -+ } -+ -+ okay: -+ cr_parser_try_to_skip_spaces_and_comments (a_this); -+ -+ if (!*a_selector) { -+ *a_selector = selector; -+ } else { -+ *a_selector = cr_selector_append (*a_selector, selector); -+ } -+ -+ selector = NULL; -+ return CR_OK; -+ -+ error: -+ -+ if (simple_sels) { -+ cr_simple_sel_destroy (simple_sels); -+ simple_sels = NULL; -+ } -+ -+ if (selector) { -+ cr_selector_unref (selector); -+ selector = NULL; -+ } -+ -+ cr_tknzr_set_cur_pos (PRIVATE (a_this)->tknzr, &init_pos); -+ -+ return status; -+} -+ -+/** -+ * cr_parser_parse_function: -+ *@a_this: the "this pointer" of the current instance of #CRParser. -+ * -+ *@a_func_name: out parameter. The parsed function name -+ *@a_expr: out parameter. The successfully parsed term. -+ * -+ *Parses a "function" as defined in css spec at appendix D.1: -+ *function ::= FUNCTION S* expr ')' S* -+ *FUNCTION ::= ident'(' -+ * -+ *Returns CR_OK upon successfull completion, an error code otherwise. -+ */ -+static enum CRStatus -+cr_parser_parse_function (CRParser * a_this, -+ CRString ** a_func_name, -+ CRTerm ** a_expr) -+{ -+ CRInputPos init_pos; -+ enum CRStatus status = CR_OK; -+ CRToken *token = NULL; -+ CRTerm *expr = NULL; -+ -+ g_return_val_if_fail (a_this && PRIVATE (a_this) -+ && a_func_name, -+ CR_BAD_PARAM_ERROR); -+ -+ RECORD_INITIAL_POS (a_this, &init_pos); -+ -+ status = cr_tknzr_get_next_token (PRIVATE (a_this)->tknzr, &token); -+ if (status != CR_OK) -+ goto error; -+ -+ if (token && token->type == FUNCTION_TK) { -+ *a_func_name = token->u.str; -+ token->u.str = NULL; -+ } else { -+ status = CR_PARSING_ERROR; -+ goto error; -+ } -+ cr_token_destroy (token); -+ token = NULL; -+ -+ cr_parser_try_to_skip_spaces_and_comments (a_this) ; -+ -+ status = cr_parser_parse_expr (a_this, &expr); -+ -+ CHECK_PARSING_STATUS (status, FALSE); -+ -+ status = cr_tknzr_get_next_token (PRIVATE (a_this)->tknzr, &token); -+ if (status != CR_OK) -+ goto error; -+ -+ ENSURE_PARSING_COND (token && token->type == PC_TK); -+ -+ cr_token_destroy (token); -+ token = NULL; -+ -+ if (expr) { -+ *a_expr = cr_term_append_term (*a_expr, expr); -+ expr = NULL; -+ } -+ -+ cr_parser_clear_errors (a_this); -+ return CR_OK; -+ -+ error: -+ -+ if (*a_func_name) { -+ cr_string_destroy (*a_func_name); -+ *a_func_name = NULL; -+ } -+ -+ if (expr) { -+ cr_term_destroy (expr); -+ expr = NULL; -+ } -+ -+ if (token) { -+ cr_token_destroy (token); -+ -+ } -+ -+ cr_tknzr_set_cur_pos (PRIVATE (a_this)->tknzr, &init_pos); -+ -+ return status; -+} -+ -+/** -+ * cr_parser_parse_uri: -+ *@a_this: the current instance of #CRParser. -+ *@a_str: the successfully parsed url. -+ * -+ *Parses an uri as defined by the css spec [4.1.1]: -+ * URI ::= url\({w}{string}{w}\) -+ * |url\({w}([!#$%&*-~]|{nonascii}|{escape})*{w}\) -+ * -+ *Returns CR_OK upon successfull completion, an error code otherwise. -+ */ -+static enum CRStatus -+cr_parser_parse_uri (CRParser * a_this, CRString ** a_str) -+{ -+ -+ enum CRStatus status = CR_PARSING_ERROR; -+ -+ g_return_val_if_fail (a_this && PRIVATE (a_this) -+ && PRIVATE (a_this)->tknzr, CR_BAD_PARAM_ERROR); -+ -+ status = cr_tknzr_parse_token (PRIVATE (a_this)->tknzr, -+ URI_TK, NO_ET, a_str, NULL); -+ return status; -+} -+ -+/** -+ * cr_parser_parse_string: -+ *@a_this: the current instance of #CRParser. -+ *@a_start: out parameter. Upon successfull completion, -+ *points to the beginning of the string, points to an undefined value -+ *otherwise. -+ *@a_end: out parameter. Upon successfull completion, points to -+ *the beginning of the string, points to an undefined value otherwise. -+ * -+ *Parses a string type as defined in css spec [4.1.1]: -+ * -+ *string ::= {string1}|{string2} -+ *string1 ::= \"([\t !#$%&(-~]|\\{nl}|\'|{nonascii}|{escape})*\" -+ *string2 ::= \'([\t !#$%&(-~]|\\{nl}|\"|{nonascii}|{escape})*\' -+ * -+ *Returns CR_OK upon successfull completion, an error code otherwise. -+ */ -+static enum CRStatus -+cr_parser_parse_string (CRParser * a_this, CRString ** a_str) -+{ -+ enum CRStatus status = CR_OK; -+ -+ g_return_val_if_fail (a_this && PRIVATE (a_this) -+ && PRIVATE (a_this)->tknzr -+ && a_str, CR_BAD_PARAM_ERROR); -+ -+ status = cr_tknzr_parse_token (PRIVATE (a_this)->tknzr, -+ STRING_TK, NO_ET, a_str, NULL); -+ return status; -+} -+ -+/** -+ *Parses an "ident" as defined in css spec [4.1.1]: -+ *ident ::= {nmstart}{nmchar}* -+ * -+ *@param a_this the currens instance of #CRParser. -+ * -+ *@param a_str a pointer to parsed ident. If *a_str is NULL, -+ *this function allocates a new instance of #CRString. If not, -+ *the function just appends the parsed string to the one passed. -+ *In both cases it is up to the caller to free *a_str. -+ * -+ *@return CR_OK upon successfull completion, an error code -+ *otherwise. -+ */ -+static enum CRStatus -+cr_parser_parse_ident (CRParser * a_this, CRString ** a_str) -+{ -+ enum CRStatus status = CR_OK; -+ -+ g_return_val_if_fail (a_this && PRIVATE (a_this) -+ && PRIVATE (a_this)->tknzr -+ && a_str, CR_BAD_PARAM_ERROR); -+ -+ status = cr_tknzr_parse_token (PRIVATE (a_this)->tknzr, -+ IDENT_TK, NO_ET, a_str, NULL); -+ return status; -+} -+ -+/** -+ *the next rule is ignored as well. This seems to be a bug -+ *Parses a stylesheet as defined in the css2 spec in appendix D.1: -+ *stylesheet ::= [ CHARSET_SYM S* STRING S* ';' ]? -+ * [S|CDO|CDC]* [ import [S|CDO|CDC]* ]* -+ * [ [ ruleset | media | page | font_face ] [S|CDO|CDC]* ]* -+ * -+ *TODO: Finish the code of this function. Think about splitting it into -+ *smaller functions. -+ * -+ *@param a_this the "this pointer" of the current instance of #CRParser. -+ *@param a_start out parameter. A pointer to the first character of -+ *the successfully parsed string. -+ *@param a_end out parameter. A pointer to the first character of -+ *the successfully parsed string. -+ * -+ *@return CR_OK upon successfull completion, an error code otherwise. -+ */ -+static enum CRStatus -+cr_parser_parse_stylesheet (CRParser * a_this) -+{ -+ enum CRStatus status = CR_OK; -+ CRInputPos init_pos; -+ CRToken *token = NULL; -+ CRString *charset = NULL; -+ -+ g_return_val_if_fail (a_this && PRIVATE (a_this) -+ && PRIVATE (a_this)->tknzr, CR_BAD_PARAM_ERROR); -+ -+ RECORD_INITIAL_POS (a_this, &init_pos); -+ -+ PRIVATE (a_this)->state = READY_STATE; -+ -+ if (PRIVATE (a_this)->sac_handler -+ && PRIVATE (a_this)->sac_handler->start_document) { -+ PRIVATE (a_this)->sac_handler->start_document -+ (PRIVATE (a_this)->sac_handler); -+ } -+ -+ parse_charset: -+ status = cr_tknzr_get_next_token (PRIVATE (a_this)->tknzr, &token); -+ -+ if (status == CR_END_OF_INPUT_ERROR) -+ goto done; -+ CHECK_PARSING_STATUS (status, TRUE); -+ -+ if (token && token->type == CHARSET_SYM_TK) { -+ CRParsingLocation location = {0} ; -+ status = cr_tknzr_unget_token (PRIVATE (a_this)->tknzr, -+ token); -+ CHECK_PARSING_STATUS (status, TRUE); -+ token = NULL; -+ -+ status = cr_parser_parse_charset (a_this, -+ &charset, -+ &location); -+ -+ if (status == CR_OK && charset) { -+ if (PRIVATE (a_this)->sac_handler -+ && PRIVATE (a_this)->sac_handler->charset) { -+ PRIVATE (a_this)->sac_handler->charset -+ (PRIVATE (a_this)->sac_handler, -+ charset, &location); -+ } -+ } else if (status != CR_END_OF_INPUT_ERROR) { -+ status = cr_parser_parse_atrule_core (a_this); -+ CHECK_PARSING_STATUS (status, FALSE); -+ } -+ -+ if (charset) { -+ cr_string_destroy (charset); -+ charset = NULL; -+ } -+ } else if (token -+ && (token->type == S_TK -+ || token->type == COMMENT_TK)) { -+ status = cr_tknzr_unget_token (PRIVATE (a_this)->tknzr, -+ token); -+ token = NULL; -+ CHECK_PARSING_STATUS (status, TRUE); -+ -+ cr_parser_try_to_skip_spaces_and_comments (a_this); -+ goto parse_charset ; -+ } else if (token) { -+ status = cr_tknzr_unget_token (PRIVATE (a_this)->tknzr, -+ token); -+ token = NULL; -+ CHECK_PARSING_STATUS (status, TRUE); -+ } -+ -+/* parse_imports:*/ -+ do { -+ if (token) { -+ cr_token_destroy (token); -+ token = NULL; -+ } -+ cr_parser_try_to_skip_spaces_and_comments (a_this) ; -+ status = cr_tknzr_get_next_token -+ (PRIVATE (a_this)->tknzr, &token); -+ -+ if (status == CR_END_OF_INPUT_ERROR) -+ goto done; -+ CHECK_PARSING_STATUS (status, TRUE); -+ } while (token -+ && (token->type == S_TK -+ || token->type == CDO_TK || token->type == CDC_TK)); -+ -+ if (token) { -+ status = cr_tknzr_unget_token (PRIVATE (a_this)->tknzr, -+ token); -+ token = NULL; -+ } -+ -+ for (;;) { -+ status = cr_tknzr_get_next_token -+ (PRIVATE (a_this)->tknzr, &token); -+ if (status == CR_END_OF_INPUT_ERROR) -+ goto done; -+ CHECK_PARSING_STATUS (status, TRUE); -+ -+ if (token && token->type == IMPORT_SYM_TK) { -+ GList *media_list = NULL; -+ CRString *import_string = NULL; -+ CRParsingLocation location = {0} ; -+ -+ status = cr_tknzr_unget_token -+ (PRIVATE (a_this)->tknzr, token); -+ token = NULL; -+ CHECK_PARSING_STATUS (status, TRUE); -+ -+ status = cr_parser_parse_import (a_this, -+ &media_list, -+ &import_string, -+ &location); -+ if (status == CR_OK) { -+ if (import_string -+ && PRIVATE (a_this)->sac_handler -+ && PRIVATE (a_this)->sac_handler->import_style) { -+ PRIVATE (a_this)->sac_handler->import_style -+ (PRIVATE(a_this)->sac_handler, -+ media_list, -+ import_string, -+ NULL, &location) ; -+ -+ if ((PRIVATE (a_this)->sac_handler->resolve_import == TRUE)) { -+ /* -+ *TODO: resolve the -+ *import rule. -+ */ -+ } -+ -+ if ((PRIVATE (a_this)->sac_handler->import_style_result)) { -+ PRIVATE (a_this)->sac_handler->import_style_result -+ (PRIVATE (a_this)->sac_handler, -+ media_list, import_string, -+ NULL, NULL); -+ } -+ } -+ } else if (status != CR_END_OF_INPUT_ERROR) { -+ if (PRIVATE (a_this)->sac_handler -+ && PRIVATE (a_this)->sac_handler->error) { -+ PRIVATE (a_this)->sac_handler->error -+ (PRIVATE (a_this)->sac_handler); -+ } -+ status = cr_parser_parse_atrule_core (a_this); -+ CHECK_PARSING_STATUS (status, TRUE) ; -+ } else { -+ goto error ; -+ } -+ -+ /* -+ *then, after calling the appropriate -+ *SAC handler, free -+ *the media_list and import_string. -+ */ -+ if (media_list) { -+ GList *cur = NULL; -+ -+ /*free the medium list */ -+ for (cur = media_list; cur; cur = cur->next) { -+ if (cur->data) { -+ cr_string_destroy (cur->data); -+ } -+ } -+ -+ g_list_free (media_list); -+ media_list = NULL; -+ } -+ -+ if (import_string) { -+ cr_string_destroy (import_string); -+ import_string = NULL; -+ } -+ -+ cr_parser_try_to_skip_spaces_and_comments (a_this); -+ } else if (token -+ && (token->type == S_TK -+ || token->type == CDO_TK -+ || token->type == CDC_TK)) { -+ status = cr_tknzr_unget_token -+ (PRIVATE (a_this)->tknzr, token); -+ token = NULL; -+ -+ do { -+ if (token) { -+ cr_token_destroy (token); -+ token = NULL; -+ } -+ -+ status = cr_tknzr_get_next_token -+ (PRIVATE (a_this)->tknzr, &token); -+ -+ if (status == CR_END_OF_INPUT_ERROR) -+ goto done; -+ CHECK_PARSING_STATUS (status, TRUE); -+ } while (token -+ && (token->type == S_TK -+ || token->type == CDO_TK -+ || token->type == CDC_TK)); -+ } else { -+ if (token) { -+ status = cr_tknzr_unget_token -+ (PRIVATE (a_this)->tknzr, token); -+ token = NULL; -+ } -+ goto parse_ruleset_and_others; -+ } -+ } -+ -+ parse_ruleset_and_others: -+ -+ cr_parser_try_to_skip_spaces_and_comments (a_this); -+ -+ for (;;) { -+ status = cr_tknzr_get_next_token -+ (PRIVATE (a_this)->tknzr, &token); -+ if (status == CR_END_OF_INPUT_ERROR) -+ goto done; -+ CHECK_PARSING_STATUS (status, TRUE); -+ -+ if (token -+ && (token->type == S_TK -+ || token->type == CDO_TK || token->type == CDC_TK)) { -+ status = cr_tknzr_unget_token -+ (PRIVATE (a_this)->tknzr, token); -+ token = NULL; -+ -+ do { -+ if (token) { -+ cr_token_destroy (token); -+ token = NULL; -+ } -+ -+ cr_parser_try_to_skip_spaces_and_comments -+ (a_this); -+ status = cr_tknzr_get_next_token -+ (PRIVATE (a_this)->tknzr, &token); -+ } while (token -+ && (token->type == S_TK -+ || token->type == COMMENT_TK -+ || token->type == CDO_TK -+ || token->type == CDC_TK)); -+ if (token) { -+ cr_tknzr_unget_token -+ (PRIVATE (a_this)->tknzr, token); -+ token = NULL; -+ } -+ } else if (token -+ && (token->type == HASH_TK -+ || (token->type == DELIM_TK -+ && token->u.unichar == '.') -+ || (token->type == DELIM_TK -+ && token->u.unichar == ':') -+ || (token->type == DELIM_TK -+ && token->u.unichar == '*') -+ || (token->type == BO_TK) -+ || token->type == IDENT_TK)) { -+ /* -+ *Try to parse a CSS2 ruleset. -+ *if the parsing fails, try to parse -+ *a css core ruleset. -+ */ -+ status = cr_tknzr_unget_token -+ (PRIVATE (a_this)->tknzr, token); -+ CHECK_PARSING_STATUS (status, TRUE); -+ token = NULL; -+ -+ status = cr_parser_parse_ruleset (a_this); -+ -+ if (status == CR_OK) { -+ continue; -+ } else { -+ if (PRIVATE (a_this)->sac_handler -+ && PRIVATE (a_this)->sac_handler->error) { -+ PRIVATE (a_this)->sac_handler-> -+ error -+ (PRIVATE (a_this)-> -+ sac_handler); -+ } -+ -+ status = cr_parser_parse_ruleset_core -+ (a_this); -+ -+ if (status == CR_OK) { -+ continue; -+ } else { -+ break; -+ } -+ } -+ } else if (token && token->type == MEDIA_SYM_TK) { -+ status = cr_tknzr_unget_token -+ (PRIVATE (a_this)->tknzr, token); -+ CHECK_PARSING_STATUS (status, TRUE); -+ token = NULL; -+ -+ status = cr_parser_parse_media (a_this); -+ if (status == CR_OK) { -+ continue; -+ } else { -+ if (PRIVATE (a_this)->sac_handler -+ && PRIVATE (a_this)->sac_handler->error) { -+ PRIVATE (a_this)->sac_handler-> -+ error -+ (PRIVATE (a_this)-> -+ sac_handler); -+ } -+ -+ status = cr_parser_parse_atrule_core (a_this); -+ -+ if (status == CR_OK) { -+ continue; -+ } else { -+ break; -+ } -+ } -+ -+ } else if (token && token->type == PAGE_SYM_TK) { -+ status = cr_tknzr_unget_token -+ (PRIVATE (a_this)->tknzr, token); -+ CHECK_PARSING_STATUS (status, TRUE); -+ token = NULL; -+ status = cr_parser_parse_page (a_this); -+ -+ if (status == CR_OK) { -+ continue; -+ } else { -+ if (PRIVATE (a_this)->sac_handler -+ && PRIVATE (a_this)->sac_handler->error) { -+ PRIVATE (a_this)->sac_handler-> -+ error -+ (PRIVATE (a_this)-> -+ sac_handler); -+ } -+ -+ status = cr_parser_parse_atrule_core (a_this); -+ -+ if (status == CR_OK) { -+ continue; -+ } else { -+ break; -+ } -+ } -+ } else if (token && token->type == FONT_FACE_SYM_TK) { -+ status = cr_tknzr_unget_token -+ (PRIVATE (a_this)->tknzr, token); -+ CHECK_PARSING_STATUS (status, TRUE); -+ token = NULL; -+ status = cr_parser_parse_font_face (a_this); -+ -+ if (status == CR_OK) { -+ continue; -+ } else { -+ if (PRIVATE (a_this)->sac_handler -+ && PRIVATE (a_this)->sac_handler->error) { -+ PRIVATE (a_this)->sac_handler-> -+ error -+ (PRIVATE (a_this)-> -+ sac_handler); -+ } -+ -+ status = cr_parser_parse_atrule_core (a_this); -+ -+ if (status == CR_OK) { -+ continue; -+ } else { -+ break; -+ } -+ } -+ } else { -+ status = cr_tknzr_unget_token -+ (PRIVATE (a_this)->tknzr, token); -+ CHECK_PARSING_STATUS (status, TRUE); -+ token = NULL; -+ status = cr_parser_parse_statement_core (a_this); -+ -+ if (status == CR_OK) { -+ continue; -+ } else { -+ break; -+ } -+ } -+ } -+ -+ done: -+ if (token) { -+ cr_token_destroy (token); -+ token = NULL; -+ } -+ -+ if (status == CR_END_OF_INPUT_ERROR || status == CR_OK) { -+ -+ if (PRIVATE (a_this)->sac_handler -+ && PRIVATE (a_this)->sac_handler->end_document) { -+ PRIVATE (a_this)->sac_handler->end_document -+ (PRIVATE (a_this)->sac_handler); -+ } -+ -+ return CR_OK; -+ } -+ -+ cr_parser_push_error -+ (a_this, (const guchar *) "could not recognize next production", CR_ERROR); -+ -+ if (PRIVATE (a_this)->sac_handler -+ && PRIVATE (a_this)->sac_handler->unrecoverable_error) { -+ PRIVATE (a_this)->sac_handler-> -+ unrecoverable_error (PRIVATE (a_this)->sac_handler); -+ } -+ -+ cr_parser_dump_err_stack (a_this, TRUE); -+ -+ return status; -+ -+ error: -+ -+ if (token) { -+ cr_token_destroy (token); -+ token = NULL; -+ } -+ -+ if (PRIVATE (a_this)->sac_handler -+ && PRIVATE (a_this)->sac_handler->unrecoverable_error) { -+ PRIVATE (a_this)->sac_handler-> -+ unrecoverable_error (PRIVATE (a_this)->sac_handler); -+ } -+ -+ cr_tknzr_set_cur_pos (PRIVATE (a_this)->tknzr, &init_pos); -+ -+ return status; -+} -+ -+/**************************************** -+ *Public CRParser Methods -+ ****************************************/ -+ -+/** -+ * cr_parser_new: -+ * @a_tknzr: the tokenizer to use for the parsing. -+ * -+ *Creates a new parser to parse data -+ *coming the input stream given in parameter. -+ * -+ *Returns the newly created instance of #CRParser, -+ *or NULL if an error occurred. -+ */ -+CRParser * -+cr_parser_new (CRTknzr * a_tknzr) -+{ -+ CRParser *result = NULL; -+ enum CRStatus status = CR_OK; -+ -+ result = g_malloc0 (sizeof (CRParser)); -+ -+ PRIVATE (result) = g_malloc0 (sizeof (CRParserPriv)); -+ -+ if (a_tknzr) { -+ status = cr_parser_set_tknzr (result, a_tknzr); -+ } -+ -+ g_return_val_if_fail (status == CR_OK, NULL); -+ -+ return result; -+} -+ -+/** -+ * cr_parser_new_from_buf: -+ *@a_buf: the buffer to parse. -+ *@a_len: the length of the data in the buffer. -+ *@a_enc: the encoding of the input buffer a_buf. -+ *@a_free_buf: if set to TRUE, a_buf will be freed -+ *during the destruction of the newly built instance -+ *of #CRParser. If set to FALSE, it is up to the caller to -+ *eventually free it. -+ * -+ *Instanciates a new parser from a memory buffer. -+ * -+ *Returns the newly built parser, or NULL if an error arises. -+ */ -+CRParser * -+cr_parser_new_from_buf (guchar * a_buf, -+ gulong a_len, -+ enum CREncoding a_enc, -+ gboolean a_free_buf) -+{ -+ CRParser *result = NULL; -+ CRInput *input = NULL; -+ -+ g_return_val_if_fail (a_buf && a_len, NULL); -+ -+ input = cr_input_new_from_buf (a_buf, a_len, a_enc, a_free_buf); -+ g_return_val_if_fail (input, NULL); -+ -+ result = cr_parser_new_from_input (input); -+ if (!result) { -+ cr_input_destroy (input); -+ input = NULL; -+ return NULL; -+ } -+ return result; -+} -+ -+/** -+ * cr_parser_new_from_input: -+ * @a_input: the parser input stream to use. -+ * -+ * Returns a newly built parser input. -+ */ -+CRParser * -+cr_parser_new_from_input (CRInput * a_input) -+{ -+ CRParser *result = NULL; -+ CRTknzr *tokenizer = NULL; -+ -+ if (a_input) { -+ tokenizer = cr_tknzr_new (a_input); -+ g_return_val_if_fail (tokenizer, NULL); -+ } -+ -+ result = cr_parser_new (tokenizer); -+ g_return_val_if_fail (result, NULL); -+ -+ return result; -+} -+ -+/** -+ * cr_parser_new_from_file: -+ * @a_file_uri: the uri of the file to parse. -+ * @a_enc: the file encoding to use. -+ * -+ * Returns the newly built parser. -+ */ -+CRParser * -+cr_parser_new_from_file (const guchar * a_file_uri, enum CREncoding a_enc) -+{ -+ CRParser *result = NULL; -+ CRTknzr *tokenizer = NULL; -+ -+ tokenizer = cr_tknzr_new_from_uri (a_file_uri, a_enc); -+ if (!tokenizer) { -+ cr_utils_trace_info ("Could not open input file"); -+ return NULL; -+ } -+ -+ result = cr_parser_new (tokenizer); -+ g_return_val_if_fail (result, NULL); -+ return result; -+} -+ -+/** -+ * cr_parser_set_sac_handler: -+ *@a_this: the "this pointer" of the current instance of #CRParser. -+ *@a_handler: the handler to set. -+ * -+ *Sets a SAC document handler to the parser. -+ * -+ *Returns CR_OK upon successfull completion, an error code otherwise. -+ */ -+enum CRStatus -+cr_parser_set_sac_handler (CRParser * a_this, CRDocHandler * a_handler) -+{ -+ g_return_val_if_fail (a_this, CR_BAD_PARAM_ERROR); -+ -+ if (PRIVATE (a_this)->sac_handler) { -+ cr_doc_handler_unref (PRIVATE (a_this)->sac_handler); -+ } -+ -+ PRIVATE (a_this)->sac_handler = a_handler; -+ cr_doc_handler_ref (a_handler); -+ -+ return CR_OK; -+} -+ -+/** -+ * cr_parser_get_sac_handler: -+ *@a_this: the "this pointer" of the current instance of -+ *#CRParser. -+ *@a_handler: out parameter. The returned handler. -+ * -+ *Gets the SAC document handler. -+ * -+ *Returns CR_OK upon successfull completion, an error code -+ *otherwise. -+ */ -+enum CRStatus -+cr_parser_get_sac_handler (CRParser * a_this, CRDocHandler ** a_handler) -+{ -+ g_return_val_if_fail (a_this, CR_BAD_PARAM_ERROR); -+ -+ *a_handler = PRIVATE (a_this)->sac_handler; -+ -+ return CR_OK; -+} -+ -+/** -+ * cr_parser_set_default_sac_handler: -+ *@a_this: a pointer to the current instance of #CRParser. -+ * -+ *Sets the SAC handler associated to the current instance -+ *of #CRParser to the default SAC handler. -+ * -+ *Returns CR_OK upon successfull completion, an error code otherwise. -+ */ -+enum CRStatus -+cr_parser_set_default_sac_handler (CRParser * a_this) -+{ -+ CRDocHandler *default_sac_handler = NULL; -+ enum CRStatus status = CR_ERROR; -+ -+ g_return_val_if_fail (a_this && PRIVATE (a_this), CR_BAD_PARAM_ERROR); -+ -+ default_sac_handler = cr_doc_handler_new (); -+ -+ cr_doc_handler_set_default_sac_handler (default_sac_handler); -+ -+ status = cr_parser_set_sac_handler (a_this, default_sac_handler); -+ -+ if (status != CR_OK) { -+ cr_doc_handler_destroy (default_sac_handler); -+ default_sac_handler = NULL; -+ } -+ -+ return status; -+} -+ -+/** -+ * cr_parser_set_use_core_grammar: -+ * @a_this: the current instance of #CRParser. -+ * @a_use_core_grammar: where to parse against the css core grammar. -+ * -+ * Returns CR_OK upon succesful completion, an error code otherwise. -+ */ -+enum CRStatus -+cr_parser_set_use_core_grammar (CRParser * a_this, -+ gboolean a_use_core_grammar) -+{ -+ g_return_val_if_fail (a_this && PRIVATE (a_this), CR_BAD_PARAM_ERROR); -+ -+ PRIVATE (a_this)->use_core_grammar = a_use_core_grammar; -+ -+ return CR_OK; -+} -+ -+/** -+ * cr_parser_get_use_core_grammar: -+ * @a_this: the current instance of #CRParser. -+ * @a_use_core_grammar: wether to use the core grammar or not. -+ * -+ * Returns CR_OK upon succesful completion, an error code otherwise. -+ */ -+enum CRStatus -+cr_parser_get_use_core_grammar (CRParser const * a_this, -+ gboolean * a_use_core_grammar) -+{ -+ g_return_val_if_fail (a_this && PRIVATE (a_this), CR_BAD_PARAM_ERROR); -+ -+ *a_use_core_grammar = PRIVATE (a_this)->use_core_grammar; -+ -+ return CR_OK; -+} -+ -+/** -+ * cr_parser_parse_file: -+ *@a_this: a pointer to the current instance of #CRParser. -+ *@a_file_uri: the uri to the file to load. For the time being, -+ *@a_enc: the encoding of the file to parse. -+ *only local files are supported. -+ * -+ *Parses a the given in parameter. -+ * -+ *Returns CR_OK upon successfull completion, an error code otherwise. -+ */ -+enum CRStatus -+cr_parser_parse_file (CRParser * a_this, -+ const guchar * a_file_uri, enum CREncoding a_enc) -+{ -+ enum CRStatus status = CR_ERROR; -+ CRTknzr *tknzr = NULL; -+ -+ g_return_val_if_fail (a_this && PRIVATE (a_this) -+ && a_file_uri, CR_BAD_PARAM_ERROR); -+ -+ tknzr = cr_tknzr_new_from_uri (a_file_uri, a_enc); -+ -+ g_return_val_if_fail (tknzr != NULL, CR_ERROR); -+ -+ status = cr_parser_set_tknzr (a_this, tknzr); -+ g_return_val_if_fail (status == CR_OK, CR_ERROR); -+ -+ status = cr_parser_parse (a_this); -+ -+ return status; -+} -+ -+/** -+ * cr_parser_parse_expr: -+ * @a_this: the current instance of #CRParser. -+ * @a_expr: out parameter. the parsed expression. -+ * -+ *Parses an expression as defined by the css2 spec in appendix -+ *D.1: -+ *expr: term [ operator term ]* -+ * -+ * -+ * Returns CR_OK upon successful completion, an error code otherwise. -+ */ -+enum CRStatus -+cr_parser_parse_expr (CRParser * a_this, CRTerm ** a_expr) -+{ -+ enum CRStatus status = CR_ERROR; -+ CRInputPos init_pos; -+ CRTerm *expr = NULL, -+ *expr2 = NULL; -+ guchar next_byte = 0; -+ gulong nb_terms = 0; -+ -+ g_return_val_if_fail (a_this && PRIVATE (a_this) -+ && a_expr, CR_BAD_PARAM_ERROR); -+ -+ RECORD_INITIAL_POS (a_this, &init_pos); -+ -+ status = cr_parser_parse_term (a_this, &expr); -+ -+ CHECK_PARSING_STATUS (status, FALSE); -+ -+ for (;;) { -+ guchar operator = 0; -+ -+ status = cr_tknzr_peek_byte (PRIVATE (a_this)->tknzr, -+ 1, &next_byte); -+ if (status != CR_OK) { -+ if (status == CR_END_OF_INPUT_ERROR) { -+ /* -+ if (!nb_terms) -+ { -+ goto error ; -+ } -+ */ -+ status = CR_OK; -+ break; -+ } else { -+ goto error; -+ } -+ } -+ -+ if (next_byte == '/' || next_byte == ',') { -+ READ_NEXT_BYTE (a_this, &operator); -+ } -+ -+ cr_parser_try_to_skip_spaces_and_comments (a_this); -+ -+ status = cr_parser_parse_term (a_this, &expr2); -+ -+ if (status != CR_OK || expr2 == NULL) { -+ status = CR_OK; -+ break; -+ } -+ -+ switch (operator) { -+ case '/': -+ expr2->the_operator = DIVIDE; -+ break; -+ case ',': -+ expr2->the_operator = COMMA; -+ -+ default: -+ break; -+ } -+ -+ expr = cr_term_append_term (expr, expr2); -+ expr2 = NULL; -+ operator = 0; -+ nb_terms++; -+ } -+ -+ if (status == CR_OK) { -+ *a_expr = cr_term_append_term (*a_expr, expr); -+ expr = NULL; -+ -+ cr_parser_clear_errors (a_this); -+ return CR_OK; -+ } -+ -+ error: -+ -+ if (expr) { -+ cr_term_destroy (expr); -+ expr = NULL; -+ } -+ -+ if (expr2) { -+ cr_term_destroy (expr2); -+ expr2 = NULL; -+ } -+ -+ cr_tknzr_set_cur_pos (PRIVATE (a_this)->tknzr, &init_pos); -+ -+ return status; -+} -+ -+/** -+ * cr_parser_parse_prio: -+ *@a_this: the current instance of #CRParser. -+ *@a_prio: a string representing the priority. -+ *Today, only "!important" is returned as only this -+ *priority is defined by css2. -+ * -+ *Parses a declaration priority as defined by -+ *the css2 grammar in appendix C: -+ *prio: IMPORTANT_SYM S* -+ * -+ * Returns CR_OK upon successful completion, an error code otherwise. -+ */ -+enum CRStatus -+cr_parser_parse_prio (CRParser * a_this, CRString ** a_prio) -+{ -+ enum CRStatus status = CR_ERROR; -+ CRInputPos init_pos; -+ CRToken *token = NULL; -+ -+ g_return_val_if_fail (a_this && PRIVATE (a_this) -+ && a_prio -+ && *a_prio == NULL, CR_BAD_PARAM_ERROR); -+ -+ RECORD_INITIAL_POS (a_this, &init_pos); -+ -+ status = cr_tknzr_get_next_token (PRIVATE (a_this)->tknzr, &token); -+ if (status == CR_END_OF_INPUT_ERROR) { -+ goto error; -+ } -+ ENSURE_PARSING_COND (status == CR_OK -+ && token && token->type == IMPORTANT_SYM_TK); -+ -+ cr_parser_try_to_skip_spaces_and_comments (a_this); -+ *a_prio = cr_string_new_from_string ("!important"); -+ cr_token_destroy (token); -+ token = NULL; -+ return CR_OK; -+ -+ error: -+ if (token) { -+ cr_token_destroy (token); -+ token = NULL; -+ } -+ cr_tknzr_set_cur_pos (PRIVATE (a_this)->tknzr, &init_pos); -+ -+ return status; -+} -+ -+/** -+ * cr_parser_parse_declaration: -+ *@a_this: the "this pointer" of the current instance of #CRParser. -+ *@a_property: the successfully parsed property. The caller -+ * *must* free the returned pointer. -+ *@a_expr: the expression that represents the attribute value. -+ *The caller *must* free the returned pointer. -+ * -+ *TODO: return the parsed priority, so that -+ *upper layers can take benefit from it. -+ *Parses a "declaration" as defined by the css2 spec in appendix D.1: -+ *declaration ::= [property ':' S* expr prio?]? -+ * -+ *Returns CR_OK upon successfull completion, an error code otherwise. -+ */ -+enum CRStatus -+cr_parser_parse_declaration (CRParser * a_this, -+ CRString ** a_property, -+ CRTerm ** a_expr, gboolean * a_important) -+{ -+ enum CRStatus status = CR_ERROR; -+ CRInputPos init_pos; -+ guint32 cur_char = 0; -+ CRTerm *expr = NULL; -+ CRString *prio = NULL; -+ -+ g_return_val_if_fail (a_this && PRIVATE (a_this) -+ && a_property && a_expr -+ && a_important, CR_BAD_PARAM_ERROR); -+ -+ RECORD_INITIAL_POS (a_this, &init_pos); -+ -+ status = cr_parser_parse_property (a_this, a_property); -+ -+ if (status == CR_END_OF_INPUT_ERROR) -+ goto error; -+ -+ CHECK_PARSING_STATUS_ERR -+ (a_this, status, FALSE, -+ (const guchar *) "while parsing declaration: next property is malformed", -+ CR_SYNTAX_ERROR); -+ -+ READ_NEXT_CHAR (a_this, &cur_char); -+ -+ if (cur_char != ':') { -+ status = CR_PARSING_ERROR; -+ cr_parser_push_error -+ (a_this, -+ (const guchar *) "while parsing declaration: this char must be ':'", -+ CR_SYNTAX_ERROR); -+ goto error; -+ } -+ -+ cr_parser_try_to_skip_spaces_and_comments (a_this); -+ -+ status = cr_parser_parse_expr (a_this, &expr); -+ -+ CHECK_PARSING_STATUS_ERR -+ (a_this, status, FALSE, -+ (const guchar *) "while parsing declaration: next expression is malformed", -+ CR_SYNTAX_ERROR); -+ -+ cr_parser_try_to_skip_spaces_and_comments (a_this); -+ status = cr_parser_parse_prio (a_this, &prio); -+ if (prio) { -+ cr_string_destroy (prio); -+ prio = NULL; -+ *a_important = TRUE; -+ } else { -+ *a_important = FALSE; -+ } -+ if (*a_expr) { -+ cr_term_append_term (*a_expr, expr); -+ expr = NULL; -+ } else { -+ *a_expr = expr; -+ expr = NULL; -+ } -+ -+ cr_parser_clear_errors (a_this); -+ return CR_OK; -+ -+ error: -+ -+ if (expr) { -+ cr_term_destroy (expr); -+ expr = NULL; -+ } -+ -+ if (*a_property) { -+ cr_string_destroy (*a_property); -+ *a_property = NULL; -+ } -+ -+ cr_tknzr_set_cur_pos (PRIVATE (a_this)->tknzr, &init_pos); -+ -+ return status; -+} -+ -+/** -+ * cr_parser_parse_statement_core: -+ *@a_this: the current instance of #CRParser. -+ * -+ *Parses a statement as defined by the css core grammar in -+ *chapter 4.1 of the css2 spec. -+ *statement : ruleset | at-rule; -+ * -+ *Returns CR_OK upon successfull completion, an error code otherwise. -+ */ -+enum CRStatus -+cr_parser_parse_statement_core (CRParser * a_this) -+{ -+ CRToken *token = NULL; -+ CRInputPos init_pos; -+ enum CRStatus status = CR_ERROR; -+ -+ g_return_val_if_fail (a_this && PRIVATE (a_this), CR_BAD_PARAM_ERROR); -+ -+ RECORD_INITIAL_POS (a_this, &init_pos); -+ -+ status = cr_tknzr_get_next_token (PRIVATE (a_this)->tknzr, &token); -+ -+ ENSURE_PARSING_COND (status == CR_OK && token); -+ -+ switch (token->type) { -+ case ATKEYWORD_TK: -+ case IMPORT_SYM_TK: -+ case PAGE_SYM_TK: -+ case MEDIA_SYM_TK: -+ case FONT_FACE_SYM_TK: -+ case CHARSET_SYM_TK: -+ cr_tknzr_unget_token (PRIVATE (a_this)->tknzr, token); -+ token = NULL; -+ status = cr_parser_parse_atrule_core (a_this); -+ CHECK_PARSING_STATUS (status, TRUE); -+ break; -+ -+ default: -+ cr_tknzr_unget_token (PRIVATE (a_this)->tknzr, token); -+ token = NULL; -+ status = cr_parser_parse_ruleset_core (a_this); -+ cr_parser_clear_errors (a_this); -+ CHECK_PARSING_STATUS (status, TRUE); -+ } -+ -+ return CR_OK; -+ -+ error: -+ if (token) { -+ cr_token_destroy (token); -+ token = NULL; -+ } -+ -+ cr_tknzr_set_cur_pos (PRIVATE (a_this)->tknzr, &init_pos); -+ -+ return status; -+} -+ -+/** -+ * cr_parser_parse_ruleset: -+ *@a_this: the "this pointer" of the current instance of #CRParser. -+ * -+ *Parses a "ruleset" as defined in the css2 spec at appendix D.1. -+ *ruleset ::= selector [ ',' S* selector ]* -+ *'{' S* declaration? [ ';' S* declaration? ]* '}' S*; -+ * -+ *This methods calls the the SAC handler on the relevant SAC handler -+ *callbacks whenever it encounters some specific constructions. -+ *See the documentation of #CRDocHandler (the SAC handler) to know -+ *when which SAC handler is called. -+ * -+ *Returns CR_OK upon successfull completion, an error code otherwise. -+ */ -+enum CRStatus -+cr_parser_parse_ruleset (CRParser * a_this) -+{ -+ enum CRStatus status = CR_OK; -+ CRInputPos init_pos; -+ guint32 cur_char = 0, -+ next_char = 0; -+ CRString *property = NULL; -+ CRTerm *expr = NULL; -+ CRSimpleSel *simple_sels = NULL; -+ CRSelector *selector = NULL; -+ gboolean start_selector = FALSE, -+ is_important = FALSE; -+ CRParsingLocation end_parsing_location; -+ -+ g_return_val_if_fail (a_this, CR_BAD_PARAM_ERROR); -+ -+ RECORD_INITIAL_POS (a_this, &init_pos); -+ -+ status = cr_parser_parse_selector (a_this, &selector); -+ CHECK_PARSING_STATUS (status, FALSE); -+ -+ READ_NEXT_CHAR (a_this, &cur_char); -+ -+ ENSURE_PARSING_COND_ERR -+ (a_this, cur_char == '{', -+ (const guchar *) "while parsing rulset: current char should be '{'", -+ CR_SYNTAX_ERROR); -+ -+ if (PRIVATE (a_this)->sac_handler -+ && PRIVATE (a_this)->sac_handler->start_selector) { -+ /* -+ *the selector is ref counted so that the parser's user -+ *can choose to keep it. -+ */ -+ if (selector) { -+ cr_selector_ref (selector); -+ } -+ -+ PRIVATE (a_this)->sac_handler->start_selector -+ (PRIVATE (a_this)->sac_handler, selector); -+ start_selector = TRUE; -+ } -+ -+ cr_parser_try_to_skip_spaces_and_comments (a_this); -+ -+ PRIVATE (a_this)->state = TRY_PARSE_RULESET_STATE; -+ -+ status = cr_parser_parse_declaration (a_this, &property, -+ &expr, -+ &is_important); -+ if (expr) { -+ cr_term_ref (expr); -+ } -+ if (status == CR_OK -+ && PRIVATE (a_this)->sac_handler -+ && PRIVATE (a_this)->sac_handler->property) { -+ PRIVATE (a_this)->sac_handler->property -+ (PRIVATE (a_this)->sac_handler, property, expr, -+ is_important); -+ } -+ if (status == CR_OK) { -+ /* -+ *free the allocated -+ *'property' and 'term' before parsing -+ *next declarations. -+ */ -+ if (property) { -+ cr_string_destroy (property); -+ property = NULL; -+ } -+ if (expr) { -+ cr_term_unref (expr); -+ expr = NULL; -+ } -+ } else {/*status != CR_OK*/ -+ guint32 c = 0 ; -+ /* -+ *test if we have reached '}', which -+ *would mean that we are parsing an empty ruleset (eg. x{ }) -+ *In that case, goto end_of_ruleset. -+ */ -+ status = cr_tknzr_peek_char (PRIVATE (a_this)->tknzr, &c) ; -+ if (status == CR_OK && c == '}') { -+ status = CR_OK ; -+ goto end_of_ruleset ; -+ } -+ } -+ CHECK_PARSING_STATUS_ERR -+ (a_this, status, FALSE, -+ (const guchar *) "while parsing ruleset: next construction should be a declaration", -+ CR_SYNTAX_ERROR); -+ -+ for (;;) { -+ PEEK_NEXT_CHAR (a_this, &next_char); -+ if (next_char != ';') -+ break; -+ -+ /*consume the ';' char */ -+ READ_NEXT_CHAR (a_this, &cur_char); -+ -+ cr_parser_try_to_skip_spaces_and_comments (a_this); -+ -+ status = cr_parser_parse_declaration (a_this, &property, -+ &expr, &is_important); -+ -+ if (expr) { -+ cr_term_ref (expr); -+ } -+ if (status == CR_OK -+ && PRIVATE (a_this)->sac_handler -+ && PRIVATE (a_this)->sac_handler->property) { -+ PRIVATE (a_this)->sac_handler->property -+ (PRIVATE (a_this)->sac_handler, -+ property, expr, is_important); -+ } -+ if (property) { -+ cr_string_destroy (property); -+ property = NULL; -+ } -+ if (expr) { -+ cr_term_unref (expr); -+ expr = NULL; -+ } -+ } -+ -+ end_of_ruleset: -+ cr_parser_try_to_skip_spaces_and_comments (a_this); -+ cr_parser_get_parsing_location (a_this, &end_parsing_location); -+ READ_NEXT_CHAR (a_this, &cur_char); -+ ENSURE_PARSING_COND_ERR -+ (a_this, cur_char == '}', -+ (const guchar *) "while parsing rulset: current char must be a '}'", -+ CR_SYNTAX_ERROR); -+ -+ selector->location = end_parsing_location; -+ if (PRIVATE (a_this)->sac_handler -+ && PRIVATE (a_this)->sac_handler->end_selector) { -+ PRIVATE (a_this)->sac_handler->end_selector -+ (PRIVATE (a_this)->sac_handler, selector); -+ start_selector = FALSE; -+ } -+ -+ if (expr) { -+ cr_term_unref (expr); -+ expr = NULL; -+ } -+ -+ if (simple_sels) { -+ cr_simple_sel_destroy (simple_sels); -+ simple_sels = NULL; -+ } -+ -+ if (selector) { -+ cr_selector_unref (selector); -+ selector = NULL; -+ } -+ -+ cr_parser_clear_errors (a_this); -+ PRIVATE (a_this)->state = RULESET_PARSED_STATE; -+ -+ return CR_OK; -+ -+ error: -+ if (start_selector == TRUE -+ && PRIVATE (a_this)->sac_handler -+ && PRIVATE (a_this)->sac_handler->error) { -+ PRIVATE (a_this)->sac_handler->error -+ (PRIVATE (a_this)->sac_handler); -+ } -+ if (expr) { -+ cr_term_unref (expr); -+ expr = NULL; -+ } -+ if (simple_sels) { -+ cr_simple_sel_destroy (simple_sels); -+ simple_sels = NULL; -+ } -+ if (property) { -+ cr_string_destroy (property); -+ } -+ if (selector) { -+ cr_selector_unref (selector); -+ selector = NULL; -+ } -+ -+ cr_tknzr_set_cur_pos (PRIVATE (a_this)->tknzr, &init_pos); -+ -+ return status; -+} -+ -+/** -+ * cr_parser_parse_import: -+ *@a_this: the "this pointer" of the current instance -+ *of #CRParser. -+ *@a_media_list: out parameter. A linked list of -+ *#CRString -+ *Each CRString is a string that contains -+ *a 'medium' declaration part of the successfully -+ *parsed 'import' declaration. -+ *@a_import_string: out parameter. -+ *A string that contains the 'import -+ *string". The import string can be either an uri (if it starts with -+ *the substring "uri(") or a any other css2 string. Note that -+ * *a_import_string must be initially set to NULL or else, this function -+ *will return CR_BAD_PARAM_ERROR. -+ *@a_location: the location (line, column) where the import has been parsed -+ * -+ *Parses an 'import' declaration as defined in the css2 spec -+ *in appendix D.1: -+ * -+ *import ::= -+ *\@import [STRING|URI] S* [ medium [ ',' S* medium]* ]? ';' S* -+ * -+ *Returns CR_OK upon sucessfull completion, an error code otherwise. -+ */ -+enum CRStatus -+cr_parser_parse_import (CRParser * a_this, -+ GList ** a_media_list, -+ CRString ** a_import_string, -+ CRParsingLocation *a_location) -+{ -+ enum CRStatus status = CR_OK; -+ CRInputPos init_pos; -+ guint32 cur_char = 0, -+ next_char = 0; -+ CRString *medium = NULL; -+ -+ g_return_val_if_fail (a_this -+ && a_import_string -+ && (*a_import_string == NULL), -+ CR_BAD_PARAM_ERROR); -+ -+ RECORD_INITIAL_POS (a_this, &init_pos); -+ -+ if (BYTE (a_this, 1, NULL) == '@' -+ && BYTE (a_this, 2, NULL) == 'i' -+ && BYTE (a_this, 3, NULL) == 'm' -+ && BYTE (a_this, 4, NULL) == 'p' -+ && BYTE (a_this, 5, NULL) == 'o' -+ && BYTE (a_this, 6, NULL) == 'r' -+ && BYTE (a_this, 7, NULL) == 't') { -+ SKIP_CHARS (a_this, 1); -+ if (a_location) { -+ cr_parser_get_parsing_location -+ (a_this, a_location) ; -+ } -+ SKIP_CHARS (a_this, 6); -+ status = CR_OK; -+ } else { -+ status = CR_PARSING_ERROR; -+ goto error; -+ } -+ -+ cr_parser_try_to_skip_spaces_and_comments (a_this); -+ -+ PRIVATE (a_this)->state = TRY_PARSE_IMPORT_STATE; -+ -+ PEEK_NEXT_CHAR (a_this, &next_char); -+ -+ if (next_char == '"' || next_char == '\'') { -+ status = cr_parser_parse_string (a_this, a_import_string); -+ -+ CHECK_PARSING_STATUS (status, FALSE); -+ } else { -+ status = cr_parser_parse_uri (a_this, a_import_string); -+ -+ CHECK_PARSING_STATUS (status, FALSE); -+ } -+ -+ cr_parser_try_to_skip_spaces_and_comments (a_this); -+ -+ status = cr_parser_parse_ident (a_this, &medium); -+ -+ if (status == CR_OK && medium) { -+ *a_media_list = g_list_append (*a_media_list, medium); -+ medium = NULL; -+ } -+ -+ cr_parser_try_to_skip_spaces_and_comments (a_this); -+ -+ for (; status == CR_OK;) { -+ if ((status = cr_tknzr_peek_char (PRIVATE (a_this)->tknzr, -+ &next_char)) != CR_OK) { -+ if (status == CR_END_OF_INPUT_ERROR) { -+ status = CR_OK; -+ goto okay; -+ } -+ goto error; -+ } -+ -+ if (next_char == ',') { -+ READ_NEXT_CHAR (a_this, &cur_char); -+ } else { -+ break; -+ } -+ -+ cr_parser_try_to_skip_spaces_and_comments (a_this); -+ -+ status = cr_parser_parse_ident (a_this, &medium); -+ -+ cr_parser_try_to_skip_spaces_and_comments (a_this); -+ -+ if ((status == CR_OK) && medium) { -+ *a_media_list = g_list_append (*a_media_list, medium); -+ -+ medium = NULL; -+ } -+ -+ CHECK_PARSING_STATUS (status, FALSE); -+ cr_parser_try_to_skip_spaces_and_comments (a_this); -+ } -+ cr_parser_try_to_skip_spaces_and_comments (a_this); -+ READ_NEXT_CHAR (a_this, &cur_char); -+ ENSURE_PARSING_COND (cur_char == ';'); -+ cr_parser_try_to_skip_spaces_and_comments (a_this); -+ okay: -+ cr_parser_clear_errors (a_this); -+ PRIVATE (a_this)->state = IMPORT_PARSED_STATE; -+ -+ return CR_OK; -+ -+ error: -+ -+ if (*a_media_list) { -+ GList *cur = NULL; -+ -+ /* -+ *free each element of *a_media_list. -+ *Note that each element of *a_medium list *must* -+ *be a GString* or else, the code that is coming next -+ *will corrupt the memory and lead to hard to debug -+ *random crashes. -+ *This is where C++ and its compile time -+ *type checking mecanism (through STL containers) would -+ *have prevented us to go through this hassle. -+ */ -+ for (cur = *a_media_list; cur; cur = cur->next) { -+ if (cur->data) { -+ cr_string_destroy (cur->data); -+ } -+ } -+ -+ g_list_free (*a_media_list); -+ *a_media_list = NULL; -+ } -+ -+ if (*a_import_string) { -+ cr_string_destroy (*a_import_string); -+ *a_import_string = NULL; -+ } -+ -+ if (medium) { -+ cr_string_destroy (medium); -+ medium = NULL; -+ } -+ -+ cr_tknzr_set_cur_pos (PRIVATE (a_this)->tknzr, &init_pos); -+ -+ return status; -+} -+ -+/** -+ * cr_parser_parse_media: -+ *@a_this: the "this pointer" of the current instance of #CRParser. -+ * -+ *Parses a 'media' declaration as specified in the css2 spec at -+ *appendix D.1: -+ * -+ *media ::= \@media S* medium [ ',' S* medium ]* '{' S* ruleset* '}' S* -+ * -+ *Note that this function calls the required sac handlers during the parsing -+ *to notify media productions. See #CRDocHandler to know the callback called -+ *during \@media parsing. -+ * -+ *Returns CR_OK upon successfull completion, an error code otherwise. -+ */ -+enum CRStatus -+cr_parser_parse_media (CRParser * a_this) -+{ -+ enum CRStatus status = CR_OK; -+ CRInputPos init_pos; -+ CRToken *token = NULL; -+ guint32 next_char = 0, -+ cur_char = 0; -+ CRString *medium = NULL; -+ GList *media_list = NULL; -+ CRParsingLocation location = {0} ; -+ -+ g_return_val_if_fail (a_this -+ && PRIVATE (a_this), -+ CR_BAD_PARAM_ERROR); -+ -+ RECORD_INITIAL_POS (a_this, &init_pos); -+ -+ status = cr_tknzr_get_next_token (PRIVATE (a_this)->tknzr, -+ &token); -+ ENSURE_PARSING_COND (status == CR_OK -+ && token -+ && token->type == MEDIA_SYM_TK); -+ cr_parsing_location_copy (&location, &token->location) ; -+ cr_token_destroy (token); -+ token = NULL; -+ -+ cr_parser_try_to_skip_spaces_and_comments (a_this); -+ -+ status = cr_tknzr_get_next_token (PRIVATE (a_this)->tknzr, &token); -+ ENSURE_PARSING_COND (status == CR_OK -+ && token && token->type == IDENT_TK); -+ -+ medium = token->u.str; -+ token->u.str = NULL; -+ cr_token_destroy (token); -+ token = NULL; -+ -+ if (medium) { -+ media_list = g_list_append (media_list, medium); -+ medium = NULL; -+ } -+ -+ for (; status == CR_OK;) { -+ cr_parser_try_to_skip_spaces_and_comments (a_this); -+ PEEK_NEXT_CHAR (a_this, &next_char); -+ -+ if (next_char == ',') { -+ READ_NEXT_CHAR (a_this, &cur_char); -+ } else { -+ break; -+ } -+ -+ cr_parser_try_to_skip_spaces_and_comments (a_this); -+ -+ status = cr_parser_parse_ident (a_this, &medium); -+ -+ CHECK_PARSING_STATUS (status, FALSE); -+ -+ if (medium) { -+ media_list = g_list_append (media_list, medium); -+ medium = NULL; -+ } -+ } -+ -+ READ_NEXT_CHAR (a_this, &cur_char); -+ -+ ENSURE_PARSING_COND (cur_char == '{'); -+ -+ /* -+ *call the SAC handler api here. -+ */ -+ if (PRIVATE (a_this)->sac_handler -+ && PRIVATE (a_this)->sac_handler->start_media) { -+ PRIVATE (a_this)->sac_handler->start_media -+ (PRIVATE (a_this)->sac_handler, media_list, -+ &location); -+ } -+ -+ cr_parser_try_to_skip_spaces_and_comments (a_this); -+ -+ PRIVATE (a_this)->state = TRY_PARSE_MEDIA_STATE; -+ -+ for (; status == CR_OK;) { -+ status = cr_parser_parse_ruleset (a_this); -+ cr_parser_try_to_skip_spaces_and_comments (a_this); -+ } -+ -+ READ_NEXT_CHAR (a_this, &cur_char); -+ -+ ENSURE_PARSING_COND (cur_char == '}'); -+ -+ /* -+ *call the right SAC handler api here. -+ */ -+ if (PRIVATE (a_this)->sac_handler -+ && PRIVATE (a_this)->sac_handler->end_media) { -+ PRIVATE (a_this)->sac_handler->end_media -+ (PRIVATE (a_this)->sac_handler, media_list); -+ } -+ -+ cr_parser_try_to_skip_spaces_and_comments (a_this); -+ -+ /* -+ *Then, free the data structures passed to -+ *the last call to the SAC handler. -+ */ -+ if (medium) { -+ cr_string_destroy (medium); -+ medium = NULL; -+ } -+ -+ if (media_list) { -+ GList *cur = NULL; -+ -+ for (cur = media_list; cur; cur = cur->next) { -+ cr_string_destroy (cur->data); -+ } -+ -+ g_list_free (media_list); -+ media_list = NULL; -+ } -+ -+ cr_parser_clear_errors (a_this); -+ PRIVATE (a_this)->state = MEDIA_PARSED_STATE; -+ -+ return CR_OK; -+ -+ error: -+ -+ if (token) { -+ cr_token_destroy (token); -+ token = NULL; -+ } -+ -+ if (medium) { -+ cr_string_destroy (medium); -+ medium = NULL; -+ } -+ -+ if (media_list) { -+ GList *cur = NULL; -+ -+ for (cur = media_list; cur; cur = cur->next) { -+ cr_string_destroy (cur->data); -+ } -+ -+ g_list_free (media_list); -+ media_list = NULL; -+ } -+ -+ cr_tknzr_set_cur_pos (PRIVATE (a_this)->tknzr, &init_pos); -+ -+ return status; -+} -+ -+/** -+ * cr_parser_parse_page: -+ *@a_this: the "this pointer" of the current instance of #CRParser. -+ * -+ *Parses '\@page' rule as specified in the css2 spec in appendix D.1: -+ *page ::= PAGE_SYM S* IDENT? pseudo_page? S* -+ *'{' S* declaration [ ';' S* declaration ]* '}' S* -+ * -+ *This function also calls the relevant SAC handlers whenever it -+ *encounters a construction that must -+ *be reported to the calling application. -+ * -+ *Returns CR_OK upon successfull completion, an error code otherwise. -+ */ -+enum CRStatus -+cr_parser_parse_page (CRParser * a_this) -+{ -+ enum CRStatus status = CR_OK; -+ CRInputPos init_pos; -+ CRToken *token = NULL; -+ CRTerm *css_expression = NULL; -+ CRString *page_selector = NULL, -+ *page_pseudo_class = NULL, -+ *property = NULL; -+ gboolean important = TRUE; -+ CRParsingLocation location = {0} ; -+ -+ g_return_val_if_fail (a_this, CR_BAD_PARAM_ERROR); -+ -+ RECORD_INITIAL_POS (a_this, &init_pos); -+ -+ status = cr_tknzr_get_next_token (PRIVATE (a_this)->tknzr, -+ &token) ; -+ ENSURE_PARSING_COND (status == CR_OK -+ && token -+ && token->type == PAGE_SYM_TK); -+ -+ cr_parsing_location_copy (&location, &token->location) ; -+ cr_token_destroy (token); -+ token = NULL; -+ -+ cr_parser_try_to_skip_spaces_and_comments (a_this); -+ -+ status = cr_tknzr_get_next_token (PRIVATE (a_this)->tknzr, &token); -+ ENSURE_PARSING_COND (status == CR_OK && token); -+ -+ if (token->type == IDENT_TK) { -+ page_selector = token->u.str; -+ token->u.str = NULL; -+ cr_token_destroy (token); -+ token = NULL; -+ } else { -+ cr_tknzr_unget_token (PRIVATE (a_this)->tknzr, token); -+ token = NULL; -+ } -+ -+ /* -+ *try to parse pseudo_page -+ */ -+ cr_parser_try_to_skip_spaces_and_comments (a_this); -+ status = cr_tknzr_get_next_token (PRIVATE (a_this)->tknzr, &token); -+ ENSURE_PARSING_COND (status == CR_OK && token); -+ -+ if (token->type == DELIM_TK && token->u.unichar == ':') { -+ cr_token_destroy (token); -+ token = NULL; -+ status = cr_parser_parse_ident (a_this, &page_pseudo_class); -+ CHECK_PARSING_STATUS (status, FALSE); -+ } else { -+ cr_tknzr_unget_token (PRIVATE (a_this)->tknzr, token); -+ token = NULL; -+ } -+ -+ /* -+ *parse_block -+ * -+ */ -+ cr_parser_try_to_skip_spaces_and_comments (a_this); -+ -+ status = cr_tknzr_get_next_token (PRIVATE (a_this)->tknzr, &token); -+ -+ ENSURE_PARSING_COND (status == CR_OK && token -+ && token->type == CBO_TK); -+ -+ cr_token_destroy (token); -+ token = NULL; -+ -+ /* -+ *Call the appropriate SAC handler here. -+ */ -+ if (PRIVATE (a_this)->sac_handler -+ && PRIVATE (a_this)->sac_handler->start_page) { -+ PRIVATE (a_this)->sac_handler->start_page -+ (PRIVATE (a_this)->sac_handler, -+ page_selector, page_pseudo_class, -+ &location); -+ } -+ cr_parser_try_to_skip_spaces_and_comments (a_this); -+ -+ PRIVATE (a_this)->state = TRY_PARSE_PAGE_STATE; -+ -+ status = cr_parser_parse_declaration (a_this, &property, -+ &css_expression, -+ &important); -+ ENSURE_PARSING_COND (status == CR_OK); -+ -+ /* -+ *call the relevant SAC handler here... -+ */ -+ if (PRIVATE (a_this)->sac_handler -+ && PRIVATE (a_this)->sac_handler->property) { -+ if (css_expression) -+ cr_term_ref (css_expression); -+ -+ PRIVATE (a_this)->sac_handler->property -+ (PRIVATE (a_this)->sac_handler, -+ property, css_expression, important); -+ } -+ /* -+ *... and free the data structure passed to that last -+ *SAC handler. -+ */ -+ if (property) { -+ cr_string_destroy (property); -+ property = NULL; -+ } -+ if (css_expression) { -+ cr_term_unref (css_expression); -+ css_expression = NULL; -+ } -+ -+ for (;;) { -+ /*parse the other ';' separated declarations */ -+ if (token) { -+ cr_token_destroy (token); -+ token = NULL; -+ } -+ status = cr_tknzr_get_next_token -+ (PRIVATE (a_this)->tknzr, &token); -+ -+ ENSURE_PARSING_COND (status == CR_OK && token); -+ -+ if (token->type != SEMICOLON_TK) { -+ cr_tknzr_unget_token -+ (PRIVATE (a_this)->tknzr, -+ token); -+ token = NULL ; -+ break; -+ } -+ -+ cr_token_destroy (token); -+ token = NULL; -+ cr_parser_try_to_skip_spaces_and_comments (a_this); -+ -+ status = cr_parser_parse_declaration (a_this, &property, -+ &css_expression, -+ &important); -+ if (status != CR_OK) -+ break ; -+ -+ /* -+ *call the relevant SAC handler here... -+ */ -+ if (PRIVATE (a_this)->sac_handler -+ && PRIVATE (a_this)->sac_handler->property) { -+ cr_term_ref (css_expression); -+ PRIVATE (a_this)->sac_handler->property -+ (PRIVATE (a_this)->sac_handler, -+ property, css_expression, important); -+ } -+ /* -+ *... and free the data structure passed to that last -+ *SAC handler. -+ */ -+ if (property) { -+ cr_string_destroy (property); -+ property = NULL; -+ } -+ if (css_expression) { -+ cr_term_unref (css_expression); -+ css_expression = NULL; -+ } -+ } -+ cr_parser_try_to_skip_spaces_and_comments -+ (a_this) ; -+ if (token) { -+ cr_token_destroy (token) ; -+ token = NULL ; -+ } -+ -+ status = cr_tknzr_get_next_token -+ (PRIVATE (a_this)->tknzr, &token); -+ ENSURE_PARSING_COND (status == CR_OK -+ && token -+ && token->type == CBC_TK) ; -+ cr_token_destroy (token) ; -+ token = NULL ; -+ /* -+ *call the relevant SAC handler here. -+ */ -+ if (PRIVATE (a_this)->sac_handler -+ && PRIVATE (a_this)->sac_handler->end_page) { -+ PRIVATE (a_this)->sac_handler->end_page -+ (PRIVATE (a_this)->sac_handler, -+ page_selector, page_pseudo_class); -+ } -+ -+ if (page_selector) { -+ cr_string_destroy (page_selector); -+ page_selector = NULL; -+ } -+ -+ if (page_pseudo_class) { -+ cr_string_destroy (page_pseudo_class); -+ page_pseudo_class = NULL; -+ } -+ -+ cr_parser_try_to_skip_spaces_and_comments (a_this); -+ -+ /*here goes the former implem of this function ... */ -+ -+ cr_parser_clear_errors (a_this); -+ PRIVATE (a_this)->state = PAGE_PARSED_STATE; -+ -+ return CR_OK; -+ -+ error: -+ if (token) { -+ cr_token_destroy (token); -+ token = NULL; -+ } -+ if (page_selector) { -+ cr_string_destroy (page_selector); -+ page_selector = NULL; -+ } -+ if (page_pseudo_class) { -+ cr_string_destroy (page_pseudo_class); -+ page_pseudo_class = NULL; -+ } -+ if (property) { -+ cr_string_destroy (property); -+ property = NULL; -+ } -+ if (css_expression) { -+ cr_term_destroy (css_expression); -+ css_expression = NULL; -+ } -+ cr_tknzr_set_cur_pos (PRIVATE (a_this)->tknzr, &init_pos); -+ return status; -+} -+ -+/** -+ * cr_parser_parse_charset: -+ *@a_this: the "this pointer" of the current instance of #CRParser. -+ *@a_value: out parameter. The actual parsed value of the charset -+ *declararation. Note that for safety check reasons, *a_value must be -+ *set to NULL. -+ *@a_charset_sym_location: the parsing location of the charset rule -+ * -+ *Parses a charset declaration as defined implictly by the css2 spec in -+ *appendix D.1: -+ *charset ::= CHARSET_SYM S* STRING S* ';' -+ * -+ *Returns CR_OK upon successfull completion, an error code otherwise. -+ */ -+enum CRStatus -+cr_parser_parse_charset (CRParser * a_this, CRString ** a_value, -+ CRParsingLocation *a_charset_sym_location) -+{ -+ enum CRStatus status = CR_OK; -+ CRInputPos init_pos; -+ CRToken *token = NULL; -+ CRString *charset_str = NULL; -+ -+ g_return_val_if_fail (a_this && a_value -+ && (*a_value == NULL), -+ CR_BAD_PARAM_ERROR); -+ -+ RECORD_INITIAL_POS (a_this, &init_pos); -+ -+ status = cr_tknzr_get_next_token (PRIVATE (a_this)->tknzr, &token); -+ -+ ENSURE_PARSING_COND (status == CR_OK -+ && token && token->type == CHARSET_SYM_TK); -+ if (a_charset_sym_location) { -+ cr_parsing_location_copy (a_charset_sym_location, -+ &token->location) ; -+ } -+ cr_token_destroy (token); -+ token = NULL; -+ -+ PRIVATE (a_this)->state = TRY_PARSE_CHARSET_STATE; -+ -+ cr_parser_try_to_skip_spaces_and_comments (a_this); -+ -+ status = cr_tknzr_get_next_token (PRIVATE (a_this)->tknzr, &token); -+ ENSURE_PARSING_COND (status == CR_OK -+ && token && token->type == STRING_TK); -+ charset_str = token->u.str; -+ token->u.str = NULL; -+ cr_token_destroy (token); -+ token = NULL; -+ -+ cr_parser_try_to_skip_spaces_and_comments (a_this); -+ -+ status = cr_tknzr_get_next_token (PRIVATE (a_this)->tknzr, &token); -+ -+ ENSURE_PARSING_COND (status == CR_OK -+ && token && token->type == SEMICOLON_TK); -+ cr_token_destroy (token); -+ token = NULL; -+ -+ if (charset_str) { -+ *a_value = charset_str; -+ charset_str = NULL; -+ } -+ -+ PRIVATE (a_this)->state = CHARSET_PARSED_STATE; -+ return CR_OK; -+ -+ error: -+ -+ if (token) { -+ cr_token_destroy (token); -+ token = NULL; -+ } -+ -+ if (*a_value) { -+ cr_string_destroy (*a_value); -+ *a_value = NULL; -+ } -+ -+ if (charset_str) { -+ cr_string_destroy (charset_str); -+ charset_str = NULL; -+ } -+ -+ cr_tknzr_set_cur_pos (PRIVATE (a_this)->tknzr, &init_pos); -+ -+ return status; -+} -+ -+/** -+ * cr_parser_parse_font_face: -+ *@a_this: the current instance of #CRParser. -+ * -+ *Parses the "\@font-face" rule specified in the css1 spec in -+ *appendix D.1: -+ * -+ *font_face ::= FONT_FACE_SYM S* -+ *'{' S* declaration [ ';' S* declaration ]* '}' S* -+ * -+ *This function will call SAC handlers whenever it is necessary. -+ * -+ *Returns CR_OK upon successfull completion, an error code otherwise. -+ */ -+enum CRStatus -+cr_parser_parse_font_face (CRParser * a_this) -+{ -+ enum CRStatus status = CR_ERROR; -+ CRInputPos init_pos; -+ CRString *property = NULL; -+ CRTerm *css_expression = NULL; -+ CRToken *token = NULL; -+ gboolean important = FALSE; -+ guint32 next_char = 0, -+ cur_char = 0; -+ CRParsingLocation location = {0} ; -+ -+ g_return_val_if_fail (a_this, CR_BAD_PARAM_ERROR); -+ -+ RECORD_INITIAL_POS (a_this, &init_pos); -+ -+ status = cr_tknzr_get_next_token (PRIVATE (a_this)->tknzr, &token); -+ ENSURE_PARSING_COND (status == CR_OK -+ && token -+ && token->type == FONT_FACE_SYM_TK); -+ -+ cr_parser_try_to_skip_spaces_and_comments (a_this); -+ if (token) { -+ cr_parsing_location_copy (&location, -+ &token->location) ; -+ cr_token_destroy (token); -+ token = NULL; -+ } -+ status = cr_tknzr_get_next_token (PRIVATE (a_this)->tknzr, -+ &token); -+ ENSURE_PARSING_COND (status == CR_OK && token -+ && token->type == CBO_TK); -+ if (token) { -+ cr_token_destroy (token); -+ token = NULL; -+ } -+ /* -+ *here, call the relevant SAC handler. -+ */ -+ if (PRIVATE (a_this)->sac_handler -+ && PRIVATE (a_this)->sac_handler->start_font_face) { -+ PRIVATE (a_this)->sac_handler->start_font_face -+ (PRIVATE (a_this)->sac_handler, &location); -+ } -+ PRIVATE (a_this)->state = TRY_PARSE_FONT_FACE_STATE; -+ /* -+ *and resume the parsing. -+ */ -+ cr_parser_try_to_skip_spaces_and_comments (a_this); -+ status = cr_parser_parse_declaration (a_this, &property, -+ &css_expression, &important); -+ if (status == CR_OK) { -+ /* -+ *here, call the relevant SAC handler. -+ */ -+ cr_term_ref (css_expression); -+ if (PRIVATE (a_this)->sac_handler && -+ PRIVATE (a_this)->sac_handler->property) { -+ PRIVATE (a_this)->sac_handler->property -+ (PRIVATE (a_this)->sac_handler, -+ property, css_expression, important); -+ } -+ ENSURE_PARSING_COND (css_expression && property); -+ } -+ /*free the data structures allocated during last parsing. */ -+ if (property) { -+ cr_string_destroy (property); -+ property = NULL; -+ } -+ if (css_expression) { -+ cr_term_unref (css_expression); -+ css_expression = NULL; -+ } -+ for (;;) { -+ PEEK_NEXT_CHAR (a_this, &next_char); -+ if (next_char == ';') { -+ READ_NEXT_CHAR (a_this, &cur_char); -+ } else { -+ break; -+ } -+ cr_parser_try_to_skip_spaces_and_comments (a_this); -+ status = cr_parser_parse_declaration (a_this, -+ &property, -+ &css_expression, -+ &important); -+ if (status != CR_OK) -+ break; -+ /* -+ *here, call the relevant SAC handler. -+ */ -+ cr_term_ref (css_expression); -+ if (PRIVATE (a_this)->sac_handler->property) { -+ PRIVATE (a_this)->sac_handler->property -+ (PRIVATE (a_this)->sac_handler, -+ property, css_expression, important); -+ } -+ /* -+ *Then, free the data structures allocated during -+ *last parsing. -+ */ -+ if (property) { -+ cr_string_destroy (property); -+ property = NULL; -+ } -+ if (css_expression) { -+ cr_term_unref (css_expression); -+ css_expression = NULL; -+ } -+ } -+ cr_parser_try_to_skip_spaces_and_comments (a_this); -+ READ_NEXT_CHAR (a_this, &cur_char); -+ ENSURE_PARSING_COND (cur_char == '}'); -+ /* -+ *here, call the relevant SAC handler. -+ */ -+ if (PRIVATE (a_this)->sac_handler->end_font_face) { -+ PRIVATE (a_this)->sac_handler->end_font_face -+ (PRIVATE (a_this)->sac_handler); -+ } -+ cr_parser_try_to_skip_spaces_and_comments (a_this); -+ -+ if (token) { -+ cr_token_destroy (token); -+ token = NULL; -+ } -+ cr_parser_clear_errors (a_this); -+ PRIVATE (a_this)->state = FONT_FACE_PARSED_STATE; -+ return CR_OK; -+ -+ error: -+ if (token) { -+ cr_token_destroy (token); -+ token = NULL; -+ } -+ if (property) { -+ cr_string_destroy (property); -+ property = NULL; -+ } -+ if (css_expression) { -+ cr_term_destroy (css_expression); -+ css_expression = NULL; -+ } -+ cr_tknzr_set_cur_pos (PRIVATE (a_this)->tknzr, &init_pos); -+ return status; -+} -+ -+/** -+ * cr_parser_parse: -+ *@a_this: the current instance of #CRParser. -+ * -+ *Parses the data that comes from the -+ *input previously associated to the current instance of -+ *#CRParser. -+ * -+ *Returns CR_OK upon succesful completion, an error code otherwise. -+ */ -+enum CRStatus -+cr_parser_parse (CRParser * a_this) -+{ -+ enum CRStatus status = CR_ERROR; -+ -+ g_return_val_if_fail (a_this && PRIVATE (a_this) -+ && PRIVATE (a_this)->tknzr, CR_BAD_PARAM_ERROR); -+ -+ if (PRIVATE (a_this)->use_core_grammar == FALSE) { -+ status = cr_parser_parse_stylesheet (a_this); -+ } else { -+ status = cr_parser_parse_stylesheet_core (a_this); -+ } -+ -+ return status; -+} -+ -+/** -+ * cr_parser_set_tknzr: -+ * @a_this: the current instance of #CRParser; -+ * @a_tknzr: the new tokenizer. -+ * -+ * Returns CR_OK upon successful completion, an error code otherwise. -+ */ -+enum CRStatus -+cr_parser_set_tknzr (CRParser * a_this, CRTknzr * a_tknzr) -+{ -+ g_return_val_if_fail (a_this && PRIVATE (a_this), CR_BAD_PARAM_ERROR); -+ -+ if (PRIVATE (a_this)->tknzr) { -+ cr_tknzr_unref (PRIVATE (a_this)->tknzr); -+ } -+ -+ PRIVATE (a_this)->tknzr = a_tknzr; -+ -+ if (a_tknzr) -+ cr_tknzr_ref (a_tknzr); -+ -+ return CR_OK; -+} -+ -+/** -+ * cr_parser_get_tknzr: -+ *@a_this: the current instance of #CRParser -+ *@a_tknzr: out parameter. The returned tokenizer -+ * -+ *Getter of the parser's underlying tokenizer -+ * -+ *Returns CR_OK upon succesful completion, an error code -+ *otherwise -+ */ -+enum CRStatus -+cr_parser_get_tknzr (CRParser * a_this, CRTknzr ** a_tknzr) -+{ -+ g_return_val_if_fail (a_this && PRIVATE (a_this) -+ && a_tknzr, CR_BAD_PARAM_ERROR); -+ -+ *a_tknzr = PRIVATE (a_this)->tknzr; -+ return CR_OK; -+} -+ -+/** -+ * cr_parser_get_parsing_location: -+ *@a_this: the current instance of #CRParser -+ *@a_loc: the parsing location to get. -+ * -+ *Gets the current parsing location. -+ * -+ *Returns CR_OK upon succesful completion, an error code -+ *otherwise. -+ */ -+enum CRStatus -+cr_parser_get_parsing_location (CRParser const *a_this, -+ CRParsingLocation *a_loc) -+{ -+ g_return_val_if_fail (a_this -+ && PRIVATE (a_this) -+ && a_loc, CR_BAD_PARAM_ERROR) ; -+ -+ return cr_tknzr_get_parsing_location -+ (PRIVATE (a_this)->tknzr, a_loc) ; -+} -+ -+/** -+ * cr_parser_parse_buf: -+ *@a_this: the current instance of #CRparser -+ *@a_buf: the input buffer -+ *@a_len: the length of the input buffer -+ *@a_enc: the encoding of the buffer -+ * -+ *Parses a stylesheet from a buffer -+ * -+ *Returns CR_OK upon successful completion, an error code otherwise. -+ */ -+enum CRStatus -+cr_parser_parse_buf (CRParser * a_this, -+ const guchar * a_buf, -+ gulong a_len, enum CREncoding a_enc) -+{ -+ enum CRStatus status = CR_ERROR; -+ CRTknzr *tknzr = NULL; -+ -+ g_return_val_if_fail (a_this && PRIVATE (a_this) -+ && a_buf, CR_BAD_PARAM_ERROR); -+ -+ tknzr = cr_tknzr_new_from_buf ((guchar*)a_buf, a_len, a_enc, FALSE); -+ -+ g_return_val_if_fail (tknzr != NULL, CR_ERROR); -+ -+ status = cr_parser_set_tknzr (a_this, tknzr); -+ g_return_val_if_fail (status == CR_OK, CR_ERROR); -+ -+ status = cr_parser_parse (a_this); -+ -+ return status; -+} -+ -+/** -+ * cr_parser_destroy: -+ *@a_this: the current instance of #CRParser to -+ *destroy. -+ * -+ *Destroys the current instance -+ *of #CRParser. -+ */ -+void -+cr_parser_destroy (CRParser * a_this) -+{ -+ g_return_if_fail (a_this && PRIVATE (a_this)); -+ -+ if (PRIVATE (a_this)->tknzr) { -+ if (cr_tknzr_unref (PRIVATE (a_this)->tknzr) == TRUE) -+ PRIVATE (a_this)->tknzr = NULL; -+ } -+ -+ if (PRIVATE (a_this)->sac_handler) { -+ cr_doc_handler_unref (PRIVATE (a_this)->sac_handler); -+ PRIVATE (a_this)->sac_handler = NULL; -+ } -+ -+ if (PRIVATE (a_this)->err_stack) { -+ cr_parser_clear_errors (a_this); -+ PRIVATE (a_this)->err_stack = NULL; -+ } -+ -+ if (PRIVATE (a_this)) { -+ g_free (PRIVATE (a_this)); -+ PRIVATE (a_this) = NULL; -+ } -+ -+ if (a_this) { -+ g_free (a_this); -+ a_this = NULL; /*useless. Just for the sake of coherence */ -+ } -+} -diff --git a/src/st/croco/cr-parser.h b/src/st/croco/cr-parser.h -new file mode 100644 -index 000000000..6dce9439e ---- /dev/null -+++ b/src/st/croco/cr-parser.h -@@ -0,0 +1,128 @@ -+/* -*- Mode: C; indent-tabs-mode:nil; c-basic-offset: 8-*- */ -+ -+/* -+ * This file is part of The Croco Library -+ * -+ * 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 -+ * See COPYRIGHTS file for copyrights information. -+ */ -+ -+#ifndef __CR_PARSER_H__ -+#define __CR_PARSER_H__ -+ -+#include -+#include "cr-input.h" -+#include "cr-tknzr.h" -+#include "cr-utils.h" -+#include "cr-doc-handler.h" -+ -+G_BEGIN_DECLS -+ -+/** -+ *@file -+ *The declaration file -+ *of the #CRParser class. -+ */ -+typedef struct _CRParser CRParser ; -+typedef struct _CRParserPriv CRParserPriv ; -+ -+ -+/** -+ *The implementation of -+ *the SAC parser. -+ *The Class is opaque -+ *and must be manipulated through -+ *the provided methods. -+ */ -+struct _CRParser { -+ CRParserPriv *priv ; -+} ; -+ -+ -+CRParser * cr_parser_new (CRTknzr *a_tknzr) ; -+ -+CRParser * cr_parser_new_from_buf (guchar *a_buf, gulong a_len, -+ enum CREncoding a_enc, -+ gboolean a_free_buf) ; -+ -+CRParser * cr_parser_new_from_file (const guchar *a_file_uri, -+ enum CREncoding a_enc) ; -+ -+CRParser * cr_parser_new_from_input (CRInput *a_input) ; -+ -+enum CRStatus cr_parser_set_tknzr (CRParser *a_this, CRTknzr *a_tknzr) ; -+ -+enum CRStatus cr_parser_get_tknzr (CRParser *a_this, CRTknzr **a_tknzr) ; -+ -+enum CRStatus cr_parser_get_parsing_location (CRParser const *a_this, CRParsingLocation *a_loc) ; -+ -+enum CRStatus cr_parser_try_to_skip_spaces_and_comments (CRParser *a_this) ; -+ -+ -+enum CRStatus cr_parser_set_sac_handler (CRParser *a_this, -+ CRDocHandler *a_handler) ; -+ -+enum CRStatus cr_parser_get_sac_handler (CRParser *a_this, -+ CRDocHandler **a_handler) ; -+ -+enum CRStatus cr_parser_set_use_core_grammar (CRParser *a_this, -+ gboolean a_use_core_grammar) ; -+enum CRStatus cr_parser_get_use_core_grammar (CRParser const *a_this, -+ gboolean *a_use_core_grammar) ; -+ -+enum CRStatus cr_parser_parse (CRParser *a_this) ; -+ -+enum CRStatus cr_parser_parse_file (CRParser *a_this, -+ const guchar *a_file_uri, -+ enum CREncoding a_enc) ; -+ -+enum CRStatus cr_parser_parse_buf (CRParser *a_this, const guchar *a_buf, -+ gulong a_len, enum CREncoding a_enc) ; -+ -+enum CRStatus cr_parser_set_default_sac_handler (CRParser *a_this) ; -+ -+enum CRStatus cr_parser_parse_term (CRParser *a_this, CRTerm **a_term) ; -+ -+enum CRStatus cr_parser_parse_expr (CRParser *a_this, CRTerm **a_expr) ; -+ -+enum CRStatus cr_parser_parse_prio (CRParser *a_this, CRString **a_prio) ; -+ -+enum CRStatus cr_parser_parse_declaration (CRParser *a_this, CRString **a_property, -+ CRTerm **a_expr, gboolean *a_important) ; -+ -+enum CRStatus cr_parser_parse_statement_core (CRParser *a_this) ; -+ -+enum CRStatus cr_parser_parse_ruleset (CRParser *a_this) ; -+ -+enum CRStatus cr_parser_parse_import (CRParser *a_this, GList ** a_media_list, -+ CRString **a_import_string, -+ CRParsingLocation *a_location) ; -+ -+enum CRStatus cr_parser_parse_media (CRParser *a_this) ; -+ -+enum CRStatus cr_parser_parse_page (CRParser *a_this) ; -+ -+enum CRStatus cr_parser_parse_charset (CRParser *a_this, CRString **a_value, -+ CRParsingLocation *a_charset_sym_location) ; -+ -+enum CRStatus cr_parser_parse_font_face (CRParser *a_this) ; -+ -+void cr_parser_destroy (CRParser *a_this) ; -+ -+G_END_DECLS -+ -+#endif /*__CR_PARSER_H__*/ -diff --git a/src/st/croco/cr-parsing-location.c b/src/st/croco/cr-parsing-location.c -new file mode 100644 -index 000000000..4fe4acc30 ---- /dev/null -+++ b/src/st/croco/cr-parsing-location.c -@@ -0,0 +1,172 @@ -+/* -*- Mode: C; indent-tabs-mode: nil; c-basic-offset: 8 -*- */ -+ -+/* -+ * This file is part of The Croco Library -+ * -+ * 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. -+ * See the COPYRIGHTS file for copyright information. -+ */ -+ -+#include -+#include "cr-parsing-location.h" -+ -+/** -+ *@CRParsingLocation: -+ * -+ *Definition of the #CRparsingLocation class. -+ */ -+ -+ -+/** -+ * cr_parsing_location_new: -+ *Instanciates a new parsing location. -+ * -+ *Returns the newly instanciated #CRParsingLocation. -+ *Must be freed by cr_parsing_location_destroy() -+ */ -+CRParsingLocation * -+cr_parsing_location_new (void) -+{ -+ CRParsingLocation * result = NULL ; -+ -+ result = g_try_malloc (sizeof (CRParsingLocation)) ; -+ if (!result) { -+ cr_utils_trace_info ("Out of memory error") ; -+ return NULL ; -+ } -+ cr_parsing_location_init (result) ; -+ return result ; -+} -+ -+/** -+ * cr_parsing_location_init: -+ *@a_this: the current instance of #CRParsingLocation. -+ * -+ *Initializes the an instance of #CRparsingLocation. -+ * -+ *Returns CR_OK upon succesful completion, an error code otherwise. -+ */ -+enum CRStatus -+cr_parsing_location_init (CRParsingLocation *a_this) -+{ -+ g_return_val_if_fail (a_this, CR_BAD_PARAM_ERROR) ; -+ -+ memset (a_this, 0, sizeof (CRParsingLocation)) ; -+ return CR_OK ; -+} -+ -+/** -+ * cr_parsing_location_copy: -+ *@a_to: the destination of the copy. -+ *Must be allocated by the caller. -+ *@a_from: the source of the copy. -+ * -+ *Copies an instance of CRParsingLocation into another one. -+ * -+ *Returns CR_OK upon succesful completion, an error code -+ *otherwise. -+ */ -+enum CRStatus -+cr_parsing_location_copy (CRParsingLocation *a_to, -+ CRParsingLocation const *a_from) -+{ -+ g_return_val_if_fail (a_to && a_from, CR_BAD_PARAM_ERROR) ; -+ -+ memcpy (a_to, a_from, sizeof (CRParsingLocation)) ; -+ return CR_OK ; -+} -+ -+/** -+ * cr_parsing_location_to_string: -+ *@a_this: the current instance of #CRParsingLocation. -+ *@a_mask: a bitmap that defines which parts of the -+ *parsing location are to be serialized (line, column or byte offset) -+ * -+ *Returns the serialized string or NULL in case of an error. -+ */ -+gchar * -+cr_parsing_location_to_string (CRParsingLocation const *a_this, -+ enum CRParsingLocationSerialisationMask a_mask) -+{ -+ GString *result = NULL ; -+ gchar *str = NULL ; -+ -+ g_return_val_if_fail (a_this, NULL) ; -+ -+ if (!a_mask) { -+ a_mask = DUMP_LINE | DUMP_COLUMN | DUMP_BYTE_OFFSET ; -+ } -+ result =g_string_new (NULL) ; -+ if (!result) -+ return NULL ; -+ if (a_mask & DUMP_LINE) { -+ g_string_append_printf (result, "line:%d ", -+ a_this->line) ; -+ } -+ if (a_mask & DUMP_COLUMN) { -+ g_string_append_printf (result, "column:%d ", -+ a_this->column) ; -+ } -+ if (a_mask & DUMP_BYTE_OFFSET) { -+ g_string_append_printf (result, "byte offset:%d ", -+ a_this->byte_offset) ; -+ } -+ if (result->len) { -+ str = result->str ; -+ g_string_free (result, FALSE) ; -+ } else { -+ g_string_free (result, TRUE) ; -+ } -+ return str ; -+} -+ -+/** -+ * cr_parsing_location_dump: -+ * @a_this: current instance of #CRParsingLocation -+ * @a_mask: the serialization mask. -+ * @a_fp: the file pointer to dump the parsing location to. -+ */ -+void -+cr_parsing_location_dump (CRParsingLocation const *a_this, -+ enum CRParsingLocationSerialisationMask a_mask, -+ FILE *a_fp) -+{ -+ gchar *str = NULL ; -+ -+ g_return_if_fail (a_this && a_fp) ; -+ str = cr_parsing_location_to_string (a_this, a_mask) ; -+ if (str) { -+ fprintf (a_fp, "%s", str) ; -+ g_free (str) ; -+ str = NULL ; -+ } -+} -+ -+/** -+ * cr_parsing_location_destroy: -+ *@a_this: the current instance of #CRParsingLocation. Must -+ *have been allocated with cr_parsing_location_new(). -+ * -+ *Destroys the current instance of #CRParsingLocation -+ */ -+void -+cr_parsing_location_destroy (CRParsingLocation *a_this) -+{ -+ g_return_if_fail (a_this) ; -+ g_free (a_this) ; -+} -+ -diff --git a/src/st/croco/cr-parsing-location.h b/src/st/croco/cr-parsing-location.h -new file mode 100644 -index 000000000..b8064a560 ---- /dev/null -+++ b/src/st/croco/cr-parsing-location.h -@@ -0,0 +1,70 @@ -+/* -*- Mode: C; indent-tabs-mode: nil; c-basic-offset: 8 -*- */ -+ -+/* -+ * This file is part of The Croco Library -+ * -+ * 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. -+ * See the COPYRIGHTS file for copyright information. -+ */ -+ -+#ifndef __CR_PARSING_LOCATION_H__ -+#define __CR_PARSING_LOCATION_H__ -+ -+#include "cr-utils.h" -+ -+G_BEGIN_DECLS -+ -+/** -+ *@file -+ *The declaration of the CRParsingLocation -+ *object. This object keeps track of line/column/byte offset/ -+ *at which the parsing of a given CSS construction appears. -+ */ -+ -+typedef struct _CRParsingLocation CRParsingLocation; -+struct _CRParsingLocation { -+ guint line ; -+ guint column ; -+ guint byte_offset ; -+} ; -+ -+ -+enum CRParsingLocationSerialisationMask { -+ DUMP_LINE = 1, -+ DUMP_COLUMN = 1 << 1, -+ DUMP_BYTE_OFFSET = 1 << 2 -+} ; -+ -+CRParsingLocation * cr_parsing_location_new (void) ; -+ -+enum CRStatus cr_parsing_location_init (CRParsingLocation *a_this) ; -+ -+enum CRStatus cr_parsing_location_copy (CRParsingLocation *a_to, -+ CRParsingLocation const *a_from) ; -+ -+gchar * cr_parsing_location_to_string (CRParsingLocation const *a_this, -+ enum CRParsingLocationSerialisationMask a_mask) ; -+void cr_parsing_location_dump (CRParsingLocation const *a_this, -+ enum CRParsingLocationSerialisationMask a_mask, -+ FILE *a_fp) ; -+ -+void cr_parsing_location_destroy (CRParsingLocation *a_this) ; -+ -+ -+ -+G_END_DECLS -+#endif -diff --git a/src/st/croco/cr-prop-list.c b/src/st/croco/cr-prop-list.c -new file mode 100644 -index 000000000..70a04f337 ---- /dev/null -+++ b/src/st/croco/cr-prop-list.c -@@ -0,0 +1,404 @@ -+/* -+ * This file is part of The Croco Library -+ * -+ * 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 -+ * See COPYRIGHTS file for copyrights information. -+ */ -+ -+#include -+#include "cr-prop-list.h" -+ -+#define PRIVATE(a_obj) (a_obj)->priv -+ -+struct _CRPropListPriv { -+ CRString *prop; -+ CRDeclaration *decl; -+ CRPropList *next; -+ CRPropList *prev; -+}; -+ -+static CRPropList *cr_prop_list_allocate (void); -+ -+/** -+ *Default allocator of CRPropList -+ *@return the newly allocated CRPropList or NULL -+ *if an error arises. -+ */ -+static CRPropList * -+cr_prop_list_allocate (void) -+{ -+ CRPropList *result = NULL; -+ -+ result = g_try_malloc (sizeof (CRPropList)); -+ if (!result) { -+ cr_utils_trace_info ("could not allocate CRPropList"); -+ return NULL; -+ } -+ memset (result, 0, sizeof (CRPropList)); -+ PRIVATE (result) = g_try_malloc (sizeof (CRPropListPriv)); -+ if (!result) { -+ cr_utils_trace_info ("could not allocate CRPropListPriv"); -+ g_free (result); -+ return NULL; -+ } -+ memset (PRIVATE (result), 0, sizeof (CRPropListPriv)); -+ return result; -+} -+ -+/**************** -+ *public methods -+ ***************/ -+ -+/** -+ * cr_prop_list_append: -+ *@a_this: the current instance of #CRPropList -+ *@a_to_append: the property list to append -+ * -+ *Appends a property list to the current one. -+ * -+ *Returns the resulting prop list, or NULL if an error -+ *occurred -+ */ -+CRPropList * -+cr_prop_list_append (CRPropList * a_this, CRPropList * a_to_append) -+{ -+ CRPropList *cur = NULL; -+ -+ g_return_val_if_fail (a_to_append, NULL); -+ -+ if (!a_this) -+ return a_to_append; -+ -+ /*go fetch the last element of the list */ -+ for (cur = a_this; -+ cur && PRIVATE (cur) && PRIVATE (cur)->next; -+ cur = PRIVATE (cur)->next) ; -+ g_return_val_if_fail (cur, NULL); -+ PRIVATE (cur)->next = a_to_append; -+ PRIVATE (a_to_append)->prev = cur; -+ return a_this; -+} -+ -+/** -+ * cr_prop_list_append2: -+ *Appends a pair of prop/declaration to -+ *the current prop list. -+ *@a_this: the current instance of #CRPropList -+ *@a_prop: the property to consider -+ *@a_decl: the declaration to consider -+ * -+ *Returns the resulting property list, or NULL in case -+ *of an error. -+ */ -+CRPropList * -+cr_prop_list_append2 (CRPropList * a_this, -+ CRString * a_prop, -+ CRDeclaration * a_decl) -+{ -+ CRPropList *list = NULL, -+ *result = NULL; -+ -+ g_return_val_if_fail (a_prop && a_decl, NULL); -+ -+ list = cr_prop_list_allocate (); -+ g_return_val_if_fail (list && PRIVATE (list), NULL); -+ -+ PRIVATE (list)->prop = a_prop; -+ PRIVATE (list)->decl = a_decl; -+ -+ result = cr_prop_list_append (a_this, list); -+ return result; -+} -+ -+/** -+ * cr_prop_list_prepend: -+ *@a_this: the current instance of #CRPropList -+ *@a_to_prepend: the new list to prepend. -+ * -+ *Prepends a list to the current list -+ *Returns the new properties list. -+ */ -+CRPropList * -+cr_prop_list_prepend (CRPropList * a_this, CRPropList * a_to_prepend) -+{ -+ CRPropList *cur = NULL; -+ -+ g_return_val_if_fail (a_to_prepend, NULL); -+ -+ if (!a_this) -+ return a_to_prepend; -+ -+ for (cur = a_to_prepend; cur && PRIVATE (cur)->next; -+ cur = PRIVATE (cur)->next) ; -+ g_return_val_if_fail (cur, NULL); -+ PRIVATE (cur)->next = a_this; -+ PRIVATE (a_this)->prev = cur; -+ return a_to_prepend; -+} -+ -+/** -+ * cr_prop_list_prepend2: -+ *@a_this: the current instance of #CRPropList -+ *@a_prop_name: property name to append -+ *@a_decl: the property value to append. -+ * -+ *Prepends a propertie to a list of properties -+ * -+ *Returns the new property list. -+ */ -+CRPropList * -+cr_prop_list_prepend2 (CRPropList * a_this, -+ CRString * a_prop_name, CRDeclaration * a_decl) -+{ -+ CRPropList *list = NULL, -+ *result = NULL; -+ -+ g_return_val_if_fail (a_this && PRIVATE (a_this) -+ && a_prop_name && a_decl, NULL); -+ -+ list = cr_prop_list_allocate (); -+ g_return_val_if_fail (list, NULL); -+ PRIVATE (list)->prop = a_prop_name; -+ PRIVATE (list)->decl = a_decl; -+ result = cr_prop_list_prepend (a_this, list); -+ return result; -+} -+ -+/** -+ * cr_prop_list_set_prop: -+ *@a_this: the current instance of #CRPropList -+ *@a_prop: the property to set -+ * -+ *Sets the property of a CRPropList -+ */ -+enum CRStatus -+cr_prop_list_set_prop (CRPropList * a_this, CRString * a_prop) -+{ -+ g_return_val_if_fail (a_this && PRIVATE (a_this) -+ && a_prop, CR_BAD_PARAM_ERROR); -+ -+ PRIVATE (a_this)->prop = a_prop; -+ return CR_OK; -+} -+ -+/** -+ * cr_prop_list_get_prop: -+ *@a_this: the current instance of #CRPropList -+ *@a_prop: out parameter. The returned property -+ * -+ *Getter of the property associated to the current instance -+ *of #CRPropList -+ * -+ *Returns CR_OK upon successful completion, an error code -+ *otherwise. -+ */ -+enum CRStatus -+cr_prop_list_get_prop (CRPropList const * a_this, CRString ** a_prop) -+{ -+ g_return_val_if_fail (a_this && PRIVATE (a_this) -+ && a_prop, CR_BAD_PARAM_ERROR); -+ -+ *a_prop = PRIVATE (a_this)->prop; -+ return CR_OK; -+} -+ -+/** -+ * cr_prop_list_set_decl: -+ * @a_this: the current instance of #CRPropList -+ * @a_decl: the new property value. -+ * -+ * Returns CR_OK upon successful completion, an error code otherwise. -+ */ -+enum CRStatus -+cr_prop_list_set_decl (CRPropList * a_this, CRDeclaration * a_decl) -+{ -+ g_return_val_if_fail (a_this && PRIVATE (a_this) -+ && a_decl, CR_BAD_PARAM_ERROR); -+ -+ PRIVATE (a_this)->decl = a_decl; -+ return CR_OK; -+} -+ -+/** -+ * cr_prop_list_get_decl: -+ * @a_this: the current instance of #CRPropList -+ * @a_decl: out parameter. The property value -+ * -+ * Returns CR_OK upon successful completion. -+ */ -+enum CRStatus -+cr_prop_list_get_decl (CRPropList const * a_this, CRDeclaration ** a_decl) -+{ -+ g_return_val_if_fail (a_this && PRIVATE (a_this) -+ && a_decl, CR_BAD_PARAM_ERROR); -+ -+ *a_decl = PRIVATE (a_this)->decl; -+ return CR_OK; -+} -+ -+/** -+ * cr_prop_list_lookup_prop: -+ *@a_this: the current instance of #CRPropList -+ *@a_prop: the property to lookup -+ *@a_prop_list: out parameter. The property/declaration -+ *pair found (if and only if the function returned code if CR_OK) -+ * -+ *Lookup a given property/declaration pair -+ * -+ *Returns CR_OK if a prop/decl pair has been found, -+ *CR_VALUE_NOT_FOUND_ERROR if not, or an error code if something -+ *bad happens. -+ */ -+enum CRStatus -+cr_prop_list_lookup_prop (CRPropList * a_this, -+ CRString * a_prop, CRPropList ** a_pair) -+{ -+ CRPropList *cur = NULL; -+ -+ g_return_val_if_fail (a_prop && a_pair, CR_BAD_PARAM_ERROR); -+ -+ if (!a_this) -+ return CR_VALUE_NOT_FOUND_ERROR; -+ -+ g_return_val_if_fail (PRIVATE (a_this), CR_BAD_PARAM_ERROR); -+ -+ for (cur = a_this; cur; cur = PRIVATE (cur)->next) { -+ if (PRIVATE (cur)->prop -+ && PRIVATE (cur)->prop->stryng -+ && PRIVATE (cur)->prop->stryng->str -+ && a_prop->stryng -+ && a_prop->stryng->str -+ && !strcmp (PRIVATE (cur)->prop->stryng->str, -+ a_prop->stryng->str)) -+ break; -+ } -+ -+ if (cur) { -+ *a_pair = cur; -+ return CR_OK; -+ } -+ -+ return CR_VALUE_NOT_FOUND_ERROR; -+} -+ -+/** -+ * cr_prop_list_get_next: -+ *@a_this: the current instance of CRPropList -+ * -+ *Gets the next prop/decl pair in the list -+ * -+ *Returns the next prop/declaration pair of the list, -+ *or NULL if we reached end of list (or if an error occurs) -+ */ -+CRPropList * -+cr_prop_list_get_next (CRPropList * a_this) -+{ -+ g_return_val_if_fail (a_this && PRIVATE (a_this), NULL); -+ -+ return PRIVATE (a_this)->next; -+} -+ -+/** -+ * cr_prop_list_get_prev: -+ *@a_this: the current instance of CRPropList -+ * -+ *Gets the previous prop/decl pair in the list -+ * -+ *Returns the previous prop/declaration pair of the list, -+ *or NULL if we reached end of list (or if an error occurs) -+ */ -+CRPropList * -+cr_prop_list_get_prev (CRPropList * a_this) -+{ -+ g_return_val_if_fail (a_this && PRIVATE (a_this), NULL); -+ -+ return PRIVATE (a_this)->prev; -+} -+ -+/** -+ * cr_prop_list_unlink: -+ *@a_this: the current list of prop/decl pairs -+ *@a_pair: the prop/decl pair to unlink. -+ * -+ *Unlinks a prop/decl pair from the list -+ * -+ *Returns the new list or NULL in case of an error. -+ */ -+CRPropList * -+cr_prop_list_unlink (CRPropList * a_this, CRPropList * a_pair) -+{ -+ CRPropList *prev = NULL, -+ *next = NULL; -+ -+ g_return_val_if_fail (a_this && PRIVATE (a_this) && a_pair, NULL); -+ -+ /*some sanity checks */ -+ if (PRIVATE (a_pair)->next) { -+ next = PRIVATE (a_pair)->next; -+ g_return_val_if_fail (PRIVATE (next), NULL); -+ g_return_val_if_fail (PRIVATE (next)->prev == a_pair, NULL); -+ } -+ if (PRIVATE (a_pair)->prev) { -+ prev = PRIVATE (a_pair)->prev; -+ g_return_val_if_fail (PRIVATE (prev), NULL); -+ g_return_val_if_fail (PRIVATE (prev)->next == a_pair, NULL); -+ } -+ if (prev) { -+ PRIVATE (prev)->next = next; -+ } -+ if (next) { -+ PRIVATE (next)->prev = prev; -+ } -+ PRIVATE (a_pair)->prev = PRIVATE (a_pair)->next = NULL; -+ if (a_this == a_pair) { -+ if (next) -+ return next; -+ return NULL; -+ } -+ return a_this; -+} -+ -+/** -+ * cr_prop_list_destroy: -+ * @a_this: the current instance of #CRPropList -+ */ -+void -+cr_prop_list_destroy (CRPropList * a_this) -+{ -+ CRPropList *tail = NULL, -+ *cur = NULL; -+ -+ g_return_if_fail (a_this && PRIVATE (a_this)); -+ -+ for (tail = a_this; -+ tail && PRIVATE (tail) && PRIVATE (tail)->next; -+ tail = cr_prop_list_get_next (tail)) ; -+ g_return_if_fail (tail); -+ -+ cur = tail; -+ -+ while (cur) { -+ tail = PRIVATE (cur)->prev; -+ if (tail && PRIVATE (tail)) -+ PRIVATE (tail)->next = NULL; -+ PRIVATE (cur)->prev = NULL; -+ g_free (PRIVATE (cur)); -+ PRIVATE (cur) = NULL; -+ g_free (cur); -+ cur = tail; -+ } -+} -diff --git a/src/st/croco/cr-prop-list.h b/src/st/croco/cr-prop-list.h -new file mode 100644 -index 000000000..797ba43ea ---- /dev/null -+++ b/src/st/croco/cr-prop-list.h -@@ -0,0 +1,80 @@ -+/* -+ * This file is part of The Croco Library -+ * -+ * 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 -+ * See COPYRIGHTS file for copyrights information. -+ */ -+ -+#ifndef __CR_PROP_LIST_H__ -+#define __CR_PROP_LIST_H__ -+ -+#include "cr-utils.h" -+#include "cr-declaration.h" -+#include "cr-string.h" -+ -+G_BEGIN_DECLS -+ -+typedef struct _CRPropList CRPropList ; -+typedef struct _CRPropListPriv CRPropListPriv ; -+ -+struct _CRPropList -+{ -+ CRPropListPriv * priv; -+} ; -+ -+CRPropList * cr_prop_list_append (CRPropList *a_this, -+ CRPropList *a_to_append) ; -+ -+CRPropList * cr_prop_list_append2 (CRPropList *a_this, -+ CRString *a_prop, -+ CRDeclaration *a_decl) ; -+ -+CRPropList * cr_prop_list_prepend (CRPropList *a_this, -+ CRPropList *a_to_append) ; -+ -+CRPropList * cr_prop_list_prepend2 (CRPropList *a_this, -+ CRString *a_prop, -+ CRDeclaration *a_decl) ; -+ -+enum CRStatus cr_prop_list_set_prop (CRPropList *a_this, -+ CRString *a_prop) ; -+ -+enum CRStatus cr_prop_list_get_prop (CRPropList const *a_this, -+ CRString **a_prop) ; -+ -+enum CRStatus cr_prop_list_lookup_prop (CRPropList *a_this, -+ CRString *a_prop, -+ CRPropList**a_pair) ; -+ -+CRPropList * cr_prop_list_get_next (CRPropList *a_this) ; -+ -+CRPropList * cr_prop_list_get_prev (CRPropList *a_this) ; -+ -+enum CRStatus cr_prop_list_set_decl (CRPropList *a_this, -+ CRDeclaration *a_decl); -+ -+enum CRStatus cr_prop_list_get_decl (CRPropList const *a_this, -+ CRDeclaration **a_decl) ; -+ -+CRPropList * cr_prop_list_unlink (CRPropList *a_this, -+ CRPropList *a_pair) ; -+ -+void cr_prop_list_destroy (CRPropList *a_this) ; -+ -+G_END_DECLS -+ -+#endif /*__CR_PROP_LIST_H__*/ -diff --git a/src/st/croco/cr-pseudo.c b/src/st/croco/cr-pseudo.c -new file mode 100644 -index 000000000..cee3fc869 ---- /dev/null -+++ b/src/st/croco/cr-pseudo.c -@@ -0,0 +1,167 @@ -+/* -*- Mode: C; indent-tabs-mode:nil; c-basic-offset: 8-*- */ -+ -+/* -+ * This file is part of The Croco Library -+ * -+ * 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 -+ * See COPYRIGHTS file for copyright information. -+ */ -+ -+#include "cr-pseudo.h" -+ -+/** -+ *@CRPseudo: -+ *The definition of the #CRPseudo class. -+ */ -+ -+/** -+ * cr_pseudo_new: -+ *Constructor of the #CRPseudo class. -+ * -+ *Returns the newly build instance. -+ */ -+CRPseudo * -+cr_pseudo_new (void) -+{ -+ CRPseudo *result = NULL; -+ -+ result = g_malloc0 (sizeof (CRPseudo)); -+ -+ return result; -+} -+ -+/** -+ * cr_pseudo_to_string: -+ * @a_this: the current instance of #CRPseud. -+ * -+ * Returns the serialized pseudo. Caller must free the returned -+ * string using g_free(). -+ */ -+guchar * -+cr_pseudo_to_string (CRPseudo const * a_this) -+{ -+ guchar *result = NULL; -+ GString *str_buf = NULL; -+ -+ g_return_val_if_fail (a_this, NULL); -+ -+ str_buf = g_string_new (NULL); -+ -+ if (a_this->type == IDENT_PSEUDO) { -+ guchar *name = NULL; -+ -+ if (a_this->name == NULL) { -+ goto error; -+ } -+ -+ name = (guchar *) g_strndup (a_this->name->stryng->str, -+ a_this->name->stryng->len); -+ -+ if (name) { -+ g_string_append (str_buf, (const gchar *) name); -+ g_free (name); -+ name = NULL; -+ } -+ } else if (a_this->type == FUNCTION_PSEUDO) { -+ guchar *name = NULL, -+ *arg = NULL; -+ -+ if (a_this->name == NULL) -+ goto error; -+ -+ name = (guchar *) g_strndup (a_this->name->stryng->str, -+ a_this->name->stryng->len); -+ -+ if (a_this->extra) { -+ arg = (guchar *) g_strndup (a_this->extra->stryng->str, -+ a_this->extra->stryng->len); -+ } -+ -+ if (name) { -+ g_string_append_printf (str_buf, "%s(", name); -+ g_free (name); -+ name = NULL; -+ -+ if (arg) { -+ g_string_append (str_buf, (const gchar *) arg); -+ g_free (arg); -+ arg = NULL; -+ } -+ -+ g_string_append_c (str_buf, ')'); -+ } -+ } -+ -+ if (str_buf) { -+ result = (guchar *) str_buf->str; -+ g_string_free (str_buf, FALSE); -+ str_buf = NULL; -+ } -+ -+ return result; -+ -+ error: -+ g_string_free (str_buf, TRUE); -+ return NULL; -+} -+ -+/** -+ * cr_pseudo_dump: -+ *@a_this: the current instance of pseudo -+ *@a_fp: the destination file pointer. -+ * -+ *Dumps the pseudo to a file. -+ * -+ */ -+void -+cr_pseudo_dump (CRPseudo const * a_this, FILE * a_fp) -+{ -+ guchar *tmp_str = NULL; -+ -+ if (a_this) { -+ tmp_str = cr_pseudo_to_string (a_this); -+ if (tmp_str) { -+ fprintf (a_fp, "%s", tmp_str); -+ g_free (tmp_str); -+ tmp_str = NULL; -+ } -+ } -+} -+ -+/** -+ * cr_pseudo_destroy: -+ *@a_this: the current instance to destroy. -+ * -+ *destructor of the #CRPseudo class. -+ */ -+void -+cr_pseudo_destroy (CRPseudo * a_this) -+{ -+ g_return_if_fail (a_this); -+ -+ if (a_this->name) { -+ cr_string_destroy (a_this->name); -+ a_this->name = NULL; -+ } -+ -+ if (a_this->extra) { -+ cr_string_destroy (a_this->extra); -+ a_this->extra = NULL; -+ } -+ -+ g_free (a_this); -+} -diff --git a/src/st/croco/cr-pseudo.h b/src/st/croco/cr-pseudo.h -new file mode 100644 -index 000000000..8917da45e ---- /dev/null -+++ b/src/st/croco/cr-pseudo.h -@@ -0,0 +1,64 @@ -+/* -*- Mode: C; indent-tabs-mode:nil; c-basic-offset: 8-*- */ -+ -+/* -+ * This file is part of The Croco Library -+ * -+ * 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 -+ * -+ * See COPYRIGHTS file for copyright information -+ */ -+ -+#ifndef __CR_PSEUDO_H__ -+#define __CR_PSEUDO_H__ -+ -+#include -+#include -+#include "cr-attr-sel.h" -+#include "cr-parsing-location.h" -+ -+G_BEGIN_DECLS -+ -+enum CRPseudoType -+{ -+ IDENT_PSEUDO = 0, -+ FUNCTION_PSEUDO -+} ; -+ -+typedef struct _CRPseudo CRPseudo ; -+ -+/** -+ *The CRPseudo Class. -+ *Abstract a "pseudo" as defined by the css2 spec -+ *in appendix D.1 . -+ */ -+struct _CRPseudo -+{ -+ enum CRPseudoType type ; -+ CRString *name ; -+ CRString *extra ; -+ CRParsingLocation location ; -+} ; -+ -+CRPseudo * cr_pseudo_new (void) ; -+ -+guchar * cr_pseudo_to_string (CRPseudo const *a_this) ; -+ -+void cr_pseudo_dump (CRPseudo const *a_this, FILE *a_fp) ; -+ -+void cr_pseudo_destroy (CRPseudo *a_this) ; -+ -+G_END_DECLS -+ -+#endif /*__CR_PSEUDO_H__*/ -diff --git a/src/st/croco/cr-rgb.c b/src/st/croco/cr-rgb.c -new file mode 100644 -index 000000000..1b8b66256 ---- /dev/null -+++ b/src/st/croco/cr-rgb.c -@@ -0,0 +1,687 @@ -+/* -*- Mode: C; indent-tabs-mode:nil; c-basic-offset: 8-*- */ -+ -+/* -+ * This file is part of The Croco Library -+ * -+ * 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 -+ * See COPYRIGHTS file for copyrights information. -+ */ -+ -+#include "config.h" -+ -+#include -+#include -+#include -+#include "cr-rgb.h" -+#include "cr-term.h" -+#include "cr-parser.h" -+ -+static const CRRgb gv_standard_colors[] = { -+ {(const guchar*)"aliceblue", 240, 248, 255, FALSE, FALSE, FALSE, {0,0,0}}, -+ {(const guchar*)"antiquewhite", 250, 235, 215, FALSE, FALSE, FALSE, {0,0,0}}, -+ {(const guchar*)"aqua", 0, 255, 255, FALSE, FALSE, FALSE, {0,0,0}}, -+ {(const guchar*)"aquamarine", 127, 255, 212, FALSE, FALSE, FALSE, {0,0,0}}, -+ {(const guchar*)"azure", 240, 255, 255, FALSE, FALSE, FALSE, {0,0,0}}, -+ {(const guchar*)"beige", 245, 245, 220, FALSE, FALSE, FALSE, {0,0,0}}, -+ {(const guchar*)"bisque", 255, 228, 196, FALSE, FALSE, FALSE, {0,0,0}}, -+ {(const guchar*)"black", 0, 0, 0, FALSE, FALSE, FALSE, {0,0,0}}, -+ {(const guchar*)"blanchedalmond", 255, 235, 205, FALSE, FALSE, FALSE, {0,0,0}}, -+ {(const guchar*)"blue", 0, 0, 255, FALSE, FALSE, FALSE, {0,0,0}}, -+ {(const guchar*)"blueviolet", 138, 43, 226, FALSE, FALSE, FALSE, {0,0,0}}, -+ {(const guchar*)"brown", 165, 42, 42, FALSE, FALSE, FALSE, {0,0,0}}, -+ {(const guchar*)"burlywood", 222, 184, 135, FALSE, FALSE, FALSE, {0,0,0}}, -+ {(const guchar*)"cadetblue", 95, 158, 160, FALSE, FALSE, FALSE, {0,0,0}}, -+ {(const guchar*)"chartreuse", 127, 255, 0, FALSE, FALSE, FALSE, {0,0,0}}, -+ {(const guchar*)"chocolate", 210, 105, 30, FALSE, FALSE, FALSE, {0,0,0}}, -+ {(const guchar*)"coral", 255, 127, 80, FALSE, FALSE, FALSE, {0,0,0}}, -+ {(const guchar*)"cornflowerblue", 100, 149, 237, FALSE, FALSE, FALSE, {0,0,0}}, -+ {(const guchar*)"cornsilk", 255, 248, 220, FALSE, FALSE, FALSE, {0,0,0}}, -+ {(const guchar*)"crimson", 220, 20, 60, FALSE, FALSE, FALSE, {0,0,0}}, -+ {(const guchar*)"cyan", 0, 255, 255, FALSE, FALSE, FALSE, {0,0,0}}, -+ {(const guchar*)"darkblue", 0, 0, 139, FALSE, FALSE, FALSE, {0,0,0}}, -+ {(const guchar*)"darkcyan", 0, 139, 139, FALSE, FALSE, FALSE, {0,0,0}}, -+ {(const guchar*)"darkgoldenrod", 184, 134, 11, FALSE, FALSE, FALSE, {0,0,0}}, -+ {(const guchar*)"darkgray", 169, 169, 169, FALSE, FALSE, FALSE, {0,0,0}}, -+ {(const guchar*)"darkgreen", 0, 100, 0, FALSE, FALSE, FALSE, {0,0,0}}, -+ {(const guchar*)"darkgrey", 169, 169, 169, FALSE, FALSE, FALSE, {0,0,0}}, -+ {(const guchar*)"darkkhaki", 189, 183, 107, FALSE, FALSE, FALSE, {0,0,0}}, -+ {(const guchar*)"darkmagenta", 139, 0, 139, FALSE, FALSE, FALSE, {0,0,0}}, -+ {(const guchar*)"darkolivegreen", 85, 107, 47, FALSE, FALSE, FALSE, {0,0,0}}, -+ {(const guchar*)"darkorange", 255, 140, 0, FALSE, FALSE, FALSE, {0,0,0}}, -+ {(const guchar*)"darkorchid", 153, 50, 204, FALSE, FALSE, FALSE, {0,0,0}}, -+ {(const guchar*)"darkred", 139, 0, 0, FALSE, FALSE, FALSE, {0,0,0}}, -+ {(const guchar*)"darksalmon", 233, 150, 122, FALSE, FALSE, FALSE, {0,0,0}}, -+ {(const guchar*)"darkseagreen", 143, 188, 143, FALSE, FALSE, FALSE, {0,0,0}}, -+ {(const guchar*)"darkslateblue", 72, 61, 139, FALSE, FALSE, FALSE, {0,0,0}}, -+ {(const guchar*)"darkslategray", 47, 79, 79, FALSE, FALSE, FALSE, {0,0,0}}, -+ {(const guchar*)"darkslategrey", 47, 79, 79, FALSE, FALSE, FALSE, {0,0,0}}, -+ {(const guchar*)"darkturquoise", 0, 206, 209, FALSE, FALSE, FALSE, {0,0,0}}, -+ {(const guchar*)"darkviolet", 148, 0, 211, FALSE, FALSE, FALSE, {0,0,0}}, -+ {(const guchar*)"deeppink", 255, 20, 147, FALSE, FALSE, FALSE, {0,0,0}}, -+ {(const guchar*)"deepskyblue", 0, 191, 255, FALSE, FALSE, FALSE, {0,0,0}}, -+ {(const guchar*)"dimgray", 105, 105, 105, FALSE, FALSE, FALSE, {0,0,0}}, -+ {(const guchar*)"dimgrey", 105, 105, 105, FALSE, FALSE, FALSE, {0,0,0}}, -+ {(const guchar*)"dodgerblue", 30, 144, 255, FALSE, FALSE, FALSE, {0,0,0}}, -+ {(const guchar*)"firebrick", 178, 34, 34, FALSE, FALSE, FALSE, {0,0,0}}, -+ {(const guchar*)"floralwhite", 255, 250, 240, FALSE, FALSE, FALSE, {0,0,0}}, -+ {(const guchar*)"forestgreen", 34, 139, 34, FALSE, FALSE, FALSE, {0,0,0}}, -+ {(const guchar*)"fuchsia", 255, 0, 255, FALSE, FALSE, FALSE, {0,0,0}}, -+ {(const guchar*)"gainsboro", 220, 220, 220, FALSE, FALSE, FALSE, {0,0,0}}, -+ {(const guchar*)"ghostwhite", 248, 248, 255, FALSE, FALSE, FALSE, {0,0,0}}, -+ {(const guchar*)"gold", 255, 215, 0, FALSE, FALSE, FALSE, {0,0,0}}, -+ {(const guchar*)"goldenrod", 218, 165, 32, FALSE, FALSE, FALSE, {0,0,0}}, -+ {(const guchar*)"gray", 128, 128, 128, FALSE, FALSE, FALSE, {0,0,0}}, -+ {(const guchar*)"green", 0, 128, 0, FALSE, FALSE, FALSE, {0,0,0}}, -+ {(const guchar*)"greenyellow", 173, 255, 47, FALSE, FALSE, FALSE, {0,0,0}}, -+ {(const guchar*)"grey", 128, 128, 128, FALSE, FALSE, FALSE, {0,0,0}}, -+ {(const guchar*)"honeydew", 240, 255, 240, FALSE, FALSE, FALSE, {0,0,0}}, -+ {(const guchar*)"hotpink", 255, 105, 180, FALSE, FALSE, FALSE, {0,0,0}}, -+ {(const guchar*)"indianred", 205, 92, 92, FALSE, FALSE, FALSE, {0,0,0}}, -+ {(const guchar*)"indigo", 75, 0, 130, FALSE, FALSE, FALSE, {0,0,0}}, -+ {(const guchar*)"ivory", 255, 255, 240, FALSE, FALSE, FALSE, {0,0,0}}, -+ {(const guchar*)"khaki", 240, 230, 140, FALSE, FALSE, FALSE, {0,0,0}}, -+ {(const guchar*)"lavender", 230, 230, 250, FALSE, FALSE, FALSE, {0,0,0}}, -+ {(const guchar*)"lavenderblush", 255, 240, 245, FALSE, FALSE, FALSE, {0,0,0}}, -+ {(const guchar*)"lawngreen", 124, 252, 0, FALSE, FALSE, FALSE, {0,0,0}}, -+ {(const guchar*)"lemonchiffon", 255, 250, 205, FALSE, FALSE, FALSE, {0,0,0}}, -+ {(const guchar*)"lightblue", 173, 216, 230, FALSE, FALSE, FALSE, {0,0,0}}, -+ {(const guchar*)"lightcoral", 240, 128, 128, FALSE, FALSE, FALSE, {0,0,0}}, -+ {(const guchar*)"lightcyan", 224, 255, 255, FALSE, FALSE, FALSE, {0,0,0}}, -+ {(const guchar*)"lightgoldenrodyellow", 250, 250, 210, FALSE, FALSE, FALSE, {0,0,0}}, -+ {(const guchar*)"lightgray", 211, 211, 211, FALSE, FALSE, FALSE, {0,0,0}}, -+ {(const guchar*)"lightgreen", 144, 238, 144, FALSE, FALSE, FALSE, {0,0,0}}, -+ {(const guchar*)"lightgrey", 211, 211, 211, FALSE, FALSE, FALSE, {0,0,0}}, -+ {(const guchar*)"lightpink", 255, 182, 193, FALSE, FALSE, FALSE, {0,0,0}}, -+ {(const guchar*)"lightsalmon", 255, 160, 122, FALSE, FALSE, FALSE, {0,0,0}}, -+ {(const guchar*)"lightseagreen", 32, 178, 170, FALSE, FALSE, FALSE, {0,0,0}}, -+ {(const guchar*)"lightskyblue", 135, 206, 250, FALSE, FALSE, FALSE, {0,0,0}}, -+ {(const guchar*)"lightslategray", 119, 136, 153, FALSE, FALSE, FALSE, {0,0,0}}, -+ {(const guchar*)"lightslategrey", 119, 136, 153, FALSE, FALSE, FALSE, {0,0,0}}, -+ {(const guchar*)"lightsteelblue", 176, 196, 222, FALSE, FALSE, FALSE, {0,0,0}}, -+ {(const guchar*)"lightyellow", 255, 255, 224, FALSE, FALSE, FALSE, {0,0,0}}, -+ {(const guchar*)"lime", 0, 255, 0, FALSE, FALSE, FALSE, {0,0,0}}, -+ {(const guchar*)"limegreen", 50, 205, 50, FALSE, FALSE, FALSE, {0,0,0}}, -+ {(const guchar*)"linen", 250, 240, 230, FALSE, FALSE, FALSE, {0,0,0}}, -+ {(const guchar*)"magenta", 255, 0, 255, FALSE, FALSE, FALSE, {0,0,0}}, -+ {(const guchar*)"maroon", 128, 0, 0, FALSE, FALSE, FALSE, {0,0,0}}, -+ {(const guchar*)"mediumaquamarine", 102, 205, 170, FALSE, FALSE, FALSE, {0,0,0}}, -+ {(const guchar*)"mediumblue", 0, 0, 205, FALSE, FALSE, FALSE, {0,0,0}}, -+ {(const guchar*)"mediumorchid", 186, 85, 211, FALSE, FALSE, FALSE, {0,0,0}}, -+ {(const guchar*)"mediumpurple", 147, 112, 219, FALSE, FALSE, FALSE, {0,0,0}}, -+ {(const guchar*)"mediumseagreen", 60, 179, 113, FALSE, FALSE, FALSE, {0,0,0}}, -+ {(const guchar*)"mediumslateblue", 123, 104, 238, FALSE, FALSE, FALSE, {0,0,0}}, -+ {(const guchar*)"mediumspringgreen", 0, 250, 154, FALSE, FALSE, FALSE, {0,0,0}}, -+ {(const guchar*)"mediumturquoise", 72, 209, 204, FALSE, FALSE, FALSE, {0,0,0}}, -+ {(const guchar*)"mediumvioletred", 199, 21, 133, FALSE, FALSE, FALSE, {0,0,0}}, -+ {(const guchar*)"midnightblue", 25, 25, 112, FALSE, FALSE, FALSE, {0,0,0}}, -+ {(const guchar*)"mintcream", 245, 255, 250, FALSE, FALSE, FALSE, {0,0,0}}, -+ {(const guchar*)"mistyrose", 255, 228, 225, FALSE, FALSE, FALSE, {0,0,0}}, -+ {(const guchar*)"moccasin", 255, 228, 181, FALSE, FALSE, FALSE, {0,0,0}}, -+ {(const guchar*)"navajowhite", 255, 222, 173, FALSE, FALSE, FALSE, {0,0,0}}, -+ {(const guchar*)"navy", 0, 0, 128, FALSE, FALSE, FALSE, {0,0,0}}, -+ {(const guchar*)"oldlace", 253, 245, 230, FALSE, FALSE, FALSE, {0,0,0}}, -+ {(const guchar*)"olive", 128, 128, 0, FALSE, FALSE, FALSE, {0,0,0}}, -+ {(const guchar*)"olivedrab", 107, 142, 35, FALSE, FALSE, FALSE, {0,0,0}}, -+ {(const guchar*)"orange", 255, 165, 0, FALSE, FALSE, FALSE, {0,0,0}}, -+ {(const guchar*)"orangered", 255, 69, 0, FALSE, FALSE, FALSE, {0,0,0}}, -+ {(const guchar*)"orchid", 218, 112, 214, FALSE, FALSE, FALSE, {0,0,0}}, -+ {(const guchar*)"palegoldenrod", 238, 232, 170, FALSE, FALSE, FALSE, {0,0,0}}, -+ {(const guchar*)"palegreen", 152, 251, 152, FALSE, FALSE, FALSE, {0,0,0}}, -+ {(const guchar*)"paleturquoise", 175, 238, 238, FALSE, FALSE, FALSE, {0,0,0}}, -+ {(const guchar*)"palevioletred", 219, 112, 147, FALSE, FALSE, FALSE, {0,0,0}}, -+ {(const guchar*)"papayawhip", 255, 239, 213, FALSE, FALSE, FALSE, {0,0,0}}, -+ {(const guchar*)"peachpuff", 255, 218, 185, FALSE, FALSE, FALSE, {0,0,0}}, -+ {(const guchar*)"peru", 205, 133, 63, FALSE, FALSE, FALSE, {0,0,0}}, -+ {(const guchar*)"pink", 255, 192, 203, FALSE, FALSE, FALSE, {0,0,0}}, -+ {(const guchar*)"plum", 221, 160, 221, FALSE, FALSE, FALSE, {0,0,0}}, -+ {(const guchar*)"powderblue", 176, 224, 230, FALSE, FALSE, FALSE, {0,0,0}}, -+ {(const guchar*)"purple", 128, 0, 128, FALSE, FALSE, FALSE, {0,0,0}}, -+ {(const guchar*)"red", 255, 0, 0, FALSE, FALSE, FALSE, {0,0,0}}, -+ {(const guchar*)"rosybrown", 188, 143, 143, FALSE, FALSE, FALSE, {0,0,0}}, -+ {(const guchar*)"royalblue", 65, 105, 225, FALSE, FALSE, FALSE, {0,0,0}}, -+ {(const guchar*)"saddlebrown", 139, 69, 19, FALSE, FALSE, FALSE, {0,0,0}}, -+ {(const guchar*)"salmon", 250, 128, 114, FALSE, FALSE, FALSE, {0,0,0}}, -+ {(const guchar*)"sandybrown", 244, 164, 96, FALSE, FALSE, FALSE, {0,0,0}}, -+ {(const guchar*)"seagreen", 46, 139, 87, FALSE, FALSE, FALSE, {0,0,0}}, -+ {(const guchar*)"seashell", 255, 245, 238, FALSE, FALSE, FALSE, {0,0,0}}, -+ {(const guchar*)"sienna", 160, 82, 45, FALSE, FALSE, FALSE, {0,0,0}}, -+ {(const guchar*)"silver", 192, 192, 192, FALSE, FALSE, FALSE, {0,0,0}}, -+ {(const guchar*)"skyblue", 135, 206, 235, FALSE, FALSE, FALSE, {0,0,0}}, -+ {(const guchar*)"slateblue", 106, 90, 205, FALSE, FALSE, FALSE, {0,0,0}}, -+ {(const guchar*)"slategray", 112, 128, 144, FALSE, FALSE, FALSE, {0,0,0}}, -+ {(const guchar*)"slategrey", 112, 128, 144, FALSE, FALSE, FALSE, {0,0,0}}, -+ {(const guchar*)"snow", 255, 250, 250, FALSE, FALSE, FALSE, {0,0,0}}, -+ {(const guchar*)"springgreen", 0, 255, 127, FALSE, FALSE, FALSE, {0,0,0}}, -+ {(const guchar*)"steelblue", 70, 130, 180, FALSE, FALSE, FALSE, {0,0,0}}, -+ {(const guchar*)"tan", 210, 180, 140, FALSE, FALSE, FALSE, {0,0,0}}, -+ {(const guchar*)"teal", 0, 128, 128, FALSE, FALSE, FALSE, {0,0,0}}, -+ {(const guchar*)"thistle", 216, 191, 216, FALSE, FALSE, FALSE, {0,0,0}}, -+ {(const guchar*)"tomato", 255, 99, 71, FALSE, FALSE, FALSE, {0,0,0}}, -+ {(const guchar*)"transparent", 255, 255, 255, FALSE, FALSE, TRUE, {0,0,0}}, -+ {(const guchar*)"turquoise", 64, 224, 208, FALSE, FALSE, FALSE, {0,0,0}}, -+ {(const guchar*)"violet", 238, 130, 238, FALSE, FALSE, FALSE, {0,0,0}}, -+ {(const guchar*)"wheat", 245, 222, 179, FALSE, FALSE, FALSE, {0,0,0}}, -+ {(const guchar*)"white", 255, 255, 255, FALSE, FALSE, FALSE, {0,0,0}}, -+ {(const guchar*)"whitesmoke", 245, 245, 245, FALSE, FALSE, FALSE, {0,0,0}}, -+ {(const guchar*)"yellow", 255, 255, 0, FALSE, FALSE, FALSE, {0,0,0}}, -+ {(const guchar*)"yellowgreen", 154, 205, 50, FALSE, FALSE, FALSE, {0,0,0}} -+}; -+ -+/** -+ * cr_rgb_new: -+ * -+ *The default constructor of #CRRgb. -+ * -+ *Returns the newly built instance of #CRRgb -+ */ -+CRRgb * -+cr_rgb_new (void) -+{ -+ CRRgb *result = NULL; -+ -+ result = g_try_malloc (sizeof (CRRgb)); -+ -+ if (result == NULL) { -+ cr_utils_trace_info ("No more memory"); -+ return NULL; -+ } -+ -+ memset (result, 0, sizeof (CRRgb)); -+ -+ return result; -+} -+ -+/** -+ * cr_rgb_new_with_vals: -+ *@a_red: the red component of the color. -+ *@a_green: the green component of the color. -+ *@a_blue: the blue component of the color. -+ *@a_unit: the unit of the rgb values. -+ *(either percentage or integer values) -+ * -+ *A constructor of #CRRgb. -+ * -+ *Returns the newly built instance of #CRRgb. -+ */ -+CRRgb * -+cr_rgb_new_with_vals (gulong a_red, gulong a_green, -+ gulong a_blue, gboolean a_is_percentage) -+{ -+ CRRgb *result = NULL; -+ -+ result = cr_rgb_new (); -+ -+ g_return_val_if_fail (result, NULL); -+ -+ result->red = a_red; -+ result->green = a_green; -+ result->blue = a_blue; -+ result->is_percentage = a_is_percentage; -+ -+ return result; -+} -+ -+/** -+ * cr_rgb_to_string: -+ *@a_this: the instance of #CRRgb to serialize. -+ * -+ *Serializes the rgb into a zero terminated string. -+ * -+ *Returns the zero terminated string containing the serialized -+ *rgb. MUST BE FREED by the caller using g_free(). -+ */ -+guchar * -+cr_rgb_to_string (CRRgb const * a_this) -+{ -+ guchar *result = NULL; -+ GString *str_buf = NULL; -+ -+ str_buf = g_string_new (NULL); -+ g_return_val_if_fail (str_buf, NULL); -+ -+ if (a_this->is_percentage == 1) { -+ g_string_append_printf (str_buf, "%ld", a_this->red); -+ -+ g_string_append (str_buf, "%, "); -+ -+ g_string_append_printf (str_buf, "%ld", a_this->green); -+ g_string_append (str_buf, "%, "); -+ -+ g_string_append_printf (str_buf, "%ld", a_this->blue); -+ g_string_append_c (str_buf, '%'); -+ } else { -+ g_string_append_printf (str_buf, "%ld", a_this->red); -+ g_string_append (str_buf, ", "); -+ -+ g_string_append_printf (str_buf, "%ld", a_this->green); -+ g_string_append (str_buf, ", "); -+ -+ g_string_append_printf (str_buf, "%ld", a_this->blue); -+ } -+ -+ if (str_buf) { -+ result = (guchar *) str_buf->str; -+ g_string_free (str_buf, FALSE); -+ } -+ -+ return result; -+} -+ -+/** -+ * cr_rgb_dump: -+ *@a_this: the "this pointer" of -+ *the current instance of #CRRgb. -+ *@a_fp: the destination file pointer. -+ * -+ *Dumps the current instance of #CRRgb -+ *to a file. -+ */ -+void -+cr_rgb_dump (CRRgb const * a_this, FILE * a_fp) -+{ -+ guchar *str = NULL; -+ -+ g_return_if_fail (a_this); -+ -+ str = cr_rgb_to_string (a_this); -+ -+ if (str) { -+ fprintf (a_fp, "%s", str); -+ g_free (str); -+ str = NULL; -+ } -+} -+ -+/** -+ * cr_rgb_compute_from_percentage: -+ *@a_this: the current instance of #CRRgb -+ * -+ *If the rgb values are expressed in percentage, -+ *compute their real value. -+ * -+ *Returns CR_OK upon successful completion, an error code otherwise. -+ */ -+enum CRStatus -+cr_rgb_compute_from_percentage (CRRgb * a_this) -+{ -+ g_return_val_if_fail (a_this, CR_BAD_PARAM_ERROR); -+ -+ if (a_this->is_percentage == FALSE) -+ return CR_OK; -+ a_this->red = a_this->red * 255 / 100; -+ a_this->green = a_this->green * 255 / 100; -+ a_this->blue = a_this->blue * 255 / 100; -+ a_this->is_percentage = FALSE; -+ return CR_OK; -+} -+ -+/** -+ * cr_rgb_set: -+ *@a_this: the current instance of #CRRgb. -+ *@a_red: the red value. -+ *@a_green: the green value. -+ *@a_blue: the blue value. -+ * -+ *Sets rgb values to the RGB. -+ * -+ *Returns CR_OK upon successful completion, an error code -+ *otherwise. -+ */ -+enum CRStatus -+cr_rgb_set (CRRgb * a_this, gulong a_red, -+ gulong a_green, gulong a_blue, gboolean a_is_percentage) -+{ -+ g_return_val_if_fail (a_this, CR_BAD_PARAM_ERROR); -+ if (a_is_percentage != FALSE) { -+ g_return_val_if_fail (a_red <= 100 -+ && a_green <= 100 -+ && a_blue <= 100, CR_BAD_PARAM_ERROR); -+ } -+ -+ a_this->is_percentage = a_is_percentage; -+ -+ a_this->red = a_red; -+ a_this->green = a_green; -+ a_this->blue = a_blue; -+ a_this->inherit = FALSE ; -+ a_this->is_transparent = FALSE ; -+ return CR_OK; -+} -+ -+/** -+ * cr_rgb_set_to_inherit: -+ *@a_this: the current instance of #CRRgb -+ * -+ *sets the value of the rgb to inherit. -+ *Look at the css spec from chapter 6.1 to 6.2 to understand -+ *the meaning of "inherit". -+ * -+ * Returns CR_OK upon succesful completion, an error code otherwise. -+ */ -+enum CRStatus -+cr_rgb_set_to_inherit (CRRgb *a_this, gboolean a_inherit) -+{ -+ g_return_val_if_fail (a_this, CR_BAD_PARAM_ERROR) ; -+ -+ a_this->inherit = a_inherit ; -+ -+ return CR_OK ; -+} -+ -+/** -+ * cr_rgb_is_set_to_inherit: -+ * -+ * @a_this: the current instance of #CRRgb. -+ * -+ * Returns TRUE if the rgb is set to the value "inherit", FALSE otherwise. -+ */ -+gboolean -+cr_rgb_is_set_to_inherit (CRRgb const *a_this) -+{ -+ g_return_val_if_fail (a_this, CR_BAD_PARAM_ERROR) ; -+ -+ return a_this->inherit ; -+} -+ -+/** -+ * cr_rgb_is_set_to_transparent: -+ *@a_this: the current instance of -+ *#CRRgb -+ * -+ *Tests if the the rgb is set to the -+ *value "transparent" or not. -+ * -+ *Returns TRUE if the rgb has been set to -+ *transparent, FALSE otherwise. -+ */ -+gboolean -+cr_rgb_is_set_to_transparent (CRRgb const *a_this) -+{ -+ g_return_val_if_fail (a_this, FALSE) ; -+ return a_this->is_transparent ; -+} -+ -+ -+/** -+ * cr_rgb_set_to_transparent: -+ *@a_this: the current instance of #CRRgb -+ *@a_is_transparent: set to transparent or not. -+ * -+ *Sets the rgb to the "transparent" value (or not) -+ *Returns CR_OK upon successfull completion, an error code otherwise. -+ */ -+enum CRStatus -+cr_rgb_set_to_transparent (CRRgb *a_this, -+ gboolean a_is_transparent) -+{ -+ g_return_val_if_fail (a_this, CR_BAD_PARAM_ERROR) ; -+ a_this->is_transparent = a_is_transparent ; -+ return CR_OK ; -+} -+ -+/** -+ * cr_rgb_set_from_rgb: -+ *@a_this: the current instance of #CRRgb. -+ *@a_rgb: the rgb to "copy" -+ * -+ *Sets the rgb from an other one. -+ * -+ *Returns CR_OK upon successful completion, an error code otherwise. -+ */ -+enum CRStatus -+cr_rgb_set_from_rgb (CRRgb * a_this, CRRgb const * a_rgb) -+{ -+ g_return_val_if_fail (a_this && a_rgb, CR_BAD_PARAM_ERROR); -+ -+ cr_rgb_copy (a_this, a_rgb) ; -+ -+ return CR_OK; -+} -+ -+static int -+cr_rgb_color_name_compare (const void *a, -+ const void *b) -+{ -+ const char *a_color_name = a; -+ const CRRgb *rgb = b; -+ -+ return g_ascii_strcasecmp (a_color_name, (const char *) rgb->name); -+} -+ -+/** -+ * cr_rgb_set_from_name: -+ * @a_this: the current instance of #CRRgb -+ * @a_color_name: the color name -+ * -+ * Returns CR_OK upon successful completion, an error code otherwise. -+ */ -+enum CRStatus -+cr_rgb_set_from_name (CRRgb * a_this, const guchar * a_color_name) -+{ -+ enum CRStatus status = CR_OK; -+ CRRgb *result; -+ -+ g_return_val_if_fail (a_this && a_color_name, CR_BAD_PARAM_ERROR); -+ -+ result = bsearch (a_color_name, -+ gv_standard_colors, -+ G_N_ELEMENTS (gv_standard_colors), -+ sizeof (gv_standard_colors[0]), -+ cr_rgb_color_name_compare); -+ if (result != NULL) -+ cr_rgb_set_from_rgb (a_this, result); -+ else -+ status = CR_UNKNOWN_TYPE_ERROR; -+ -+ return status; -+} -+ -+/** -+ * cr_rgb_set_from_hex_str: -+ * @a_this: the current instance of #CRRgb -+ * @a_hex: the hexadecimal value to set. -+ * -+ * Returns CR_OK upon successful completion. -+ */ -+enum CRStatus -+cr_rgb_set_from_hex_str (CRRgb * a_this, const guchar * a_hex) -+{ -+ enum CRStatus status = CR_OK; -+ gulong i = 0; -+ guchar colors[3] = { 0 }; -+ -+ g_return_val_if_fail (a_this && a_hex, CR_BAD_PARAM_ERROR); -+ -+ if (strlen ((const char *) a_hex) == 3) { -+ for (i = 0; i < 3; i++) { -+ if (a_hex[i] >= '0' && a_hex[i] <= '9') { -+ colors[i] = a_hex[i] - '0'; -+ colors[i] = (colors[i] << 4) | colors[i]; -+ } else if (a_hex[i] >= 'a' && a_hex[i] <= 'z') { -+ colors[i] = 10 + a_hex[i] - 'a'; -+ colors[i] = (colors[i] << 4) | colors[i]; -+ } else if (a_hex[i] >= 'A' && a_hex[i] <= 'Z') { -+ colors[i] = 10 + a_hex[i] - 'A'; -+ colors[i] = (colors[i] << 4) | colors[i]; -+ } else { -+ status = CR_UNKNOWN_TYPE_ERROR; -+ } -+ } -+ } else if (strlen ((const char *) a_hex) == 6) { -+ for (i = 0; i < 6; i++) { -+ if (a_hex[i] >= '0' && a_hex[i] <= '9') { -+ colors[i / 2] <<= 4; -+ colors[i / 2] |= a_hex[i] - '0'; -+ status = CR_OK; -+ } else if (a_hex[i] >= 'a' && a_hex[i] <= 'z') { -+ colors[i / 2] <<= 4; -+ colors[i / 2] |= 10 + a_hex[i] - 'a'; -+ status = CR_OK; -+ } else if (a_hex[i] >= 'A' && a_hex[i] <= 'Z') { -+ colors[i / 2] <<= 4; -+ colors[i / 2] |= 10 + a_hex[i] - 'A'; -+ status = CR_OK; -+ } else { -+ status = CR_UNKNOWN_TYPE_ERROR; -+ } -+ } -+ } else { -+ status = CR_UNKNOWN_TYPE_ERROR; -+ } -+ -+ if (status == CR_OK) { -+ status = cr_rgb_set (a_this, colors[0], -+ colors[1], colors[2], FALSE); -+ cr_rgb_set_to_transparent (a_this, FALSE) ; -+ } -+ return status; -+} -+ -+/** -+ * cr_rgb_set_from_term: -+ *@a_this: the instance of #CRRgb to set -+ *@a_value: the terminal from which to set -+ * -+ *Set the rgb from a terminal symbol -+ * -+ * Returns CR_OK upon successful completion, an error code otherwise. -+ */ -+enum CRStatus -+cr_rgb_set_from_term (CRRgb *a_this, const struct _CRTerm *a_value) -+{ -+ enum CRStatus status = CR_OK ; -+ g_return_val_if_fail (a_this && a_value, -+ CR_BAD_PARAM_ERROR) ; -+ -+ switch(a_value->type) { -+ case TERM_RGB: -+ if (a_value->content.rgb) { -+ cr_rgb_set_from_rgb -+ (a_this, a_value->content.rgb) ; -+ } -+ break ; -+ case TERM_IDENT: -+ if (a_value->content.str -+ && a_value->content.str->stryng -+ && a_value->content.str->stryng->str) { -+ if (!strncmp ("inherit", -+ a_value->content.str->stryng->str, -+ sizeof ("inherit")-1)) { -+ a_this->inherit = TRUE; -+ a_this->is_transparent = FALSE ; -+ } else { -+ status = cr_rgb_set_from_name -+ (a_this, -+ (const guchar *) a_value->content.str->stryng->str) ; -+ } -+ } else { -+ cr_utils_trace_info -+ ("a_value has NULL string value") ; -+ } -+ break ; -+ case TERM_HASH: -+ if (a_value->content.str -+ && a_value->content.str->stryng -+ && a_value->content.str->stryng->str) { -+ status = cr_rgb_set_from_hex_str -+ (a_this, -+ (const guchar *) a_value->content.str->stryng->str) ; -+ } else { -+ cr_utils_trace_info -+ ("a_value has NULL string value") ; -+ } -+ break ; -+ default: -+ status = CR_UNKNOWN_TYPE_ERROR ; -+ } -+ return status ; -+} -+ -+enum CRStatus -+cr_rgb_copy (CRRgb *a_dest, CRRgb const *a_src) -+{ -+ g_return_val_if_fail (a_dest && a_src, -+ CR_BAD_PARAM_ERROR) ; -+ -+ memcpy (a_dest, a_src, sizeof (CRRgb)) ; -+ return CR_OK ; -+} -+ -+/** -+ * cr_rgb_destroy: -+ *@a_this: the "this pointer" of the -+ *current instance of #CRRgb. -+ * -+ *Destructor of #CRRgb. -+ */ -+void -+cr_rgb_destroy (CRRgb * a_this) -+{ -+ g_return_if_fail (a_this); -+ g_free (a_this); -+} -+ -+/** -+ * cr_rgb_parse_from_buf: -+ *@a_str: a string that contains a color description -+ *@a_enc: the encoding of a_str -+ * -+ *Parses a text buffer that contains a rgb color -+ * -+ *Returns the parsed color, or NULL in case of error -+ */ -+CRRgb * -+cr_rgb_parse_from_buf (const guchar *a_str, -+ enum CREncoding a_enc) -+{ -+ enum CRStatus status = CR_OK ; -+ CRTerm *value = NULL ; -+ CRParser * parser = NULL; -+ CRRgb *result = NULL; -+ -+ g_return_val_if_fail (a_str, NULL); -+ -+ parser = cr_parser_new_from_buf ((guchar *) a_str, strlen ((const char *) a_str), a_enc, FALSE); -+ -+ g_return_val_if_fail (parser, NULL); -+ -+ status = cr_parser_try_to_skip_spaces_and_comments (parser) ; -+ if (status != CR_OK) -+ goto cleanup; -+ -+ status = cr_parser_parse_term (parser, &value); -+ if (status != CR_OK) -+ goto cleanup; -+ -+ result = cr_rgb_new (); -+ if (!result) -+ goto cleanup; -+ -+ status = cr_rgb_set_from_term (result, value); -+ -+cleanup: -+ if (parser) { -+ cr_parser_destroy (parser); -+ parser = NULL; -+ } -+ if (value) { -+ cr_term_destroy(value); -+ value = NULL; -+ } -+ return result ; -+} -+ -diff --git a/src/st/croco/cr-rgb.h b/src/st/croco/cr-rgb.h -new file mode 100644 -index 000000000..a127a440e ---- /dev/null -+++ b/src/st/croco/cr-rgb.h -@@ -0,0 +1,94 @@ -+/* -*- Mode: C; indent-tabs-mode:nil; c-basic-offset: 8-*- */ -+ -+/* -+ * This file is part of The Croco Library -+ * -+ * 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 -+ * -+ * see COPYRIGHTS file for copyright information. -+ */ -+ -+#ifndef __CR_RGB_H__ -+#define __CR_RGB_H__ -+ -+#include -+#include -+#include "cr-utils.h" -+#include "cr-parsing-location.h" -+ -+G_BEGIN_DECLS -+ -+ -+typedef struct _CRRgb CRRgb ; -+struct _CRRgb -+{ -+ /* -+ *the unit of the rgb. -+ *Either NO_UNIT (integer) or -+ *UNIT_PERCENTAGE (percentage). -+ */ -+ const guchar *name ; -+ glong red ; -+ glong green ; -+ glong blue ; -+ gboolean is_percentage ; -+ gboolean inherit ; -+ gboolean is_transparent ; -+ CRParsingLocation location ; -+} ; -+ -+CRRgb * cr_rgb_new (void) ; -+ -+CRRgb * cr_rgb_new_with_vals (gulong a_red, gulong a_green, -+ gulong a_blue, gboolean a_is_percentage) ; -+ -+CRRgb *cr_rgb_parse_from_buf(const guchar *a_str, -+ enum CREncoding a_enc); -+ -+enum CRStatus cr_rgb_compute_from_percentage (CRRgb *a_this) ; -+ -+enum CRStatus cr_rgb_set (CRRgb *a_this, gulong a_red, -+ gulong a_green, gulong a_blue, -+ gboolean a_is_percentage) ; -+ -+enum CRStatus cr_rgb_copy (CRRgb *a_dest, CRRgb const *a_src) ; -+ -+enum CRStatus cr_rgb_set_to_inherit (CRRgb *a_this, gboolean a_inherit) ; -+ -+gboolean cr_rgb_is_set_to_inherit (CRRgb const *a_this) ; -+ -+gboolean cr_rgb_is_set_to_transparent (CRRgb const *a_this) ; -+ -+enum CRStatus cr_rgb_set_to_transparent (CRRgb *a_this, -+ gboolean a_is_transparent) ; -+enum CRStatus cr_rgb_set_from_rgb (CRRgb *a_this, CRRgb const *a_rgb) ; -+ -+enum CRStatus cr_rgb_set_from_name (CRRgb *a_this, const guchar *a_color_name) ; -+ -+enum CRStatus cr_rgb_set_from_hex_str (CRRgb *a_this, const guchar * a_hex_value) ; -+ -+struct _CRTerm; -+ -+enum CRStatus cr_rgb_set_from_term (CRRgb *a_this, const struct _CRTerm *a_value); -+ -+guchar * cr_rgb_to_string (CRRgb const *a_this) ; -+ -+void cr_rgb_dump (CRRgb const *a_this, FILE *a_fp) ; -+ -+void cr_rgb_destroy (CRRgb *a_this) ; -+ -+G_END_DECLS -+ -+#endif /*__CR_RGB_H__*/ -diff --git a/src/st/croco/cr-selector.c b/src/st/croco/cr-selector.c -new file mode 100644 -index 000000000..8902e1c0f ---- /dev/null -+++ b/src/st/croco/cr-selector.c -@@ -0,0 +1,306 @@ -+/* -*- Mode: C; indent-tabs-mode: nil; c-basic-offset: 8 -*- */ -+ -+/* -+ * This file is part of The Croco Library -+ * -+ * 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 -+ * -+ * See COPYRIGHTS file for copyright information. -+ */ -+ -+#include -+#include "cr-selector.h" -+#include "cr-parser.h" -+ -+/** -+ * cr_selector_new: -+ * -+ *@a_simple_sel: the initial simple selector list -+ *of the current instance of #CRSelector. -+ * -+ *Creates a new instance of #CRSelector. -+ * -+ *Returns the newly built instance of #CRSelector, or -+ *NULL in case of failure. -+ */ -+CRSelector * -+cr_selector_new (CRSimpleSel * a_simple_sel) -+{ -+ CRSelector *result = NULL; -+ -+ result = g_try_malloc (sizeof (CRSelector)); -+ if (!result) { -+ cr_utils_trace_info ("Out of memory"); -+ return NULL; -+ } -+ memset (result, 0, sizeof (CRSelector)); -+ result->simple_sel = a_simple_sel; -+ return result; -+} -+ -+CRSelector * -+cr_selector_parse_from_buf (const guchar * a_char_buf, enum CREncoding a_enc) -+{ -+ CRParser *parser = NULL; -+ -+ g_return_val_if_fail (a_char_buf, NULL); -+ -+ parser = cr_parser_new_from_buf ((guchar*)a_char_buf, strlen ((const char *) a_char_buf), -+ a_enc, FALSE); -+ g_return_val_if_fail (parser, NULL); -+ -+ return NULL; -+} -+ -+/** -+ * cr_selector_append: -+ * -+ *@a_this: the current instance of #CRSelector. -+ *@a_new: the instance of #CRSelector to be appended. -+ * -+ *Appends a new instance of #CRSelector to the current selector list. -+ * -+ *Returns the new list. -+ */ -+CRSelector * -+cr_selector_append (CRSelector * a_this, CRSelector * a_new) -+{ -+ CRSelector *cur = NULL; -+ -+ if (!a_this) { -+ return a_new; -+ } -+ -+ /*walk forward the list headed by a_this to get the list tail */ -+ for (cur = a_this; cur && cur->next; cur = cur->next) ; -+ -+ cur->next = a_new; -+ a_new->prev = cur; -+ -+ return a_this; -+} -+ -+/** -+ * cr_selector_prepend: -+ * -+ *@a_this: the current instance of #CRSelector list. -+ *@a_new: the instance of #CRSelector. -+ * -+ *Prepends an element to the #CRSelector list. -+ * -+ *Returns the new list. -+ */ -+CRSelector * -+cr_selector_prepend (CRSelector * a_this, CRSelector * a_new) -+{ -+ CRSelector *cur = NULL; -+ -+ a_new->next = a_this; -+ a_this->prev = a_new; -+ -+ for (cur = a_new; cur && cur->prev; cur = cur->prev) ; -+ -+ return cur; -+} -+ -+/** -+ * cr_selector_append_simple_sel: -+ * -+ *@a_this: the current instance of #CRSelector. -+ *@a_simple_sel: the simple selector to append. -+ * -+ *append a simple selector to the current #CRSelector list. -+ * -+ *Returns the new list or NULL in case of failure. -+ */ -+CRSelector * -+cr_selector_append_simple_sel (CRSelector * a_this, -+ CRSimpleSel * a_simple_sel) -+{ -+ CRSelector *selector = NULL; -+ -+ selector = cr_selector_new (a_simple_sel); -+ g_return_val_if_fail (selector, NULL); -+ -+ return cr_selector_append (a_this, selector); -+} -+ -+guchar * -+cr_selector_to_string (CRSelector const * a_this) -+{ -+ guchar *result = NULL; -+ GString *str_buf = NULL; -+ -+ str_buf = g_string_new (NULL); -+ g_return_val_if_fail (str_buf, NULL); -+ -+ if (a_this) { -+ CRSelector const *cur = NULL; -+ -+ for (cur = a_this; cur; cur = cur->next) { -+ if (cur->simple_sel) { -+ guchar *tmp_str = NULL; -+ -+ tmp_str = cr_simple_sel_to_string -+ (cur->simple_sel); -+ -+ if (tmp_str) { -+ if (cur->prev) -+ g_string_append (str_buf, -+ ", "); -+ -+ g_string_append (str_buf, (const gchar *) tmp_str); -+ -+ g_free (tmp_str); -+ tmp_str = NULL; -+ } -+ } -+ } -+ } -+ -+ if (str_buf) { -+ result = (guchar *) str_buf->str; -+ g_string_free (str_buf, FALSE); -+ str_buf = NULL; -+ } -+ -+ return result; -+} -+ -+/** -+ * cr_selector_dump: -+ * -+ *@a_this: the current instance of #CRSelector. -+ *@a_fp: the destination file. -+ * -+ *Serializes the current instance of #CRSelector to a file. -+ */ -+void -+cr_selector_dump (CRSelector const * a_this, FILE * a_fp) -+{ -+ guchar *tmp_buf = NULL; -+ -+ if (a_this) { -+ tmp_buf = cr_selector_to_string (a_this); -+ if (tmp_buf) { -+ fprintf (a_fp, "%s", tmp_buf); -+ g_free (tmp_buf); -+ tmp_buf = NULL; -+ } -+ } -+} -+ -+/** -+ * cr_selector_ref: -+ * -+ *@a_this: the current instance of #CRSelector. -+ * -+ *Increments the ref count of the current instance -+ *of #CRSelector. -+ */ -+void -+cr_selector_ref (CRSelector * a_this) -+{ -+ g_return_if_fail (a_this); -+ -+ a_this->ref_count++; -+} -+ -+/** -+ * cr_selector_unref: -+ * -+ *@a_this: the current instance of #CRSelector. -+ * -+ *Decrements the ref count of the current instance of -+ *#CRSelector. -+ *If the ref count reaches zero, the current instance of -+ *#CRSelector is destroyed. -+ * -+ *Returns TRUE if this function destroyed the current instance -+ *of #CRSelector, FALSE otherwise. -+ */ -+gboolean -+cr_selector_unref (CRSelector * a_this) -+{ -+ g_return_val_if_fail (a_this, FALSE); -+ -+ if (a_this->ref_count) { -+ a_this->ref_count--; -+ } -+ -+ if (a_this->ref_count == 0) { -+ cr_selector_destroy (a_this); -+ return TRUE; -+ } -+ -+ return FALSE; -+} -+ -+/** -+ * cr_selector_destroy: -+ * -+ *@a_this: the current instance of #CRSelector. -+ * -+ *Destroys the selector list. -+ */ -+void -+cr_selector_destroy (CRSelector * a_this) -+{ -+ CRSelector *cur = NULL; -+ -+ g_return_if_fail (a_this); -+ -+ /* -+ *go and get the list tail. In the same time, free -+ *all the simple selectors contained in the list. -+ */ -+ for (cur = a_this; cur && cur->next; cur = cur->next) { -+ if (cur->simple_sel) { -+ cr_simple_sel_destroy (cur->simple_sel); -+ cur->simple_sel = NULL; -+ } -+ } -+ -+ if (cur) { -+ if (cur->simple_sel) { -+ cr_simple_sel_destroy (cur->simple_sel); -+ cur->simple_sel = NULL; -+ } -+ } -+ -+ /*in case the list has only one element */ -+ if (cur && !cur->prev) { -+ g_free (cur); -+ return; -+ } -+ -+ /*walk backward the list and free each "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; -+ -+ if (cur->next) { -+ g_free (cur->next); -+ cur->next = NULL; -+ } -+ -+ g_free (cur); -+} -diff --git a/src/st/croco/cr-selector.h b/src/st/croco/cr-selector.h -new file mode 100644 -index 000000000..dd6a7f786 ---- /dev/null -+++ b/src/st/croco/cr-selector.h -@@ -0,0 +1,95 @@ -+/* -*- Mode: C; indent-tabs-mode: nil; c-basic-offset: 8 -*- */ -+ -+/* -+ * This file is part of The Croco Library -+ * -+ * 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 -+ * See COPYRIGHTS file for copyright information. -+ */ -+ -+#ifndef __CR_SELECTOR_H__ -+#define __CR_SELECTOR_H__ -+ -+#include -+#include "cr-utils.h" -+#include "cr-simple-sel.h" -+#include "cr-parsing-location.h" -+ -+/** -+ *@file -+ *The declaration file of the #CRSelector file. -+ */ -+ -+G_BEGIN_DECLS -+ -+typedef struct _CRSelector CRSelector ; -+ -+/** -+ *Abstracts a CSS2 selector as defined in the right part -+ *of the 'ruleset" production in the appendix D.1 of the -+ *css2 spec. -+ *It is actually the abstraction of a comma separated list -+ *of simple selectors list. -+ *In a css2 file, a selector is a list of simple selectors -+ *separated by a comma. -+ *e.g: sel0, sel1, sel2 ... -+ *Each seln is a simple selector -+ */ -+struct _CRSelector -+{ -+ /** -+ *A Selection expression. -+ *It is a list of basic selectors. -+ *Each basic selector can be either an element -+ *selector, an id selector, a class selector, an -+ *attribute selector, an universal selector etc ... -+ */ -+ CRSimpleSel *simple_sel ; -+ -+ /**The next selector list element*/ -+ CRSelector *next ; -+ CRSelector *prev ; -+ CRParsingLocation location ; -+ glong ref_count ; -+}; -+ -+CRSelector* cr_selector_new (CRSimpleSel *a_sel_expr) ; -+ -+CRSelector * cr_selector_parse_from_buf (const guchar * a_char_buf, -+ enum CREncoding a_enc) ; -+ -+CRSelector* cr_selector_append (CRSelector *a_this, CRSelector *a_new) ; -+ -+CRSelector* cr_selector_append_simple_sel (CRSelector *a_this, -+ CRSimpleSel *a_simple_sel) ; -+ -+CRSelector* cr_selector_prepend (CRSelector *a_this, CRSelector *a_new) ; -+ -+guchar * cr_selector_to_string (CRSelector const *a_this) ; -+ -+void cr_selector_dump (CRSelector const *a_this, FILE *a_fp) ; -+ -+void cr_selector_ref (CRSelector *a_this) ; -+ -+gboolean cr_selector_unref (CRSelector *a_this) ; -+ -+void cr_selector_destroy (CRSelector *a_this) ; -+ -+G_END_DECLS -+ -+#endif /*__CR_SELECTOR_H__*/ -diff --git a/src/st/croco/cr-simple-sel.c b/src/st/croco/cr-simple-sel.c -new file mode 100644 -index 000000000..ac906858d ---- /dev/null -+++ b/src/st/croco/cr-simple-sel.c -@@ -0,0 +1,325 @@ -+/* -*- Mode: C; indent-tabs-mode:nil; c-basic-offset: 8-*- */ -+ -+/* -+ * This file is part of The Croco Library -+ * -+ * 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 -+ * See COPYRIGHTS file for copyright information. -+ */ -+ -+#include -+#include -+#include "cr-simple-sel.h" -+ -+/** -+ * cr_simple_sel_new: -+ * -+ *The constructor of #CRSimpleSel. -+ * -+ *Returns the new instance of #CRSimpleSel. -+ */ -+CRSimpleSel * -+cr_simple_sel_new (void) -+{ -+ CRSimpleSel *result = NULL; -+ -+ result = g_try_malloc (sizeof (CRSimpleSel)); -+ if (!result) { -+ cr_utils_trace_info ("Out of memory"); -+ return NULL; -+ } -+ memset (result, 0, sizeof (CRSimpleSel)); -+ -+ return result; -+} -+ -+/** -+ * cr_simple_sel_append_simple_sel: -+ * -+ *Appends a simpe selector to the current list of simple selector. -+ * -+ *@a_this: the this pointer of the current instance of #CRSimpleSel. -+ *@a_sel: the simple selector to append. -+ * -+ *Returns: the new list upon successfull completion, an error code otherwise. -+ */ -+CRSimpleSel * -+cr_simple_sel_append_simple_sel (CRSimpleSel * a_this, CRSimpleSel * a_sel) -+{ -+ CRSimpleSel *cur = NULL; -+ -+ g_return_val_if_fail (a_sel, NULL); -+ -+ if (a_this == NULL) -+ return a_sel; -+ -+ for (cur = a_this; cur->next; cur = cur->next) ; -+ -+ cur->next = a_sel; -+ a_sel->prev = cur; -+ -+ return a_this; -+} -+ -+/** -+ * cr_simple_sel_prepend_simple_sel: -+ * -+ *@a_this: the this pointer of the current instance of #CRSimpleSel. -+ *@a_sel: the simple selector to prepend. -+ * -+ *Prepends a simple selector to the current list of simple selectors. -+ * -+ *Returns the new list upon successfull completion, an error code otherwise. -+ */ -+CRSimpleSel * -+cr_simple_sel_prepend_simple_sel (CRSimpleSel * a_this, CRSimpleSel * a_sel) -+{ -+ g_return_val_if_fail (a_sel, NULL); -+ -+ if (a_this == NULL) -+ return a_sel; -+ -+ a_sel->next = a_this; -+ a_this->prev = a_sel; -+ -+ return a_sel; -+} -+ -+guchar * -+cr_simple_sel_to_string (CRSimpleSel const * a_this) -+{ -+ GString *str_buf = NULL; -+ guchar *result = NULL; -+ -+ CRSimpleSel const *cur = NULL; -+ -+ g_return_val_if_fail (a_this, NULL); -+ -+ str_buf = g_string_new (NULL); -+ for (cur = a_this; cur; cur = cur->next) { -+ if (cur->name) { -+ guchar *str = (guchar *) g_strndup (cur->name->stryng->str, -+ cur->name->stryng->len); -+ -+ if (str) { -+ switch (cur->combinator) { -+ case COMB_WS: -+ g_string_append (str_buf, " "); -+ break; -+ -+ case COMB_PLUS: -+ g_string_append (str_buf, "+"); -+ break; -+ -+ case COMB_GT: -+ g_string_append (str_buf, ">"); -+ break; -+ -+ default: -+ break; -+ } -+ -+ g_string_append (str_buf, (const gchar *) str); -+ g_free (str); -+ str = NULL; -+ } -+ } -+ -+ if (cur->add_sel) { -+ guchar *tmp_str = NULL; -+ -+ tmp_str = cr_additional_sel_to_string (cur->add_sel); -+ if (tmp_str) { -+ g_string_append (str_buf, (const gchar *) tmp_str); -+ g_free (tmp_str); -+ tmp_str = NULL; -+ } -+ } -+ } -+ -+ if (str_buf) { -+ result = (guchar *) str_buf->str; -+ g_string_free (str_buf, FALSE); -+ str_buf = NULL; -+ } -+ -+ return result; -+} -+ -+ -+guchar * -+cr_simple_sel_one_to_string (CRSimpleSel const * a_this) -+{ -+ GString *str_buf = NULL; -+ guchar *result = NULL; -+ -+ g_return_val_if_fail (a_this, NULL); -+ -+ str_buf = g_string_new (NULL); -+ if (a_this->name) { -+ guchar *str = (guchar *) g_strndup (a_this->name->stryng->str, -+ a_this->name->stryng->len); -+ -+ if (str) { -+ g_string_append_printf (str_buf, "%s", str); -+ g_free (str); -+ str = NULL; -+ } -+ } -+ -+ if (a_this->add_sel) { -+ guchar *tmp_str = NULL; -+ -+ tmp_str = cr_additional_sel_to_string (a_this->add_sel); -+ if (tmp_str) { -+ g_string_append_printf -+ (str_buf, "%s", tmp_str); -+ g_free (tmp_str); -+ tmp_str = NULL; -+ } -+ } -+ -+ if (str_buf) { -+ result = (guchar *) str_buf->str; -+ g_string_free (str_buf, FALSE); -+ str_buf = NULL; -+ } -+ -+ return result; -+} -+ -+/** -+ * cr_simple_sel_dump: -+ *@a_this: the current instance of #CRSimpleSel. -+ *@a_fp: the destination file pointer. -+ * -+ *Dumps the selector to a file. -+ *TODO: add the support of unicode in the dump. -+ * -+ *Returns CR_OK upon successfull completion, an error code -+ *otherwise. -+ */ -+enum CRStatus -+cr_simple_sel_dump (CRSimpleSel const * a_this, FILE * a_fp) -+{ -+ guchar *tmp_str = NULL; -+ -+ g_return_val_if_fail (a_fp, CR_BAD_PARAM_ERROR); -+ -+ if (a_this) { -+ tmp_str = cr_simple_sel_to_string (a_this); -+ if (tmp_str) { -+ fprintf (a_fp, "%s", tmp_str); -+ g_free (tmp_str); -+ tmp_str = NULL; -+ } -+ } -+ -+ return CR_OK; -+} -+ -+/** -+ * cr_simple_sel_compute_specificity: -+ * -+ *@a_this: the current instance of #CRSimpleSel -+ * -+ *Computes the selector (combinator separated list of simple selectors) -+ *as defined in the css2 spec in chapter 6.4.3 -+ * -+ *Returns CR_OK upon successfull completion, an error code otherwise. -+ */ -+enum CRStatus -+cr_simple_sel_compute_specificity (CRSimpleSel * a_this) -+{ -+ CRAdditionalSel const *cur_add_sel = NULL; -+ CRSimpleSel const *cur_sel = NULL; -+ gulong a = 0, -+ b = 0, -+ c = 0; -+ -+ g_return_val_if_fail (a_this, CR_BAD_PARAM_ERROR); -+ -+ for (cur_sel = a_this; cur_sel; cur_sel = cur_sel->next) { -+ if (cur_sel->type_mask & TYPE_SELECTOR) { -+ c++; /*hmmh, is this a new language ? */ -+ } else if (!cur_sel->name -+ || !cur_sel->name->stryng -+ || !cur_sel->name->stryng->str) { -+ if (cur_sel->add_sel->type == -+ PSEUDO_CLASS_ADD_SELECTOR) { -+ /* -+ *this is a pseudo element, and -+ *the spec says, "ignore pseudo elements". -+ */ -+ continue; -+ } -+ } -+ -+ for (cur_add_sel = cur_sel->add_sel; -+ cur_add_sel; cur_add_sel = cur_add_sel->next) { -+ switch (cur_add_sel->type) { -+ case ID_ADD_SELECTOR: -+ a++; -+ break; -+ -+ case NO_ADD_SELECTOR: -+ continue; -+ -+ default: -+ b++; -+ break; -+ } -+ } -+ } -+ -+ /*we suppose a, b and c have 1 to 3 digits */ -+ a_this->specificity = a * 1000000 + b * 1000 + c; -+ -+ return CR_OK; -+} -+ -+/** -+ * cr_simple_sel_destroy: -+ * -+ *@a_this: the this pointer of the current instance of #CRSimpleSel. -+ * -+ *The destructor of the current instance of -+ *#CRSimpleSel. -+ */ -+void -+cr_simple_sel_destroy (CRSimpleSel * a_this) -+{ -+ g_return_if_fail (a_this); -+ -+ if (a_this->name) { -+ cr_string_destroy (a_this->name); -+ a_this->name = NULL; -+ } -+ -+ if (a_this->add_sel) { -+ cr_additional_sel_destroy (a_this->add_sel); -+ a_this->add_sel = NULL; -+ } -+ -+ if (a_this->next) { -+ cr_simple_sel_destroy (a_this->next); -+ } -+ -+ if (a_this) { -+ g_free (a_this); -+ } -+} -diff --git a/src/st/croco/cr-simple-sel.h b/src/st/croco/cr-simple-sel.h -new file mode 100644 -index 000000000..d8edc0025 ---- /dev/null -+++ b/src/st/croco/cr-simple-sel.h -@@ -0,0 +1,130 @@ -+/* -*- Mode: C; indent-tabs-mode:nil; c-basic-offset: 8-*- */ -+ -+/* -+ * This file is part of The Croco Library -+ * -+ * 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 -+ * See COPYRIGHTS file for copyright information. -+ */ -+ -+ -+#ifndef __CR_SEL_H__ -+#define __CR_SEL_H__ -+ -+#include -+#include -+#include "cr-additional-sel.h" -+#include "cr-parsing-location.h" -+ -+G_BEGIN_DECLS -+ -+/** -+ *@file -+ *the declaration of the #CRSimpleSel class. -+ * -+ */ -+enum Combinator -+{ -+ NO_COMBINATOR, -+ COMB_WS,/*whitespace: descendent*/ -+ COMB_PLUS,/*'+': preceded by*/ -+ COMB_GT/*greater than ('>'): child*/ -+} ; -+ -+enum SimpleSelectorType -+{ -+ NO_SELECTOR_TYPE = 0, -+ UNIVERSAL_SELECTOR = 1, -+ TYPE_SELECTOR = 1 << 1 -+} ; -+ -+typedef struct _CRSimpleSel CRSimpleSel ; -+ -+/** -+ *The abstraction of a css2 simple selection list -+ *as defined by the right part of the "selector" production in the -+ *appendix D.1 of the css2 spec. -+ *It is basically a list of simple selector, each -+ *simple selector being separated by a combinator. -+ * -+ *In the libcroco's implementation, each simple selector -+ *is made of at most two parts: -+ * -+ *1/An element name or 'type selector' (which can hold a '*' and -+ *then been called 'universal selector') -+ * -+ *2/An additional selector that "specializes" the preceding type or -+ *universal selector. The additionnal selector can be either -+ *an id selector, or a class selector, or an attribute selector. -+ */ -+struct _CRSimpleSel -+{ -+ enum SimpleSelectorType type_mask ; -+ gboolean is_case_sentive ; -+ CRString * name ; -+ /** -+ *The combinator that separates -+ *this simple selector from the previous -+ *one. -+ */ -+ enum Combinator combinator ; -+ -+ /** -+ *The additional selector list of the -+ *current simple selector. -+ *An additional selector may -+ *be a class selector, an id selector, -+ *or an attribute selector. -+ *Note that this field is a linked list. -+ */ -+ CRAdditionalSel *add_sel ; -+ -+ /* -+ *the specificity as specified by -+ *chapter 6.4.3 of the spec. -+ */ -+ gulong specificity ; -+ -+ CRSimpleSel *next ; -+ CRSimpleSel *prev ; -+ CRParsingLocation location ; -+} ; -+ -+CRSimpleSel * cr_simple_sel_new (void) ; -+ -+CRSimpleSel * cr_simple_sel_append_simple_sel (CRSimpleSel *a_this, -+ CRSimpleSel *a_sel) ; -+ -+CRSimpleSel * cr_simple_sel_prepend_simple_sel (CRSimpleSel *a_this, -+ CRSimpleSel *a_sel) ; -+ -+guchar * cr_simple_sel_to_string (CRSimpleSel const *a_this) ; -+ -+guchar * cr_simple_sel_one_to_string (CRSimpleSel const * a_this) ; -+ -+enum CRStatus cr_simple_sel_dump (CRSimpleSel const *a_this, FILE *a_fp) ; -+ -+enum CRStatus cr_simple_sel_dump_attr_sel_list (CRSimpleSel const *a_this) ; -+ -+enum CRStatus cr_simple_sel_compute_specificity (CRSimpleSel *a_this) ; -+ -+void cr_simple_sel_destroy (CRSimpleSel *a_this) ; -+ -+G_END_DECLS -+ -+ -+#endif /*__CR_SIMPLE_SEL_H__*/ -diff --git a/src/st/croco/cr-statement.c b/src/st/croco/cr-statement.c -new file mode 100644 -index 000000000..241fa5f3b ---- /dev/null -+++ b/src/st/croco/cr-statement.c -@@ -0,0 +1,2794 @@ -+/* -*- Mode: C; indent-tabs-mode: nil; c-basic-offset: 8 -*- */ -+ -+/* -+ * This file is part of The Croco Library -+ * -+ * 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. -+ * See COPYRIGHTS files for copyrights information. -+ */ -+ -+#include -+#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; -+} -diff --git a/src/st/croco/cr-statement.h b/src/st/croco/cr-statement.h -new file mode 100644 -index 000000000..74a233055 ---- /dev/null -+++ b/src/st/croco/cr-statement.h -@@ -0,0 +1,440 @@ -+/* -*- Mode: C; indent-tabs-mode: nil; c-basic-offset: 8 -*- */ -+ -+/* -+ * This file is part of The Croco Library -+ * -+ * 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 -+ * See COPYRIGHTS file for copyright information. -+ */ -+ -+#include -+#include "cr-utils.h" -+#include "cr-term.h" -+#include "cr-selector.h" -+#include "cr-declaration.h" -+ -+#ifndef __CR_STATEMENT_H__ -+#define __CR_STATEMENT_H__ -+ -+G_BEGIN_DECLS -+ -+/** -+ *@file -+ *Declaration of the #CRStatement class. -+ */ -+ -+/* -+ *forward declaration of CRStyleSheet which is defined in -+ *cr-stylesheet.h -+ */ -+ -+struct _CRStatement ; -+ -+/* -+ *typedef struct _CRStatement CRStatement ; -+ *this is forward declared in -+ *cr-declaration.h already. -+ */ -+ -+struct _CRAtMediaRule ; -+typedef struct _CRAtMediaRule CRAtMediaRule ; -+ -+typedef struct _CRRuleSet CRRuleSet ; -+ -+/** -+ *The abstraction of a css ruleset. -+ *A ruleset is made of a list of selectors, -+ *followed by a list of declarations. -+ */ -+struct _CRRuleSet -+{ -+ /**A list of instances of #CRSimpeSel*/ -+ CRSelector *sel_list ; -+ -+ /**A list of instances of #CRDeclaration*/ -+ CRDeclaration *decl_list ; -+ -+ /** -+ *The parent media rule, or NULL if -+ *no parent media rule exists. -+ */ -+ CRStatement *parent_media_rule ; -+} ; -+ -+/* -+ *a forward declaration of CRStylesheet. -+ *CRStylesheet is actually declared in -+ *cr-stylesheet.h -+ */ -+struct _CRStyleSheet ; -+typedef struct _CRStyleSheet CRStyleSheet; -+ -+ -+/**The \@import rule abstraction.*/ -+typedef struct _CRAtImportRule CRAtImportRule ; -+struct _CRAtImportRule -+{ -+ /**the url of the import rule*/ -+ CRString *url ; -+ -+ GList *media_list ; -+ -+ /** -+ *the stylesheet fetched from the url, if any. -+ *this is not "owned" by #CRAtImportRule which means -+ *it is not destroyed by the destructor of #CRAtImportRule. -+ */ -+ CRStyleSheet * sheet; -+}; -+ -+ -+/**abstraction of an \@media rule*/ -+struct _CRAtMediaRule -+{ -+ GList *media_list ; -+ CRStatement *rulesets ; -+} ; -+ -+ -+typedef struct _CRAtPageRule CRAtPageRule ; -+/**The \@page rule abstraction*/ -+struct _CRAtPageRule -+{ -+ /**a list of instances of #CRDeclaration*/ -+ CRDeclaration *decl_list ; -+ -+ /**page selector. Is a pseudo selector*/ -+ CRString *name ; -+ CRString *pseudo ; -+} ; -+ -+/**The \@charset rule abstraction*/ -+typedef struct _CRAtCharsetRule CRAtCharsetRule ; -+struct _CRAtCharsetRule -+{ -+ CRString * charset ; -+}; -+ -+/**The abstaction of the \@font-face rule.*/ -+typedef struct _CRAtFontFaceRule CRAtFontFaceRule ; -+struct _CRAtFontFaceRule -+{ -+ /*a list of instanaces of #CRDeclaration*/ -+ CRDeclaration *decl_list ; -+} ; -+ -+ -+/** -+ *The possible types of css2 statements. -+ */ -+enum CRStatementType -+{ -+ /** -+ *A generic css at-rule -+ *each unknown at-rule will -+ *be of this type. -+ */ -+ -+ /**A css at-rule*/ -+ AT_RULE_STMT = 0, -+ -+ /*A css ruleset*/ -+ RULESET_STMT, -+ -+ /**A css2 import rule*/ -+ AT_IMPORT_RULE_STMT, -+ -+ /**A css2 media rule*/ -+ AT_MEDIA_RULE_STMT, -+ -+ /**A css2 page rule*/ -+ AT_PAGE_RULE_STMT, -+ -+ /**A css2 charset rule*/ -+ AT_CHARSET_RULE_STMT, -+ -+ /**A css2 font face rule*/ -+ AT_FONT_FACE_RULE_STMT -+} ; -+ -+ -+/** -+ *The abstraction of css statement as defined -+ *in the chapter 4 and appendix D.1 of the css2 spec. -+ *A statement is actually a double chained list of -+ *statements.A statement can be a ruleset, an \@import -+ *rule, an \@page rule etc ... -+ */ -+struct _CRStatement -+{ -+ /** -+ *The type of the statement. -+ */ -+ enum CRStatementType type ; -+ -+ union -+ { -+ CRRuleSet *ruleset ; -+ CRAtImportRule *import_rule ; -+ CRAtMediaRule *media_rule ; -+ CRAtPageRule *page_rule ; -+ CRAtCharsetRule *charset_rule ; -+ CRAtFontFaceRule *font_face_rule ; -+ } kind ; -+ -+ /* -+ *the specificity of the selector -+ *that matched this statement. -+ *This is only used by the cascading -+ *order determination algorithm. -+ */ -+ gulong specificity ; -+ -+ /* -+ *the style sheet that contains -+ *this css statement. -+ */ -+ CRStyleSheet *parent_sheet ; -+ CRStatement *next ; -+ CRStatement *prev ; -+ -+ CRParsingLocation location ; -+ -+ /** -+ *a custom pointer useable by -+ *applications that use libcroco. -+ *libcroco itself will never modify -+ *this pointer. -+ */ -+ gpointer app_data ; -+ -+ /** -+ *a custom pointer used -+ *by the upper layers of libcroco. -+ *application should never use this -+ *pointer. -+ */ -+ gpointer croco_data ; -+ -+} ; -+ -+ -+gboolean -+cr_statement_does_buf_parses_against_core (const guchar *a_buf, -+ enum CREncoding a_encoding) ; -+CRStatement * -+cr_statement_parse_from_buf (const guchar *a_buf, -+ enum CREncoding a_encoding) ; -+CRStatement* -+cr_statement_new_ruleset (CRStyleSheet *a_sheet, -+ CRSelector *a_sel_list, -+ CRDeclaration *a_decl_list, -+ CRStatement *a_media_rule) ; -+CRStatement * -+cr_statement_ruleset_parse_from_buf (const guchar * a_buf, -+ enum CREncoding a_enc) ; -+ -+CRStatement* -+cr_statement_new_at_import_rule (CRStyleSheet *a_container_sheet, -+ CRString *a_url, -+ GList *a_media_list, -+ CRStyleSheet *a_imported_sheet) ; -+ -+CRStatement * -+cr_statement_at_import_rule_parse_from_buf (const guchar * a_buf, -+ enum CREncoding a_encoding) ; -+ -+CRStatement * -+cr_statement_new_at_media_rule (CRStyleSheet *a_sheet, -+ CRStatement *a_ruleset, -+ GList *a_media) ; -+CRStatement * -+cr_statement_at_media_rule_parse_from_buf (const guchar *a_buf, -+ enum CREncoding a_enc) ; -+ -+CRStatement * -+cr_statement_new_at_charset_rule (CRStyleSheet *a_sheet, -+ CRString *a_charset) ; -+CRStatement * -+cr_statement_at_charset_rule_parse_from_buf (const guchar *a_buf, -+ enum CREncoding a_encoding); -+ -+ -+CRStatement * -+cr_statement_new_at_font_face_rule (CRStyleSheet *a_sheet, -+ CRDeclaration *a_font_decls) ; -+CRStatement * -+cr_statement_font_face_rule_parse_from_buf (const guchar *a_buf, -+ enum CREncoding a_encoding) ; -+ -+CRStatement * -+cr_statement_new_at_page_rule (CRStyleSheet *a_sheet, -+ CRDeclaration *a_decl_list, -+ CRString *a_name, -+ CRString *a_pseudo) ; -+CRStatement * -+cr_statement_at_page_rule_parse_from_buf (const guchar *a_buf, -+ enum CREncoding a_encoding) ; -+ -+enum CRStatus -+cr_statement_set_parent_sheet (CRStatement *a_this, -+ CRStyleSheet *a_sheet) ; -+ -+enum CRStatus -+cr_statement_get_parent_sheet (CRStatement *a_this, -+ CRStyleSheet **a_sheet) ; -+ -+CRStatement * -+cr_statement_append (CRStatement *a_this, -+ CRStatement *a_new) ; -+ -+CRStatement* -+cr_statement_prepend (CRStatement *a_this, -+ CRStatement *a_new) ; -+ -+CRStatement * -+cr_statement_unlink (CRStatement *a_stmt) ; -+ -+enum CRStatus -+cr_statement_ruleset_set_sel_list (CRStatement *a_this, -+ CRSelector *a_sel_list) ; -+ -+enum CRStatus -+cr_statement_ruleset_get_sel_list (CRStatement const *a_this, -+ CRSelector **a_list) ; -+ -+enum CRStatus -+cr_statement_ruleset_set_decl_list (CRStatement *a_this, -+ CRDeclaration *a_list) ; -+ -+enum CRStatus -+cr_statement_ruleset_get_declarations (CRStatement *a_this, -+ CRDeclaration **a_decl_list) ; -+ -+enum CRStatus -+cr_statement_ruleset_append_decl2 (CRStatement *a_this, -+ CRString *a_prop, CRTerm *a_value) ; -+ -+enum CRStatus -+cr_statement_ruleset_append_decl (CRStatement *a_this, -+ CRDeclaration *a_decl) ; -+ -+enum CRStatus -+cr_statement_at_import_rule_set_imported_sheet (CRStatement *a_this, -+ CRStyleSheet *a_sheet) ; -+ -+enum CRStatus -+cr_statement_at_import_rule_get_imported_sheet (CRStatement *a_this, -+ CRStyleSheet **a_sheet) ; -+ -+enum CRStatus -+cr_statement_at_import_rule_set_url (CRStatement *a_this, -+ CRString *a_url) ; -+ -+enum CRStatus -+cr_statement_at_import_rule_get_url (CRStatement const *a_this, -+ CRString **a_url) ; -+ -+gint -+cr_statement_at_media_nr_rules (CRStatement const *a_this) ; -+ -+CRStatement * -+cr_statement_at_media_get_from_list (CRStatement *a_this, int itemnr) ; -+ -+enum CRStatus -+cr_statement_at_page_rule_set_sel (CRStatement *a_this, -+ CRSelector *a_sel) ; -+ -+enum CRStatus -+cr_statement_at_page_rule_get_sel (CRStatement const *a_this, -+ CRSelector **a_sel) ; -+ -+enum CRStatus -+cr_statement_at_page_rule_set_declarations (CRStatement *a_this, -+ CRDeclaration *a_decl_list) ; -+ -+enum CRStatus -+cr_statement_at_page_rule_get_declarations (CRStatement *a_this, -+ CRDeclaration **a_decl_list) ; -+ -+enum CRStatus -+cr_statement_at_charset_rule_set_charset (CRStatement *a_this, -+ CRString *a_charset) ; -+ -+enum CRStatus -+cr_statement_at_charset_rule_get_charset (CRStatement const *a_this, -+ CRString **a_charset) ; -+ -+enum CRStatus -+cr_statement_at_font_face_rule_set_decls (CRStatement *a_this, -+ CRDeclaration *a_decls) ; -+ -+enum CRStatus -+cr_statement_at_font_face_rule_get_decls (CRStatement *a_this, -+ CRDeclaration **a_decls) ; -+ -+enum CRStatus -+cr_statement_at_font_face_rule_add_decl (CRStatement *a_this, -+ CRString *a_prop, -+ CRTerm *a_value) ; -+ -+gchar * -+cr_statement_to_string (CRStatement const * a_this, gulong a_indent) ; -+ -+gchar* -+cr_statement_list_to_string (CRStatement const *a_this, gulong a_indent) ; -+ -+void -+cr_statement_dump (CRStatement const *a_this, FILE *a_fp, gulong a_indent) ; -+ -+void -+cr_statement_dump_ruleset (CRStatement const * a_this, FILE * a_fp, -+ glong a_indent) ; -+ -+void -+cr_statement_dump_font_face_rule (CRStatement const * a_this, -+ FILE * a_fp, -+ glong a_indent) ; -+ -+void -+cr_statement_dump_page (CRStatement const * a_this, FILE * a_fp, -+ gulong a_indent) ; -+ -+ -+void -+cr_statement_dump_media_rule (CRStatement const * a_this, -+ FILE * a_fp, -+ gulong a_indent) ; -+ -+void -+cr_statement_dump_import_rule (CRStatement const * a_this, FILE * a_fp, -+ gulong a_indent) ; -+void -+cr_statement_dump_charset (CRStatement const * a_this, FILE * a_fp, -+ gulong a_indent) ; -+gint -+cr_statement_nr_rules (CRStatement const *a_this) ; -+ -+CRStatement * -+cr_statement_get_from_list (CRStatement *a_this, int itemnr) ; -+ -+void -+cr_statement_destroy (CRStatement *a_this) ; -+ -+G_END_DECLS -+ -+#endif /*__CR_STATEMENT_H__*/ -diff --git a/src/st/croco/cr-string.c b/src/st/croco/cr-string.c -new file mode 100644 -index 000000000..1b10bb2ab ---- /dev/null -+++ b/src/st/croco/cr-string.c -@@ -0,0 +1,168 @@ -+/* -*- Mode: C; indent-tabs-mode:nil; c-basic-offset: 8-*- */ -+ -+/* -+ * This file is part of The Croco Library -+ * -+ * 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. -+ * See COPYRIGHTS file for copyright information. -+ */ -+ -+#include -+#include "cr-string.h" -+ -+/** -+ *Instanciates a #CRString -+ *@return the newly instanciated #CRString -+ *Must be freed with cr_string_destroy(). -+ */ -+CRString * -+cr_string_new (void) -+{ -+ CRString *result = NULL ; -+ -+ result = g_try_malloc (sizeof (CRString)) ; -+ if (!result) { -+ cr_utils_trace_info ("Out of memory") ; -+ return NULL ; -+ } -+ memset (result, 0, sizeof (CRString)) ; -+ result->stryng = g_string_new (NULL) ; -+ return result ; -+} -+ -+/** -+ *Instanciate a string and initialise it to -+ *a_string. -+ *@param a_string the initial string -+ *@return the newly instanciated string. -+ */ -+CRString * -+cr_string_new_from_string (const gchar * a_string) -+{ -+ CRString *result = NULL ; -+ -+ result = cr_string_new () ; -+ if (!result) { -+ cr_utils_trace_info ("Out of memory") ; -+ return NULL ; -+ } -+ if (a_string) -+ g_string_append (result->stryng, a_string) ; -+ return result ; -+} -+ -+/** -+ *Instanciates a #CRString from an instance of GString. -+ *@param a_string the input string that will be copied into -+ *the newly instanciated #CRString -+ *@return the newly instanciated #CRString. -+ */ -+CRString * -+cr_string_new_from_gstring (GString const *a_string) -+{ -+ CRString *result = NULL ; -+ -+ result = cr_string_new () ; -+ if (!result) { -+ cr_utils_trace_info ("Out of memory") ; -+ return NULL ; -+ } -+ if (a_string) { -+ g_string_append_len (result->stryng, -+ a_string->str, -+ a_string->len); -+ -+ } -+ return result ; -+} -+ -+CRString * -+cr_string_dup (CRString const *a_this) -+{ -+ CRString *result = NULL ; -+ g_return_val_if_fail (a_this, NULL) ; -+ -+ result = cr_string_new_from_gstring (a_this->stryng) ; -+ if (!result) { -+ cr_utils_trace_info ("Out of memory") ; -+ return NULL ; -+ } -+ cr_parsing_location_copy (&result->location, -+ &a_this->location) ; -+ return result ; -+} -+ -+gchar * -+cr_string_dup2 (CRString const *a_this) -+{ -+ gchar *result = NULL ; -+ -+ g_return_val_if_fail (a_this, NULL) ; -+ -+ if (a_this -+ && a_this->stryng -+ && a_this->stryng->str) { -+ result = g_strndup (a_this->stryng->str, -+ a_this->stryng->len) ; -+ } -+ return result ; -+} -+ -+/** -+ *Returns a pointer to the internal raw NULL terminated string -+ *of the current instance of #CRString. -+ *@param a_this the current instance of #CRString -+ */ -+const gchar * -+cr_string_peek_raw_str (CRString const *a_this) -+{ -+ g_return_val_if_fail (a_this, NULL) ; -+ -+ if (a_this->stryng && a_this->stryng->str) -+ return a_this->stryng->str ; -+ return NULL ; -+} -+ -+/** -+ *Returns the length of the internal raw NULL terminated -+ *string of the current instance of #CRString. -+ *@param a_this the current instance of #CRString. -+ *@return the len of the internal raw NULL termninated string, -+ *of -1 if no length can be returned. -+ */ -+gint -+cr_string_peek_raw_str_len (CRString const *a_this) -+{ -+ g_return_val_if_fail (a_this && a_this->stryng, -+ -1) ; -+ return a_this->stryng->len ; -+} -+ -+/** -+ *@param a_this the #CRString to destroy. -+ */ -+void -+cr_string_destroy (CRString *a_this) -+{ -+ g_return_if_fail (a_this) ; -+ -+ if (a_this->stryng) { -+ g_string_free (a_this->stryng, TRUE) ; -+ a_this->stryng = NULL ; -+ } -+ g_free (a_this) ; -+} -diff --git a/src/st/croco/cr-string.h b/src/st/croco/cr-string.h -new file mode 100644 -index 000000000..2700f0e2e ---- /dev/null -+++ b/src/st/croco/cr-string.h -@@ -0,0 +1,76 @@ -+/* -*- Mode: C; indent-tabs-mode:nil; c-basic-offset: 8-*- */ -+ -+/* -+ * This file is part of The Croco Library -+ * -+ * 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 -+ * -+ * See COPYRIGHTS file for copyright information. -+ */ -+ -+/** -+ *@file -+ *Declaration file of the #CRString class. -+ */ -+ -+#ifndef __CR_STRING_H__ -+#define __CR_STRING_H__ -+ -+#include -+#include "cr-utils.h" -+#include "cr-parsing-location.h" -+ -+G_BEGIN_DECLS -+ -+typedef struct _CRString CRString ; -+ -+/** -+ *This is a ship implementation of string based on GString. -+ *Actually, the aim of CRString is to store the parsing location -+ *(line,column,byte offset) at which a given string has been parsed -+ *in the input CSS. -+ *So this class has a gstring field of type GString that users can -+ *freely manipulate, and also a CRParginLocation type where the -+ *parsing location is store. If you don't want to deal with parsing -+ *location stuffs, then use GString instead. If we were in C++ for example, -+ *CRString would just inherit GString and just add accessors to -+ *the CRParsingLocation data ... but we are not and we still have -+ *to provide the parsing location information. -+ */ -+struct _CRString { -+ /** -+ *The GString where all the string -+ *operation happen. -+ */ -+ GString *stryng ; -+ /** -+ *The parsing location storage area. -+ */ -+ CRParsingLocation location ; -+} ; -+ -+CRString * cr_string_new (void) ; -+ -+CRString *cr_string_new_from_string (const gchar * a_string) ; -+CRString * cr_string_new_from_gstring (GString const *a_string) ; -+CRString *cr_string_dup (CRString const *a_this) ; -+gchar *cr_string_dup2 (CRString const *a_this) ; -+const gchar *cr_string_peek_raw_str (CRString const *a_this) ; -+gint cr_string_peek_raw_str_len (CRString const *a_this) ; -+void cr_string_destroy (CRString *a_this) ; -+ -+G_END_DECLS -+ -+#endif -diff --git a/src/st/croco/cr-stylesheet.c b/src/st/croco/cr-stylesheet.c -new file mode 100644 -index 000000000..69909da24 ---- /dev/null -+++ b/src/st/croco/cr-stylesheet.c -@@ -0,0 +1,178 @@ -+/* -*- Mode: C; indent-tabs-mode: nil; c-basic-offset: 8 -*- */ -+ -+/* -+ * This file is part of The Croco Library -+ * -+ * Copyright (C) 2002-2004 Dodji Seketeli -+ * -+ * 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 -+ */ -+ -+#include "string.h" -+#include "cr-stylesheet.h" -+ -+/** -+ *@file -+ *The definition of the #CRStyleSheet class -+ */ -+ -+/** -+ *Constructor of the #CRStyleSheet class. -+ *@param the initial list of css statements. -+ *@return the newly built css2 stylesheet, or NULL in case of error. -+ */ -+CRStyleSheet * -+cr_stylesheet_new (CRStatement * a_stmts) -+{ -+ CRStyleSheet *result; -+ -+ result = g_try_malloc (sizeof (CRStyleSheet)); -+ if (!result) { -+ cr_utils_trace_info ("Out of memory"); -+ return NULL; -+ } -+ -+ memset (result, 0, sizeof (CRStyleSheet)); -+ -+ if (a_stmts) -+ result->statements = a_stmts; -+ -+ return result; -+} -+ -+/** -+ *@param a_this the current instance of #CRStyleSheet -+ *@return the serialized stylesheet. -+ */ -+gchar * -+cr_stylesheet_to_string (CRStyleSheet const *a_this) -+{ -+ gchar *str = NULL; -+ GString *stringue = NULL; -+ CRStatement const *cur_stmt = NULL; -+ -+ g_return_val_if_fail (a_this, NULL); -+ -+ if (a_this->statements) { -+ stringue = g_string_new (NULL) ; -+ g_return_val_if_fail (stringue, NULL) ; -+ } -+ for (cur_stmt = a_this->statements; -+ cur_stmt; cur_stmt = cur_stmt->next) { -+ if (cur_stmt->prev) { -+ g_string_append (stringue, "\n\n") ; -+ } -+ str = cr_statement_to_string (cur_stmt, 0) ; -+ if (str) { -+ g_string_append (stringue, str) ; -+ g_free (str) ; -+ str = NULL ; -+ } -+ } -+ if (stringue) { -+ str = stringue->str ; -+ g_string_free (stringue, FALSE) ; -+ stringue = NULL ; -+ } -+ return str ; -+} -+ -+/** -+ *Dumps the current css2 stylesheet to a file. -+ *@param a_this the current instance of #CRStyleSheet. -+ *@param a_fp the destination file -+ */ -+void -+cr_stylesheet_dump (CRStyleSheet const * a_this, FILE * a_fp) -+{ -+ gchar *str = NULL ; -+ -+ g_return_if_fail (a_this); -+ -+ str = cr_stylesheet_to_string (a_this) ; -+ if (str) { -+ fprintf (a_fp, "%s", str) ; -+ g_free (str) ; -+ str = NULL ; -+ } -+} -+ -+/** -+ *Return the number of rules in the stylesheet. -+ *@param a_this the current instance of #CRStyleSheet. -+ *@return number of rules in the stylesheet. -+ */ -+gint -+cr_stylesheet_nr_rules (CRStyleSheet const * a_this) -+{ -+ g_return_val_if_fail (a_this, -1); -+ -+ return cr_statement_nr_rules (a_this->statements); -+} -+ -+/** -+ *Use an index to get a CRStatement from the rules in a given stylesheet. -+ *@param a_this the current instance of #CRStatement. -+ *@param itemnr the index into the rules. -+ *@return CRStatement at position itemnr, if itemnr > number of rules - 1, -+ *it will return NULL. -+ */ -+CRStatement * -+cr_stylesheet_statement_get_from_list (CRStyleSheet * a_this, int itemnr) -+{ -+ g_return_val_if_fail (a_this, NULL); -+ -+ return cr_statement_get_from_list (a_this->statements, itemnr); -+} -+ -+void -+cr_stylesheet_ref (CRStyleSheet * a_this) -+{ -+ g_return_if_fail (a_this); -+ -+ a_this->ref_count++; -+} -+ -+gboolean -+cr_stylesheet_unref (CRStyleSheet * a_this) -+{ -+ g_return_val_if_fail (a_this, FALSE); -+ -+ if (a_this->ref_count) -+ a_this->ref_count--; -+ -+ if (!a_this->ref_count) { -+ cr_stylesheet_destroy (a_this); -+ return TRUE; -+ } -+ -+ return FALSE; -+} -+ -+/** -+ *Destructor of the #CRStyleSheet class. -+ *@param a_this the current instance of the #CRStyleSheet class. -+ */ -+void -+cr_stylesheet_destroy (CRStyleSheet * a_this) -+{ -+ g_return_if_fail (a_this); -+ -+ if (a_this->statements) { -+ cr_statement_destroy (a_this->statements); -+ a_this->statements = NULL; -+ } -+ g_free (a_this); -+} -diff --git a/src/st/croco/cr-stylesheet.h b/src/st/croco/cr-stylesheet.h -new file mode 100644 -index 000000000..f35c94e37 ---- /dev/null -+++ b/src/st/croco/cr-stylesheet.h -@@ -0,0 +1,102 @@ -+/* -*- Mode: C; indent-tabs-mode: nil; c-basic-offset: 8 -*- */ -+ -+/* -+ * This file is part of The Croco Library -+ * -+ * 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 -+ * -+ * see COPYRIGHTS file for copyright information. -+ */ -+ -+ -+#ifndef __CR_STYLESHEET_H__ -+#define __CR_STYLESHEET_H__ -+ -+#include "cr-utils.h" -+#include "cr-statement.h" -+ -+G_BEGIN_DECLS -+ -+/** -+ *@file -+ *The declaration of the #CRStyleSheet class. -+ */ -+ -+ -+enum CRStyleOrigin -+{ -+ /*Please don't change the order of -+ *the values enumerated here ... -+ *New values should be added at the end, -+ *just before ORIGIN_END. -+ */ -+ ORIGIN_UA = 0, -+ ORIGIN_USER, -+ ORIGIN_AUTHOR, -+ -+ /*must always be the last one*/ -+ NB_ORIGINS -+} ; -+ -+/** -+ *An abstraction of a css stylesheet as defined -+ *by the css2 spec in chapter 4. -+ */ -+struct _CRStyleSheet -+{ -+ /**The css statements list*/ -+ CRStatement *statements ; -+ -+ enum CRStyleOrigin origin ; -+ -+ /*the parent import rule, if any.*/ -+ CRStatement *parent_import_rule ; -+ -+ /**custom data used by libcroco*/ -+ gpointer croco_data ; -+ -+ /** -+ *custom application data pointer -+ *Can be used by applications. -+ */ -+ gpointer app_data ; -+ -+ /** -+ *the reference count of this insance -+ *Please, don't never ever modify it -+ *directly. Use cr_stylesheet_ref() -+ *and cr_stylesheet_unref() instead. -+ */ -+ gulong ref_count ; -+} ; -+ -+CRStyleSheet * cr_stylesheet_new (CRStatement *a_stmts) ; -+ -+gchar * cr_stylesheet_to_string (CRStyleSheet const *a_this) ; -+void cr_stylesheet_dump (CRStyleSheet const *a_this, FILE *a_fp) ; -+ -+gint cr_stylesheet_nr_rules (CRStyleSheet const *a_this) ; -+ -+CRStatement * cr_stylesheet_statement_get_from_list (CRStyleSheet *a_this, int itemnr) ; -+ -+void cr_stylesheet_ref (CRStyleSheet *a_this) ; -+ -+gboolean cr_stylesheet_unref (CRStyleSheet *a_this) ; -+ -+void cr_stylesheet_destroy (CRStyleSheet *a_this) ; -+ -+G_END_DECLS -+ -+#endif /*__CR_STYLESHEET_H__*/ -diff --git a/src/st/croco/cr-term.c b/src/st/croco/cr-term.c -new file mode 100644 -index 000000000..9ffe6727b ---- /dev/null -+++ b/src/st/croco/cr-term.c -@@ -0,0 +1,790 @@ -+/* -*- Mode: C; indent-tabs-mode:nil; c-basic-offset: 8-*- */ -+ -+/* -+ * This file is part of The Croco Library -+ * -+ * 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 -+ * See COPYRIGHTS file for copyright information. -+ */ -+ -+#include -+#include -+#include "cr-term.h" -+#include "cr-num.h" -+#include "cr-parser.h" -+ -+/** -+ *@file -+ *Definition of the #CRTem class. -+ */ -+ -+static void -+cr_term_clear (CRTerm * a_this) -+{ -+ g_return_if_fail (a_this); -+ -+ switch (a_this->type) { -+ case TERM_NUMBER: -+ if (a_this->content.num) { -+ cr_num_destroy (a_this->content.num); -+ a_this->content.num = NULL; -+ } -+ break; -+ -+ case TERM_FUNCTION: -+ if (a_this->ext_content.func_param) { -+ cr_term_destroy (a_this->ext_content.func_param); -+ a_this->ext_content.func_param = NULL; -+ } -+ case TERM_STRING: -+ case TERM_IDENT: -+ case TERM_URI: -+ case TERM_HASH: -+ if (a_this->content.str) { -+ cr_string_destroy (a_this->content.str); -+ a_this->content.str = NULL; -+ } -+ break; -+ -+ case TERM_RGB: -+ if (a_this->content.rgb) { -+ cr_rgb_destroy (a_this->content.rgb); -+ a_this->content.rgb = NULL; -+ } -+ break; -+ -+ case TERM_UNICODERANGE: -+ case TERM_NO_TYPE: -+ default: -+ break; -+ } -+ -+ a_this->type = TERM_NO_TYPE; -+} -+ -+/** -+ *Instanciate a #CRTerm. -+ *@return the newly build instance -+ *of #CRTerm. -+ */ -+CRTerm * -+cr_term_new (void) -+{ -+ CRTerm *result = NULL; -+ -+ result = g_try_malloc (sizeof (CRTerm)); -+ if (!result) { -+ cr_utils_trace_info ("Out of memory"); -+ return NULL; -+ } -+ memset (result, 0, sizeof (CRTerm)); -+ return result; -+} -+ -+/** -+ *Parses an expresion as defined by the css2 spec -+ *and builds the expression as a list of terms. -+ *@param a_buf the buffer to parse. -+ *@return a pointer to the first term of the expression or -+ *NULL if parsing failed. -+ */ -+CRTerm * -+cr_term_parse_expression_from_buf (const guchar * a_buf, -+ enum CREncoding a_encoding) -+{ -+ CRParser *parser = NULL; -+ CRTerm *result = NULL; -+ enum CRStatus status = CR_OK; -+ -+ 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); -+ g_return_val_if_fail (parser, NULL); -+ -+ status = cr_parser_try_to_skip_spaces_and_comments (parser); -+ if (status != CR_OK) { -+ goto cleanup; -+ } -+ status = cr_parser_parse_expr (parser, &result); -+ if (status != CR_OK) { -+ if (result) { -+ cr_term_destroy (result); -+ result = NULL; -+ } -+ } -+ -+ cleanup: -+ if (parser) { -+ cr_parser_destroy (parser); -+ parser = NULL; -+ } -+ -+ return result; -+} -+ -+enum CRStatus -+cr_term_set_number (CRTerm * a_this, CRNum * a_num) -+{ -+ g_return_val_if_fail (a_this, CR_BAD_PARAM_ERROR); -+ -+ cr_term_clear (a_this); -+ -+ a_this->type = TERM_NUMBER; -+ a_this->content.num = a_num; -+ return CR_OK; -+} -+ -+enum CRStatus -+cr_term_set_function (CRTerm * a_this, CRString * a_func_name, -+ CRTerm * a_func_param) -+{ -+ g_return_val_if_fail (a_this, CR_BAD_PARAM_ERROR); -+ -+ cr_term_clear (a_this); -+ -+ a_this->type = TERM_FUNCTION; -+ a_this->content.str = a_func_name; -+ a_this->ext_content.func_param = a_func_param; -+ return CR_OK; -+} -+ -+enum CRStatus -+cr_term_set_string (CRTerm * a_this, CRString * a_str) -+{ -+ g_return_val_if_fail (a_this, CR_BAD_PARAM_ERROR); -+ -+ cr_term_clear (a_this); -+ -+ a_this->type = TERM_STRING; -+ a_this->content.str = a_str; -+ return CR_OK; -+} -+ -+enum CRStatus -+cr_term_set_ident (CRTerm * a_this, CRString * a_str) -+{ -+ g_return_val_if_fail (a_this, CR_BAD_PARAM_ERROR); -+ -+ cr_term_clear (a_this); -+ -+ a_this->type = TERM_IDENT; -+ a_this->content.str = a_str; -+ return CR_OK; -+} -+ -+enum CRStatus -+cr_term_set_uri (CRTerm * a_this, CRString * a_str) -+{ -+ g_return_val_if_fail (a_this, CR_BAD_PARAM_ERROR); -+ -+ cr_term_clear (a_this); -+ -+ a_this->type = TERM_URI; -+ a_this->content.str = a_str; -+ return CR_OK; -+} -+ -+enum CRStatus -+cr_term_set_rgb (CRTerm * a_this, CRRgb * a_rgb) -+{ -+ g_return_val_if_fail (a_this, CR_BAD_PARAM_ERROR); -+ -+ cr_term_clear (a_this); -+ -+ a_this->type = TERM_RGB; -+ a_this->content.rgb = a_rgb; -+ return CR_OK; -+} -+ -+enum CRStatus -+cr_term_set_hash (CRTerm * a_this, CRString * a_str) -+{ -+ g_return_val_if_fail (a_this, CR_BAD_PARAM_ERROR); -+ -+ cr_term_clear (a_this); -+ -+ a_this->type = TERM_HASH; -+ a_this->content.str = a_str; -+ return CR_OK; -+} -+ -+/** -+ *Appends a new term to the current list of #CRTerm. -+ * -+ *@param a_this the "this pointer" of the current instance -+ *of #CRTerm . -+ *@param a_new_term the term to append. -+ *@return the list of terms with the a_new_term appended to it. -+ */ -+CRTerm * -+cr_term_append_term (CRTerm * a_this, CRTerm * a_new_term) -+{ -+ CRTerm *cur = NULL; -+ -+ g_return_val_if_fail (a_new_term, NULL); -+ -+ if (a_this == NULL) -+ return a_new_term; -+ -+ for (cur = a_this; cur->next; cur = cur->next) ; -+ -+ cur->next = a_new_term; -+ a_new_term->prev = cur; -+ -+ return a_this; -+} -+ -+/** -+ *Prepends a term to the list of terms represented by a_this. -+ * -+ *@param a_this the "this pointer" of the current instance of -+ *#CRTerm . -+ *@param a_new_term the term to prepend. -+ *@return the head of the new list. -+ */ -+CRTerm * -+cr_term_prepend_term (CRTerm * a_this, CRTerm * a_new_term) -+{ -+ g_return_val_if_fail (a_this && a_new_term, NULL); -+ -+ a_new_term->next = a_this; -+ a_this->prev = a_new_term; -+ -+ return a_new_term; -+} -+ -+/** -+ *Serializes the expression represented by -+ *the chained instances of #CRterm. -+ *@param a_this the current instance of #CRTerm -+ *@return the zero terminated string containing the serialized -+ *form of #CRTerm. MUST BE FREED BY THE CALLER using g_free(). -+ */ -+guchar * -+cr_term_to_string (CRTerm const * a_this) -+{ -+ GString *str_buf = NULL; -+ CRTerm const *cur = NULL; -+ guchar *result = NULL, -+ *content = NULL; -+ -+ g_return_val_if_fail (a_this, NULL); -+ -+ str_buf = g_string_new (NULL); -+ g_return_val_if_fail (str_buf, NULL); -+ -+ for (cur = a_this; cur; cur = cur->next) { -+ if ((cur->content.str == NULL) -+ && (cur->content.num == NULL) -+ && (cur->content.str == NULL) -+ && (cur->content.rgb == NULL)) -+ continue; -+ -+ switch (cur->the_operator) { -+ case DIVIDE: -+ g_string_append (str_buf, " / "); -+ break; -+ -+ case COMMA: -+ g_string_append (str_buf, ", "); -+ break; -+ -+ case NO_OP: -+ if (cur->prev) { -+ g_string_append (str_buf, " "); -+ } -+ break; -+ default: -+ -+ break; -+ } -+ -+ switch (cur->unary_op) { -+ case PLUS_UOP: -+ g_string_append (str_buf, "+"); -+ break; -+ -+ case MINUS_UOP: -+ g_string_append (str_buf, "-"); -+ break; -+ -+ default: -+ break; -+ } -+ -+ switch (cur->type) { -+ case TERM_NUMBER: -+ if (cur->content.num) { -+ content = cr_num_to_string (cur->content.num); -+ } -+ -+ if (content) { -+ g_string_append (str_buf, (const gchar *) content); -+ g_free (content); -+ content = NULL; -+ } -+ -+ break; -+ -+ case TERM_FUNCTION: -+ if (cur->content.str) { -+ content = (guchar *) g_strndup -+ (cur->content.str->stryng->str, -+ cur->content.str->stryng->len); -+ } -+ -+ if (content) { -+ g_string_append_printf (str_buf, "%s(", -+ content); -+ -+ if (cur->ext_content.func_param) { -+ guchar *tmp_str = NULL; -+ -+ tmp_str = cr_term_to_string -+ (cur-> -+ ext_content.func_param); -+ -+ if (tmp_str) { -+ g_string_append (str_buf, -+ (const gchar *) tmp_str); -+ g_free (tmp_str); -+ tmp_str = NULL; -+ } -+ } -+ g_string_append (str_buf, ")"); -+ g_free (content); -+ content = NULL; -+ } -+ -+ break; -+ -+ case TERM_STRING: -+ if (cur->content.str) { -+ content = (guchar *) g_strndup -+ (cur->content.str->stryng->str, -+ cur->content.str->stryng->len); -+ } -+ -+ if (content) { -+ g_string_append_printf (str_buf, -+ "\"%s\"", content); -+ g_free (content); -+ content = NULL; -+ } -+ break; -+ -+ case TERM_IDENT: -+ if (cur->content.str) { -+ content = (guchar *) g_strndup -+ (cur->content.str->stryng->str, -+ cur->content.str->stryng->len); -+ } -+ -+ if (content) { -+ g_string_append (str_buf, (const gchar *) content); -+ g_free (content); -+ content = NULL; -+ } -+ break; -+ -+ case TERM_URI: -+ if (cur->content.str) { -+ content = (guchar *) g_strndup -+ (cur->content.str->stryng->str, -+ cur->content.str->stryng->len); -+ } -+ -+ if (content) { -+ g_string_append_printf -+ (str_buf, "url(%s)", content); -+ g_free (content); -+ content = NULL; -+ } -+ break; -+ -+ case TERM_RGB: -+ if (cur->content.rgb) { -+ guchar *tmp_str = NULL; -+ -+ g_string_append (str_buf, "rgb("); -+ tmp_str = cr_rgb_to_string (cur->content.rgb); -+ -+ if (tmp_str) { -+ g_string_append (str_buf, (const gchar *) tmp_str); -+ g_free (tmp_str); -+ tmp_str = NULL; -+ } -+ g_string_append (str_buf, ")"); -+ } -+ -+ break; -+ -+ case TERM_UNICODERANGE: -+ g_string_append -+ (str_buf, -+ "?found unicoderange: dump not supported yet?"); -+ break; -+ -+ case TERM_HASH: -+ if (cur->content.str) { -+ content = (guchar *) g_strndup -+ (cur->content.str->stryng->str, -+ cur->content.str->stryng->len); -+ } -+ -+ if (content) { -+ g_string_append_printf (str_buf, -+ "#%s", content); -+ g_free (content); -+ content = NULL; -+ } -+ break; -+ -+ default: -+ g_string_append (str_buf, -+ "Unrecognized Term type"); -+ break; -+ } -+ } -+ -+ if (str_buf) { -+ result =(guchar *) str_buf->str; -+ g_string_free (str_buf, FALSE); -+ str_buf = NULL; -+ } -+ -+ return result; -+} -+ -+guchar * -+cr_term_one_to_string (CRTerm const * a_this) -+{ -+ GString *str_buf = NULL; -+ guchar *result = NULL, -+ *content = NULL; -+ -+ g_return_val_if_fail (a_this, NULL); -+ -+ str_buf = g_string_new (NULL); -+ g_return_val_if_fail (str_buf, NULL); -+ -+ if ((a_this->content.str == NULL) -+ && (a_this->content.num == NULL) -+ && (a_this->content.str == NULL) -+ && (a_this->content.rgb == NULL)) -+ return NULL ; -+ -+ switch (a_this->the_operator) { -+ case DIVIDE: -+ g_string_append_printf (str_buf, " / "); -+ break; -+ -+ case COMMA: -+ g_string_append_printf (str_buf, ", "); -+ break; -+ -+ case NO_OP: -+ if (a_this->prev) { -+ g_string_append_printf (str_buf, " "); -+ } -+ break; -+ default: -+ -+ break; -+ } -+ -+ switch (a_this->unary_op) { -+ case PLUS_UOP: -+ g_string_append_printf (str_buf, "+"); -+ break; -+ -+ case MINUS_UOP: -+ g_string_append_printf (str_buf, "-"); -+ break; -+ -+ default: -+ break; -+ } -+ -+ switch (a_this->type) { -+ case TERM_NUMBER: -+ if (a_this->content.num) { -+ content = cr_num_to_string (a_this->content.num); -+ } -+ -+ if (content) { -+ g_string_append (str_buf, (const gchar *) content); -+ g_free (content); -+ content = NULL; -+ } -+ -+ break; -+ -+ case TERM_FUNCTION: -+ if (a_this->content.str) { -+ content = (guchar *) g_strndup -+ (a_this->content.str->stryng->str, -+ a_this->content.str->stryng->len); -+ } -+ -+ if (content) { -+ g_string_append_printf (str_buf, "%s(", -+ content); -+ -+ if (a_this->ext_content.func_param) { -+ guchar *tmp_str = NULL; -+ -+ tmp_str = cr_term_to_string -+ (a_this-> -+ ext_content.func_param); -+ -+ if (tmp_str) { -+ g_string_append_printf -+ (str_buf, -+ "%s", tmp_str); -+ g_free (tmp_str); -+ tmp_str = NULL; -+ } -+ -+ g_string_append_printf (str_buf, ")"); -+ g_free (content); -+ content = NULL; -+ } -+ } -+ -+ break; -+ -+ case TERM_STRING: -+ if (a_this->content.str) { -+ content = (guchar *) g_strndup -+ (a_this->content.str->stryng->str, -+ a_this->content.str->stryng->len); -+ } -+ -+ if (content) { -+ g_string_append_printf (str_buf, -+ "\"%s\"", content); -+ g_free (content); -+ content = NULL; -+ } -+ break; -+ -+ case TERM_IDENT: -+ if (a_this->content.str) { -+ content = (guchar *) g_strndup -+ (a_this->content.str->stryng->str, -+ a_this->content.str->stryng->len); -+ } -+ -+ if (content) { -+ g_string_append (str_buf, (const gchar *) content); -+ g_free (content); -+ content = NULL; -+ } -+ break; -+ -+ case TERM_URI: -+ if (a_this->content.str) { -+ content = (guchar *) g_strndup -+ (a_this->content.str->stryng->str, -+ a_this->content.str->stryng->len); -+ } -+ -+ if (content) { -+ g_string_append_printf -+ (str_buf, "url(%s)", content); -+ g_free (content); -+ content = NULL; -+ } -+ break; -+ -+ case TERM_RGB: -+ if (a_this->content.rgb) { -+ guchar *tmp_str = NULL; -+ -+ g_string_append_printf (str_buf, "rgb("); -+ tmp_str = cr_rgb_to_string (a_this->content.rgb); -+ -+ if (tmp_str) { -+ g_string_append (str_buf, (const gchar *) tmp_str); -+ g_free (tmp_str); -+ tmp_str = NULL; -+ } -+ g_string_append_printf (str_buf, ")"); -+ } -+ -+ break; -+ -+ case TERM_UNICODERANGE: -+ g_string_append_printf -+ (str_buf, -+ "?found unicoderange: dump not supported yet?"); -+ break; -+ -+ case TERM_HASH: -+ if (a_this->content.str) { -+ content = (guchar *) g_strndup -+ (a_this->content.str->stryng->str, -+ a_this->content.str->stryng->len); -+ } -+ -+ if (content) { -+ g_string_append_printf (str_buf, -+ "#%s", content); -+ g_free (content); -+ content = NULL; -+ } -+ break; -+ -+ default: -+ g_string_append_printf (str_buf, -+ "%s", -+ "Unrecognized Term type"); -+ break; -+ } -+ -+ if (str_buf) { -+ result = (guchar *) str_buf->str; -+ g_string_free (str_buf, FALSE); -+ str_buf = NULL; -+ } -+ -+ return result; -+} -+ -+/** -+ *Dumps the expression (a list of terms connected by operators) -+ *to a file. -+ *TODO: finish the dump. The dump of some type of terms have not yet been -+ *implemented. -+ *@param a_this the current instance of #CRTerm. -+ *@param a_fp the destination file pointer. -+ */ -+void -+cr_term_dump (CRTerm const * a_this, FILE * a_fp) -+{ -+ guchar *content = NULL; -+ -+ g_return_if_fail (a_this); -+ -+ content = cr_term_to_string (a_this); -+ -+ if (content) { -+ fprintf (a_fp, "%s", content); -+ g_free (content); -+ } -+} -+ -+/** -+ *Return the number of terms in the expression. -+ *@param a_this the current instance of #CRTerm. -+ *@return number of terms in the expression. -+ */ -+int -+cr_term_nr_values (CRTerm const *a_this) -+{ -+ CRTerm 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; -+} -+ -+/** -+ *Use an index to get a CRTerm from the expression. -+ *@param a_this the current instance of #CRTerm. -+ *@param itemnr the index into the expression. -+ *@return CRTerm at position itemnr, if itemnr > number of terms - 1, -+ *it will return NULL. -+ */ -+CRTerm * -+cr_term_get_from_list (CRTerm *a_this, int itemnr) -+{ -+ CRTerm *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; -+} -+ -+/** -+ *Increments the reference counter of the current instance -+ *of #CRTerm.* -+ *@param a_this the current instance of #CRTerm. -+ */ -+void -+cr_term_ref (CRTerm * a_this) -+{ -+ g_return_if_fail (a_this); -+ -+ a_this->ref_count++; -+} -+ -+/** -+ *Decrements the ref count of the current instance of -+ *#CRTerm. If the ref count reaches zero, the instance is -+ *destroyed. -+ *@param a_this the current instance of #CRTerm. -+ *@return TRUE if the current instance has been destroyed, FALSE otherwise. -+ */ -+gboolean -+cr_term_unref (CRTerm * a_this) -+{ -+ g_return_val_if_fail (a_this, FALSE); -+ -+ if (a_this->ref_count) { -+ a_this->ref_count--; -+ } -+ -+ if (a_this->ref_count == 0) { -+ cr_term_destroy (a_this); -+ return TRUE; -+ } -+ -+ return FALSE; -+} -+ -+/** -+ *The destructor of the the #CRTerm class. -+ *@param a_this the "this pointer" of the current instance -+ *of #CRTerm. -+ */ -+void -+cr_term_destroy (CRTerm * a_this) -+{ -+ g_return_if_fail (a_this); -+ -+ cr_term_clear (a_this); -+ -+ if (a_this->next) { -+ cr_term_destroy (a_this->next); -+ a_this->next = NULL; -+ } -+ -+ if (a_this) { -+ g_free (a_this); -+ } -+ -+} -diff --git a/src/st/croco/cr-term.h b/src/st/croco/cr-term.h -new file mode 100644 -index 000000000..0f22dda75 ---- /dev/null -+++ b/src/st/croco/cr-term.h -@@ -0,0 +1,190 @@ -+/* -*- Mode: C; indent-tabs-mode:nil; c-basic-offset: 8-*- */ -+ -+/* -+ * This file is part of The Croco Library -+ * -+ * 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 -+ * See COPYRIGHTS file for copyright information. -+ */ -+ -+#include -+#include -+#include "cr-utils.h" -+#include "cr-rgb.h" -+#include "cr-num.h" -+#include "cr-string.h" -+ -+#ifndef __CR_TERM_H__ -+#define __CR_TERM_H__ -+ -+G_BEGIN_DECLS -+ -+/** -+ *@file -+ *Declaration of the #CRTem class. -+ */ -+ -+enum CRTermType -+{ -+ TERM_NO_TYPE = 0, -+ TERM_NUMBER, -+ TERM_FUNCTION, -+ TERM_STRING, -+ TERM_IDENT, -+ TERM_URI, -+ TERM_RGB, -+ TERM_UNICODERANGE, -+ TERM_HASH -+} ; -+ -+ -+enum UnaryOperator -+{ -+ NO_UNARY_UOP = 0, -+ PLUS_UOP, -+ MINUS_UOP, -+ EMPTY_UNARY_UOP -+} ; -+ -+enum Operator -+{ -+ NO_OP = 0, -+ DIVIDE, -+ COMMA -+} ; -+ -+struct _CRTerm ; -+typedef struct _CRTerm CRTerm ; -+ -+/** -+ *An abstraction of a css2 term as -+ *defined in the CSS2 spec in appendix D.1: -+ *term ::= -+ *[ NUMBER S* | PERCENTAGE S* | LENGTH S* | EMS S* | EXS S* -+ *| ANGLE S* | TIME S* | FREQ S* | function ] -+ * | STRING S* | IDENT S* | URI S* | RGB S* -+ *| UNICODERANGE S* | hexcolor -+ */ -+struct _CRTerm -+{ -+ /** -+ *The type of the term. -+ */ -+ enum CRTermType type ; -+ -+ /** -+ *The unary operator associated to -+ *the current term. -+ */ -+ enum UnaryOperator unary_op ; -+ -+ /** -+ *The operator associated to the current term. -+ */ -+ enum Operator the_operator ; -+ -+ -+ /** -+ *The content of the term. -+ *Depending of the type of the term, -+ *this holds either a number, a percentage ... -+ */ -+ union -+ { -+ CRNum *num ; -+ CRString * str ; -+ CRRgb * rgb ; -+ } content ; -+ -+ /** -+ *If the term is of type UNICODERANGE, -+ *this field holds the upper bound of the range. -+ *if the term is of type FUNCTION, this holds -+ *an instance of CRTerm that represents -+ * the expression which is the argument of the function. -+ */ -+ union -+ { -+ CRTerm *func_param ; -+ } ext_content ; -+ -+ /** -+ *A spare pointer, just in case. -+ *Can be used by the application. -+ */ -+ gpointer app_data ; -+ -+ glong ref_count ; -+ -+ /** -+ *A pointer to the next term, -+ *just in case this term is part of -+ *an expression. -+ */ -+ CRTerm *next ; -+ -+ /** -+ *A pointer to the previous -+ *term. -+ */ -+ CRTerm *prev ; -+ CRParsingLocation location ; -+} ; -+ -+CRTerm * cr_term_parse_expression_from_buf (const guchar *a_buf, -+ enum CREncoding a_encoding) ; -+CRTerm * cr_term_new (void) ; -+ -+enum CRStatus cr_term_set_number (CRTerm *a_this, CRNum *a_num) ; -+ -+enum CRStatus cr_term_set_function (CRTerm *a_this, -+ CRString *a_func_name, -+ CRTerm *a_func_param) ; -+ -+enum CRStatus cr_term_set_string (CRTerm *a_this, CRString *a_str) ; -+ -+enum CRStatus cr_term_set_ident (CRTerm *a_this, CRString *a_str) ; -+ -+enum CRStatus cr_term_set_uri (CRTerm *a_this, CRString *a_str) ; -+ -+enum CRStatus cr_term_set_rgb (CRTerm *a_this, CRRgb *a_rgb) ; -+ -+enum CRStatus cr_term_set_hash (CRTerm *a_this, CRString *a_str) ; -+ -+CRTerm * cr_term_append_term (CRTerm *a_this, CRTerm *a_new_term) ; -+ -+CRTerm * cr_term_prepend_term (CRTerm *a_this, CRTerm *a_new_term) ; -+ -+guchar * cr_term_to_string (CRTerm const *a_this) ; -+ -+guchar * cr_term_one_to_string (CRTerm const * a_this) ; -+ -+void cr_term_dump (CRTerm const *a_this, FILE *a_fp) ; -+ -+int cr_term_nr_values (CRTerm const *a_this) ; -+ -+CRTerm * cr_term_get_from_list (CRTerm *a_this, int itemnr) ; -+ -+void cr_term_ref (CRTerm *a_this) ; -+ -+gboolean cr_term_unref (CRTerm *a_this) ; -+ -+void cr_term_destroy (CRTerm * a_term) ; -+ -+G_END_DECLS -+ -+#endif /*__CR_TERM_H__*/ -diff --git a/src/st/croco/cr-tknzr.c b/src/st/croco/cr-tknzr.c -new file mode 100644 -index 000000000..1548c35c6 ---- /dev/null -+++ b/src/st/croco/cr-tknzr.c -@@ -0,0 +1,2762 @@ -+/* -*- Mode: C; indent-tabs-mode:nil; c-basic-offset: 8-*- */ -+ -+/* -+ * This file is part of The Croco Library -+ * -+ * 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 -+ * See the COPYRIGHTS file for copyrights information. -+ */ -+ -+/** -+ *@file -+ *The definition of the #CRTknzr (tokenizer) -+ *class. -+ */ -+ -+#include "string.h" -+#include "cr-tknzr.h" -+#include "cr-doc-handler.h" -+ -+struct _CRTknzrPriv { -+ /**The parser input stream of bytes*/ -+ CRInput *input; -+ -+ /** -+ *A cache where tknzr_unget_token() -+ *puts back the token. tknzr_get_next_token() -+ *first look in this cache, and if and -+ *only if it's empty, fetches the next token -+ *from the input stream. -+ */ -+ CRToken *token_cache; -+ -+ /** -+ *The position of the end of the previous token -+ *or char fetched. -+ */ -+ CRInputPos prev_pos; -+ -+ CRDocHandler *sac_handler; -+ -+ /** -+ *The reference count of the current instance -+ *of #CRTknzr. Is manipulated by cr_tknzr_ref() -+ *and cr_tknzr_unref(). -+ */ -+ glong ref_count; -+}; -+ -+#define PRIVATE(obj) ((obj)->priv) -+ -+/** -+ *return TRUE if the character is a number ([0-9]), FALSE otherwise -+ *@param a_char the char to test. -+ */ -+#define IS_NUM(a_char) (((a_char) >= '0' && (a_char) <= '9')?TRUE:FALSE) -+ -+/** -+ *Checks if 'status' equals CR_OK. If not, goto the 'error' label. -+ * -+ *@param status the status (of type enum CRStatus) to test. -+ *@param is_exception if set to FALSE, the final status returned the -+ *current function will be CR_PARSING_ERROR. If set to TRUE, the -+ *current status will be the current value of the 'status' variable. -+ * -+ */ -+#define CHECK_PARSING_STATUS(status, is_exception) \ -+if ((status) != CR_OK) \ -+{ \ -+ if (is_exception == FALSE) \ -+ { \ -+ status = CR_PARSING_ERROR ; \ -+ } \ -+ goto error ; \ -+} -+ -+/** -+ *Peeks the next char from the input stream of the current tokenizer. -+ *invokes CHECK_PARSING_STATUS on the status returned by -+ *cr_tknzr_input_peek_char(). -+ * -+ *@param the current instance of #CRTkzr. -+ *@param to_char a pointer to the char where to store the -+ *char peeked. -+ */ -+#define PEEK_NEXT_CHAR(a_tknzr, a_to_char) \ -+{\ -+status = cr_tknzr_peek_char (a_tknzr, a_to_char) ; \ -+CHECK_PARSING_STATUS (status, TRUE) \ -+} -+ -+/** -+ *Reads the next char from the input stream of the current parser. -+ *In case of error, jumps to the "error:" label located in the -+ *function where this macro is called. -+ *@param parser the curent instance of #CRTknzr -+ *@param to_char a pointer to the guint32 char where to store -+ *the character read. -+ */ -+#define READ_NEXT_CHAR(a_tknzr, to_char) \ -+status = cr_tknzr_read_char (a_tknzr, to_char) ;\ -+CHECK_PARSING_STATUS (status, TRUE) -+ -+/** -+ *Gets information about the current position in -+ *the input of the parser. -+ *In case of failure, this macro returns from the -+ *calling function and -+ *returns a status code of type enum #CRStatus. -+ *@param parser the current instance of #CRTknzr. -+ *@param pos out parameter. A pointer to the position -+ *inside the current parser input. Must -+ */ -+#define RECORD_INITIAL_POS(a_tknzr, a_pos) \ -+status = cr_input_get_cur_pos (PRIVATE \ -+(a_tknzr)->input, a_pos) ; \ -+g_return_val_if_fail (status == CR_OK, status) -+ -+/** -+ *Gets the address of the current byte inside the -+ *parser input. -+ *@param parser the current instance of #CRTknzr. -+ *@param addr out parameter a pointer (guchar*) -+ *to where the address must be put. -+ */ -+#define RECORD_CUR_BYTE_ADDR(a_tknzr, a_addr) \ -+status = cr_input_get_cur_byte_addr \ -+ (PRIVATE (a_tknzr)->input, a_addr) ; \ -+CHECK_PARSING_STATUS (status, TRUE) -+ -+/** -+ *Peeks a byte from the topmost parser input at -+ *a given offset from the current position. -+ *If it fails, goto the "error:" label. -+ * -+ *@param a_parser the current instance of #CRTknzr. -+ *@param a_offset the offset of the byte to peek, the -+ *current byte having the offset '0'. -+ *@param a_byte_ptr out parameter a pointer (guchar*) to -+ *where the peeked char is to be stored. -+ */ -+#define PEEK_BYTE(a_tknzr, a_offset, a_byte_ptr) \ -+status = cr_tknzr_peek_byte (a_tknzr, \ -+ a_offset, \ -+ a_byte_ptr) ; \ -+CHECK_PARSING_STATUS (status, TRUE) ; -+ -+#define BYTE(a_input, a_n, a_eof) \ -+cr_input_peek_byte2 (a_input, a_n, a_eof) -+ -+/** -+ *Reads a byte from the topmost parser input -+ *steam. -+ *If it fails, goto the "error" label. -+ *@param a_parser the current instance of #CRTknzr. -+ *@param a_byte_ptr the guchar * where to put the read char. -+ */ -+#define READ_NEXT_BYTE(a_tknzr, a_byte_ptr) \ -+status = \ -+cr_input_read_byte (PRIVATE (a_tknzr)->input, a_byte_ptr) ;\ -+CHECK_PARSING_STATUS (status, TRUE) ; -+ -+/** -+ *Skips a given number of byte in the topmost -+ *parser input. Don't update line and column number. -+ *In case of error, jumps to the "error:" label -+ *of the surrounding function. -+ *@param a_parser the current instance of #CRTknzr. -+ *@param a_nb_bytes the number of bytes to skip. -+ */ -+#define SKIP_BYTES(a_tknzr, a_nb_bytes) \ -+status = cr_input_seek_index (PRIVATE (a_tknzr)->input, \ -+ CR_SEEK_CUR, a_nb_bytes) ; \ -+CHECK_PARSING_STATUS (status, TRUE) ; -+ -+/** -+ *Skip utf8 encoded characters. -+ *Updates line and column numbers. -+ *@param a_parser the current instance of #CRTknzr. -+ *@param a_nb_chars the number of chars to skip. Must be of -+ *type glong. -+ */ -+#define SKIP_CHARS(a_tknzr, a_nb_chars) \ -+{ \ -+gulong nb_chars = a_nb_chars ; \ -+status = cr_input_consume_chars \ -+ (PRIVATE (a_tknzr)->input,0, &nb_chars) ; \ -+CHECK_PARSING_STATUS (status, TRUE) ; \ -+} -+ -+/** -+ *Tests the condition and if it is false, sets -+ *status to "CR_PARSING_ERROR" and goto the 'error' -+ *label. -+ *@param condition the condition to test. -+ */ -+#define ENSURE_PARSING_COND(condition) \ -+if (! (condition)) {status = CR_PARSING_ERROR; goto error ;} -+ -+static enum CRStatus cr_tknzr_parse_nl (CRTknzr * a_this, -+ guchar ** a_start, -+ guchar ** a_end, -+ CRParsingLocation *a_location); -+ -+static enum CRStatus cr_tknzr_parse_w (CRTknzr * a_this, -+ guchar ** a_start, -+ guchar ** a_end, -+ CRParsingLocation *a_location) ; -+ -+static enum CRStatus cr_tknzr_parse_unicode_escape (CRTknzr * a_this, -+ guint32 * a_unicode, -+ CRParsingLocation *a_location) ; -+ -+static enum CRStatus cr_tknzr_parse_escape (CRTknzr * a_this, -+ guint32 * a_esc_code, -+ CRParsingLocation *a_location); -+ -+static enum CRStatus cr_tknzr_parse_string (CRTknzr * a_this, -+ CRString ** a_str); -+ -+static enum CRStatus cr_tknzr_parse_comment (CRTknzr * a_this, -+ CRString ** a_comment); -+ -+static enum CRStatus cr_tknzr_parse_nmstart (CRTknzr * a_this, -+ guint32 * a_char, -+ CRParsingLocation *a_location); -+ -+static enum CRStatus cr_tknzr_parse_num (CRTknzr * a_this, -+ CRNum ** a_num); -+ -+/********************************** -+ *PRIVATE methods -+ **********************************/ -+ -+/** -+ *Parses a "w" as defined by the css spec at [4.1.1]: -+ * w ::= [ \t\r\n\f]* -+ * -+ *@param a_this the current instance of #CRTknzr. -+ *@param a_start out param. Upon successfull completion, points -+ *to the beginning of the parsed white space, points to NULL otherwise. -+ *Can also point to NULL is there is no white space actually. -+ *@param a_end out param. Upon successfull completion, points -+ *to the end of the parsed white space, points to NULL otherwise. -+ *Can also point to NULL is there is no white space actually. -+ */ -+static enum CRStatus -+cr_tknzr_parse_w (CRTknzr * a_this, -+ guchar ** a_start, -+ guchar ** a_end, -+ CRParsingLocation *a_location) -+{ -+ guint32 cur_char = 0; -+ CRInputPos init_pos; -+ enum CRStatus status = CR_OK; -+ -+ g_return_val_if_fail (a_this && PRIVATE (a_this) -+ && PRIVATE (a_this)->input -+ && a_start && a_end, -+ CR_BAD_PARAM_ERROR); -+ -+ RECORD_INITIAL_POS (a_this, &init_pos); -+ -+ *a_start = NULL; -+ *a_end = NULL; -+ -+ READ_NEXT_CHAR (a_this, &cur_char); -+ -+ if (cr_utils_is_white_space (cur_char) == FALSE) { -+ status = CR_PARSING_ERROR; -+ goto error; -+ } -+ if (a_location) { -+ cr_tknzr_get_parsing_location (a_this, -+ a_location) ; -+ } -+ RECORD_CUR_BYTE_ADDR (a_this, a_start); -+ *a_end = *a_start; -+ -+ for (;;) { -+ gboolean is_eof = FALSE; -+ -+ cr_input_get_end_of_file (PRIVATE (a_this)->input, &is_eof); -+ if (is_eof) -+ break; -+ -+ status = cr_tknzr_peek_char (a_this, &cur_char); -+ if (status == CR_END_OF_INPUT_ERROR) { -+ break; -+ } else if (status != CR_OK) { -+ goto error; -+ } -+ -+ if (cr_utils_is_white_space (cur_char) == TRUE) { -+ READ_NEXT_CHAR (a_this, &cur_char); -+ RECORD_CUR_BYTE_ADDR (a_this, a_end); -+ } else { -+ break; -+ } -+ } -+ -+ return CR_OK; -+ -+ error: -+ cr_tknzr_set_cur_pos (a_this, &init_pos); -+ -+ return status; -+} -+ -+/** -+ *Parses a newline as defined in the css2 spec: -+ * nl ::= \n|\r\n|\r|\f -+ * -+ *@param a_this the "this pointer" of the current instance of #CRTknzr. -+ *@param a_start a pointer to the first character of the successfully -+ *parsed string. -+ *@param a_end a pointer to the last character of the successfully parsed -+ *string. -+ *@result CR_OK uppon successfull completion, an error code otherwise. -+ */ -+static enum CRStatus -+cr_tknzr_parse_nl (CRTknzr * a_this, -+ guchar ** a_start, -+ guchar ** a_end, -+ CRParsingLocation *a_location) -+{ -+ CRInputPos init_pos; -+ guchar next_chars[2] = { 0 }; -+ enum CRStatus status = CR_PARSING_ERROR; -+ -+ g_return_val_if_fail (a_this && PRIVATE (a_this) -+ && a_start && a_end, CR_BAD_PARAM_ERROR); -+ -+ RECORD_INITIAL_POS (a_this, &init_pos); -+ -+ PEEK_BYTE (a_this, 1, &next_chars[0]); -+ PEEK_BYTE (a_this, 2, &next_chars[1]); -+ -+ if ((next_chars[0] == '\r' && next_chars[1] == '\n')) { -+ SKIP_BYTES (a_this, 1); -+ if (a_location) { -+ cr_tknzr_get_parsing_location -+ (a_this, a_location) ; -+ } -+ SKIP_CHARS (a_this, 1); -+ -+ RECORD_CUR_BYTE_ADDR (a_this, a_end); -+ -+ status = CR_OK; -+ } else if (next_chars[0] == '\n' -+ || next_chars[0] == '\r' || next_chars[0] == '\f') { -+ SKIP_CHARS (a_this, 1); -+ if (a_location) { -+ cr_tknzr_get_parsing_location -+ (a_this, a_location) ; -+ } -+ RECORD_CUR_BYTE_ADDR (a_this, a_start); -+ *a_end = *a_start; -+ status = CR_OK; -+ } else { -+ status = CR_PARSING_ERROR; -+ goto error; -+ } -+ return CR_OK ; -+ -+ error: -+ cr_tknzr_set_cur_pos (a_this, &init_pos) ; -+ return status; -+} -+ -+/** -+ *Go ahead in the parser input, skipping all the spaces. -+ *If the next char if not a white space, this function does nothing. -+ *In any cases, it stops when it encounters a non white space character. -+ * -+ *@param a_this the current instance of #CRTknzr. -+ *@return CR_OK upon successfull completion, an error code otherwise. -+ */ -+static enum CRStatus -+cr_tknzr_try_to_skip_spaces (CRTknzr * a_this) -+{ -+ enum CRStatus status = CR_ERROR; -+ guint32 cur_char = 0; -+ -+ g_return_val_if_fail (a_this && PRIVATE (a_this) -+ && PRIVATE (a_this)->input, CR_BAD_PARAM_ERROR); -+ -+ status = cr_input_peek_char (PRIVATE (a_this)->input, &cur_char); -+ -+ if (status != CR_OK) { -+ if (status == CR_END_OF_INPUT_ERROR) -+ return CR_OK; -+ return status; -+ } -+ -+ if (cr_utils_is_white_space (cur_char) == TRUE) { -+ gulong nb_chars = -1; /*consume all spaces */ -+ -+ status = cr_input_consume_white_spaces -+ (PRIVATE (a_this)->input, &nb_chars); -+ } -+ -+ return status; -+} -+ -+/** -+ *Parses a "comment" as defined in the css spec at [4.1.1]: -+ *COMMENT ::= \/\*[^*]*\*+([^/][^*]*\*+)*\/ . -+ *This complex regexp is just to say that comments start -+ *with the two chars '/''*' and ends with the two chars '*''/'. -+ *It also means that comments cannot be nested. -+ *So based on that, I've just tried to implement the parsing function -+ *simply and in a straight forward manner. -+ */ -+static enum CRStatus -+cr_tknzr_parse_comment (CRTknzr * a_this, -+ CRString ** a_comment) -+{ -+ enum CRStatus status = CR_OK; -+ CRInputPos init_pos; -+ guint32 cur_char = 0, next_char= 0; -+ CRString *comment = NULL; -+ CRParsingLocation loc = {0} ; -+ -+ g_return_val_if_fail (a_this && PRIVATE (a_this) -+ && PRIVATE (a_this)->input, -+ CR_BAD_PARAM_ERROR); -+ -+ RECORD_INITIAL_POS (a_this, &init_pos); -+ READ_NEXT_CHAR (a_this, &cur_char) ; -+ ENSURE_PARSING_COND (cur_char == '/'); -+ cr_tknzr_get_parsing_location (a_this, &loc) ; -+ -+ READ_NEXT_CHAR (a_this, &cur_char); -+ ENSURE_PARSING_COND (cur_char == '*'); -+ comment = cr_string_new (); -+ for (;;) { /* [^*]* */ -+ PEEK_NEXT_CHAR (a_this, &next_char); -+ if (next_char == '*') -+ break; -+ READ_NEXT_CHAR (a_this, &cur_char); -+ g_string_append_unichar (comment->stryng, cur_char); -+ } -+ /* Stop condition: next_char == '*' */ -+ for (;;) { /* \*+ */ -+ READ_NEXT_CHAR(a_this, &cur_char); -+ ENSURE_PARSING_COND (cur_char == '*'); -+ g_string_append_unichar (comment->stryng, cur_char); -+ PEEK_NEXT_CHAR (a_this, &next_char); -+ if (next_char != '*') -+ break; -+ } -+ /* Stop condition: next_char != '*' */ -+ for (;;) { /* ([^/][^*]*\*+)* */ -+ if (next_char == '/') -+ break; -+ READ_NEXT_CHAR(a_this, &cur_char); -+ g_string_append_unichar (comment->stryng, cur_char); -+ for (;;) { /* [^*]* */ -+ PEEK_NEXT_CHAR (a_this, &next_char); -+ if (next_char == '*') -+ break; -+ READ_NEXT_CHAR (a_this, &cur_char); -+ g_string_append_unichar (comment->stryng, cur_char); -+ } -+ /* Stop condition: next_char = '*', no need to verify, because peek and read exit to error anyway */ -+ for (;;) { /* \*+ */ -+ READ_NEXT_CHAR(a_this, &cur_char); -+ ENSURE_PARSING_COND (cur_char == '*'); -+ g_string_append_unichar (comment->stryng, cur_char); -+ PEEK_NEXT_CHAR (a_this, &next_char); -+ if (next_char != '*') -+ break; -+ } -+ /* Continue condition: next_char != '*' */ -+ } -+ /* Stop condition: next_char == '\/' */ -+ READ_NEXT_CHAR(a_this, &cur_char); -+ g_string_append_unichar (comment->stryng, cur_char); -+ -+ if (status == CR_OK) { -+ cr_parsing_location_copy (&comment->location, -+ &loc) ; -+ *a_comment = comment; -+ return CR_OK; -+ } -+ error: -+ -+ if (comment) { -+ cr_string_destroy (comment); -+ comment = NULL; -+ } -+ -+ cr_tknzr_set_cur_pos (a_this, &init_pos); -+ -+ return status; -+} -+ -+/** -+ *Parses an 'unicode' escape sequence defined -+ *in css spec at chap 4.1.1: -+ *unicode ::= \\[0-9a-f]{1,6}[ \n\r\t\f]? -+ *@param a_this the current instance of #CRTknzr. -+ *@param a_start out parameter. A pointer to the start -+ *of the unicode escape sequence. Must *NOT* be deleted by -+ *the caller. -+ *@param a_end out parameter. A pointer to the last character -+ *of the unicode escape sequence. Must *NOT* be deleted by the caller. -+ *@return CR_OK if parsing succeded, an error code otherwise. -+ *Error code can be either CR_PARSING_ERROR if the string -+ *parsed just doesn't -+ *respect the production or another error if a -+ *lower level error occurred. -+ */ -+static enum CRStatus -+cr_tknzr_parse_unicode_escape (CRTknzr * a_this, -+ guint32 * a_unicode, -+ CRParsingLocation *a_location) -+{ -+ guint32 cur_char; -+ CRInputPos init_pos; -+ glong occur = 0; -+ guint32 unicode = 0; -+ guchar *tmp_char_ptr1 = NULL, -+ *tmp_char_ptr2 = NULL; -+ enum CRStatus status = CR_OK; -+ -+ g_return_val_if_fail (a_this && PRIVATE (a_this) -+ && a_unicode, CR_BAD_PARAM_ERROR); -+ -+ /*first, let's backup the current position pointer */ -+ RECORD_INITIAL_POS (a_this, &init_pos); -+ -+ READ_NEXT_CHAR (a_this, &cur_char); -+ -+ if (cur_char != '\\') { -+ status = CR_PARSING_ERROR; -+ goto error; -+ } -+ if (a_location) { -+ cr_tknzr_get_parsing_location -+ (a_this, a_location) ; -+ } -+ PEEK_NEXT_CHAR (a_this, &cur_char); -+ -+ for (occur = 0, unicode = 0; ((cur_char >= '0' && cur_char <= '9') -+ || (cur_char >= 'a' && cur_char <= 'f') -+ || (cur_char >= 'A' && cur_char <= 'F')) -+ && occur < 6; occur++) { -+ gint cur_char_val = 0; -+ -+ READ_NEXT_CHAR (a_this, &cur_char); -+ -+ if ((cur_char >= '0' && cur_char <= '9')) { -+ cur_char_val = (cur_char - '0'); -+ } else if ((cur_char >= 'a' && cur_char <= 'f')) { -+ cur_char_val = 10 + (cur_char - 'a'); -+ } else if ((cur_char >= 'A' && cur_char <= 'F')) { -+ cur_char_val = 10 + (cur_char - 'A'); -+ } -+ -+ unicode = unicode * 16 + cur_char_val; -+ -+ PEEK_NEXT_CHAR (a_this, &cur_char); -+ } -+ -+ /* Eat a whitespace if possible. */ -+ cr_tknzr_parse_w (a_this, &tmp_char_ptr1, -+ &tmp_char_ptr2, NULL); -+ *a_unicode = unicode; -+ return CR_OK; -+ -+ error: -+ /* -+ *restore the initial position pointer backuped at -+ *the beginning of this function. -+ */ -+ cr_tknzr_set_cur_pos (a_this, &init_pos); -+ -+ return status; -+} -+ -+/** -+ *parses an escape sequence as defined by the css spec: -+ *escape ::= {unicode}|\\[ -~\200-\4177777] -+ *@param a_this the current instance of #CRTknzr . -+ */ -+static enum CRStatus -+cr_tknzr_parse_escape (CRTknzr * a_this, guint32 * a_esc_code, -+ CRParsingLocation *a_location) -+{ -+ enum CRStatus status = CR_OK; -+ guint32 cur_char = 0; -+ CRInputPos init_pos; -+ guchar next_chars[2]; -+ -+ g_return_val_if_fail (a_this && PRIVATE (a_this) -+ && a_esc_code, CR_BAD_PARAM_ERROR); -+ -+ RECORD_INITIAL_POS (a_this, &init_pos); -+ -+ PEEK_BYTE (a_this, 1, &next_chars[0]); -+ PEEK_BYTE (a_this, 2, &next_chars[1]); -+ -+ if (next_chars[0] != '\\') { -+ status = CR_PARSING_ERROR; -+ goto error; -+ } -+ -+ if ((next_chars[1] >= '0' && next_chars[1] <= '9') -+ || (next_chars[1] >= 'a' && next_chars[1] <= 'f') -+ || (next_chars[1] >= 'A' && next_chars[1] <= 'F')) { -+ status = cr_tknzr_parse_unicode_escape (a_this, a_esc_code, -+ a_location); -+ } else { -+ /*consume the '\' char */ -+ READ_NEXT_CHAR (a_this, &cur_char); -+ if (a_location) { -+ cr_tknzr_get_parsing_location (a_this, -+ a_location) ; -+ } -+ /*then read the char after the '\' */ -+ READ_NEXT_CHAR (a_this, &cur_char); -+ -+ if (cur_char != ' ' && (cur_char < 200 || cur_char > 4177777)) { -+ status = CR_PARSING_ERROR; -+ goto error; -+ } -+ *a_esc_code = cur_char; -+ -+ } -+ if (status == CR_OK) { -+ return CR_OK; -+ } -+ error: -+ cr_tknzr_set_cur_pos (a_this, &init_pos); -+ return status; -+} -+ -+/** -+ *Parses a string type as defined in css spec [4.1.1]: -+ * -+ *string ::= {string1}|{string2} -+ *string1 ::= \"([\t !#$%&(-~]|\\{nl}|\'|{nonascii}|{escape})*\" -+ *string2 ::= \'([\t !#$%&(-~]|\\{nl}|\"|{nonascii}|{escape})*\' -+ * -+ *@param a_this the current instance of #CRTknzr. -+ *@param a_start out parameter. Upon successfull completion, -+ *points to the beginning of the string, points to an undefined value -+ *otherwise. -+ *@param a_end out parameter. Upon successfull completion, points to -+ *the beginning of the string, points to an undefined value otherwise. -+ *@return CR_OK upon successfull completion, an error code otherwise. -+ */ -+static enum CRStatus -+cr_tknzr_parse_string (CRTknzr * a_this, CRString ** a_str) -+{ -+ guint32 cur_char = 0, -+ delim = 0; -+ CRInputPos init_pos; -+ enum CRStatus status = CR_OK; -+ CRString *str = NULL; -+ -+ g_return_val_if_fail (a_this && PRIVATE (a_this) -+ && PRIVATE (a_this)->input -+ && a_str, CR_BAD_PARAM_ERROR); -+ -+ RECORD_INITIAL_POS (a_this, &init_pos); -+ READ_NEXT_CHAR (a_this, &cur_char); -+ -+ if (cur_char == '"') -+ delim = '"'; -+ else if (cur_char == '\'') -+ delim = '\''; -+ else { -+ status = CR_PARSING_ERROR; -+ goto error; -+ } -+ str = cr_string_new (); -+ if (str) { -+ cr_tknzr_get_parsing_location -+ (a_this, &str->location) ; -+ } -+ for (;;) { -+ guchar next_chars[2] = { 0 }; -+ -+ PEEK_BYTE (a_this, 1, &next_chars[0]); -+ PEEK_BYTE (a_this, 2, &next_chars[1]); -+ -+ if (next_chars[0] == '\\') { -+ guchar *tmp_char_ptr1 = NULL, -+ *tmp_char_ptr2 = NULL; -+ guint32 esc_code = 0; -+ -+ if (next_chars[1] == '\'' || next_chars[1] == '"') { -+ g_string_append_unichar (str->stryng, -+ next_chars[1]); -+ SKIP_BYTES (a_this, 2); -+ status = CR_OK; -+ } else { -+ status = cr_tknzr_parse_escape -+ (a_this, &esc_code, NULL); -+ -+ if (status == CR_OK) { -+ g_string_append_unichar -+ (str->stryng, -+ esc_code); -+ } -+ } -+ -+ if (status != CR_OK) { -+ /* -+ *consume the '\' char, and try to parse -+ *a newline. -+ */ -+ READ_NEXT_CHAR (a_this, &cur_char); -+ -+ status = cr_tknzr_parse_nl -+ (a_this, &tmp_char_ptr1, -+ &tmp_char_ptr2, NULL); -+ } -+ -+ CHECK_PARSING_STATUS (status, FALSE); -+ } else if (strchr ("\t !#$%&", next_chars[0]) -+ || (next_chars[0] >= '(' && next_chars[0] <= '~')) { -+ READ_NEXT_CHAR (a_this, &cur_char); -+ g_string_append_unichar (str->stryng, -+ cur_char); -+ status = CR_OK; -+ } -+ -+ else if (cr_utils_is_nonascii (next_chars[0])) { -+ READ_NEXT_CHAR (a_this, &cur_char); -+ g_string_append_unichar (str->stryng, cur_char); -+ } else if (next_chars[0] == delim) { -+ READ_NEXT_CHAR (a_this, &cur_char); -+ break; -+ } else { -+ status = CR_PARSING_ERROR; -+ goto error; -+ } -+ } -+ -+ if (status == CR_OK) { -+ if (*a_str == NULL) { -+ *a_str = str; -+ str = NULL; -+ } else { -+ (*a_str)->stryng = g_string_append_len -+ ((*a_str)->stryng, -+ str->stryng->str, -+ str->stryng->len); -+ cr_string_destroy (str); -+ } -+ return CR_OK; -+ } -+ -+ error: -+ -+ if (str) { -+ cr_string_destroy (str) ; -+ str = NULL; -+ } -+ cr_tknzr_set_cur_pos (a_this, &init_pos); -+ return status; -+} -+ -+/** -+ *Parses the an nmstart as defined by the css2 spec [4.1.1]: -+ * nmstart [a-zA-Z]|{nonascii}|{escape} -+ * -+ *@param a_this the current instance of #CRTknzr. -+ *@param a_start out param. A pointer to the starting point of -+ *the token. -+ *@param a_end out param. A pointer to the ending point of the -+ *token. -+ *@param a_char out param. The actual parsed nmchar. -+ *@return CR_OK upon successfull completion, -+ *an error code otherwise. -+ */ -+static enum CRStatus -+cr_tknzr_parse_nmstart (CRTknzr * a_this, -+ guint32 * a_char, -+ CRParsingLocation *a_location) -+{ -+ CRInputPos init_pos; -+ enum CRStatus status = CR_OK; -+ guint32 cur_char = 0, -+ next_char = 0; -+ -+ g_return_val_if_fail (a_this && PRIVATE (a_this) -+ && PRIVATE (a_this)->input -+ && a_char, CR_BAD_PARAM_ERROR); -+ -+ RECORD_INITIAL_POS (a_this, &init_pos); -+ -+ PEEK_NEXT_CHAR (a_this, &next_char); -+ -+ if (next_char == '\\') { -+ status = cr_tknzr_parse_escape (a_this, a_char, -+ a_location); -+ -+ if (status != CR_OK) -+ goto error; -+ -+ } else if (cr_utils_is_nonascii (next_char) == TRUE -+ || ((next_char >= 'a') && (next_char <= 'z')) -+ || ((next_char >= 'A') && (next_char <= 'Z')) -+ ) { -+ READ_NEXT_CHAR (a_this, &cur_char); -+ if (a_location) { -+ cr_tknzr_get_parsing_location (a_this, -+ a_location) ; -+ } -+ *a_char = cur_char; -+ status = CR_OK; -+ } else { -+ status = CR_PARSING_ERROR; -+ goto error; -+ } -+ -+ return CR_OK; -+ -+ error: -+ cr_tknzr_set_cur_pos (a_this, &init_pos); -+ -+ return status; -+ -+} -+ -+/** -+ *Parses an nmchar as described in the css spec at -+ *chap 4.1.1: -+ *nmchar ::= [a-z0-9-]|{nonascii}|{escape} -+ * -+ *Humm, I have added the possibility for nmchar to -+ *contain upper case letters. -+ * -+ *@param a_this the current instance of #CRTknzr. -+ *@param a_start out param. A pointer to the starting point of -+ *the token. -+ *@param a_end out param. A pointer to the ending point of the -+ *token. -+ *@param a_char out param. The actual parsed nmchar. -+ *@return CR_OK upon successfull completion, -+ *an error code otherwise. -+ */ -+static enum CRStatus -+cr_tknzr_parse_nmchar (CRTknzr * a_this, guint32 * a_char, -+ CRParsingLocation *a_location) -+{ -+ guint32 cur_char = 0, -+ next_char = 0; -+ enum CRStatus status = CR_OK; -+ CRInputPos init_pos; -+ -+ g_return_val_if_fail (a_this && PRIVATE (a_this) && a_char, -+ CR_BAD_PARAM_ERROR); -+ -+ RECORD_INITIAL_POS (a_this, &init_pos); -+ -+ status = cr_input_peek_char (PRIVATE (a_this)->input, -+ &next_char) ; -+ if (status != CR_OK) -+ goto error; -+ -+ if (next_char == '\\') { -+ status = cr_tknzr_parse_escape (a_this, a_char, -+ a_location); -+ -+ if (status != CR_OK) -+ goto error; -+ -+ } else if (cr_utils_is_nonascii (next_char) == TRUE -+ || ((next_char >= 'a') && (next_char <= 'z')) -+ || ((next_char >= 'A') && (next_char <= 'Z')) -+ || ((next_char >= '0') && (next_char <= '9')) -+ || (next_char == '-') -+ || (next_char == '_') /*'_' not allowed by the spec. */ -+ ) { -+ READ_NEXT_CHAR (a_this, &cur_char); -+ *a_char = cur_char; -+ status = CR_OK; -+ if (a_location) { -+ cr_tknzr_get_parsing_location -+ (a_this, a_location) ; -+ } -+ } else { -+ status = CR_PARSING_ERROR; -+ goto error; -+ } -+ return CR_OK; -+ -+ error: -+ cr_tknzr_set_cur_pos (a_this, &init_pos); -+ return status; -+} -+ -+/** -+ *Parses an "ident" as defined in css spec [4.1.1]: -+ *ident ::= {nmstart}{nmchar}* -+ * -+ *Actually parses it using the css3 grammar: -+ *ident ::= -?{nmstart}{nmchar}* -+ *@param a_this the currens instance of #CRTknzr. -+ * -+ *@param a_str a pointer to parsed ident. If *a_str is NULL, -+ *this function allocates a new instance of CRString. If not, -+ *the function just appends the parsed string to the one passed. -+ *In both cases it is up to the caller to free *a_str. -+ * -+ *@return CR_OK upon successfull completion, an error code -+ *otherwise. -+ */ -+static enum CRStatus -+cr_tknzr_parse_ident (CRTknzr * a_this, CRString ** a_str) -+{ -+ guint32 tmp_char = 0; -+ CRString *stringue = NULL ; -+ CRInputPos init_pos; -+ enum CRStatus status = CR_OK; -+ gboolean location_is_set = FALSE ; -+ -+ g_return_val_if_fail (a_this && PRIVATE (a_this) -+ && PRIVATE (a_this)->input -+ && a_str, CR_BAD_PARAM_ERROR); -+ -+ RECORD_INITIAL_POS (a_this, &init_pos); -+ PEEK_NEXT_CHAR (a_this, &tmp_char) ; -+ stringue = cr_string_new () ; -+ g_return_val_if_fail (stringue, -+ CR_OUT_OF_MEMORY_ERROR) ; -+ -+ if (tmp_char == '-') { -+ READ_NEXT_CHAR (a_this, &tmp_char) ; -+ cr_tknzr_get_parsing_location -+ (a_this, &stringue->location) ; -+ location_is_set = TRUE ; -+ g_string_append_unichar (stringue->stryng, -+ tmp_char) ; -+ } -+ status = cr_tknzr_parse_nmstart (a_this, &tmp_char, NULL); -+ if (status != CR_OK) { -+ status = CR_PARSING_ERROR; -+ goto end ; -+ } -+ if (location_is_set == FALSE) { -+ cr_tknzr_get_parsing_location -+ (a_this, &stringue->location) ; -+ location_is_set = TRUE ; -+ } -+ g_string_append_unichar (stringue->stryng, tmp_char); -+ for (;;) { -+ status = cr_tknzr_parse_nmchar (a_this, -+ &tmp_char, -+ NULL); -+ if (status != CR_OK) { -+ status = CR_OK ; -+ break; -+ } -+ g_string_append_unichar (stringue->stryng, tmp_char); -+ } -+ if (status == CR_OK) { -+ if (!*a_str) { -+ *a_str = stringue ; -+ -+ } else { -+ g_string_append_len ((*a_str)->stryng, -+ stringue->stryng->str, -+ stringue->stryng->len) ; -+ cr_string_destroy (stringue) ; -+ } -+ stringue = NULL ; -+ } -+ -+ error: -+ end: -+ if (stringue) { -+ cr_string_destroy (stringue) ; -+ stringue = NULL ; -+ } -+ if (status != CR_OK ) { -+ cr_tknzr_set_cur_pos (a_this, &init_pos) ; -+ } -+ return status ; -+} -+ -+ -+/** -+ *Parses a "name" as defined by css spec [4.1.1]: -+ *name ::= {nmchar}+ -+ * -+ *@param a_this the current instance of #CRTknzr. -+ * -+ *@param a_str out parameter. A pointer to the successfully parsed -+ *name. If *a_str is set to NULL, this function allocates a new instance -+ *of CRString. If not, it just appends the parsed name to the passed *a_str. -+ *In both cases, it is up to the caller to free *a_str. -+ * -+ *@return CR_OK upon successfull completion, an error code otherwise. -+ */ -+static enum CRStatus -+cr_tknzr_parse_name (CRTknzr * a_this, -+ CRString ** a_str) -+{ -+ guint32 tmp_char = 0; -+ CRInputPos init_pos; -+ enum CRStatus status = CR_OK; -+ gboolean str_needs_free = FALSE, -+ is_first_nmchar=TRUE ; -+ glong i = 0; -+ CRParsingLocation loc = {0} ; -+ -+ g_return_val_if_fail (a_this && PRIVATE (a_this) -+ && PRIVATE (a_this)->input -+ && a_str, -+ CR_BAD_PARAM_ERROR) ; -+ -+ RECORD_INITIAL_POS (a_this, &init_pos); -+ -+ if (*a_str == NULL) { -+ *a_str = cr_string_new (); -+ str_needs_free = TRUE; -+ } -+ for (i = 0;; i++) { -+ if (is_first_nmchar == TRUE) { -+ status = cr_tknzr_parse_nmchar -+ (a_this, &tmp_char, -+ &loc) ; -+ is_first_nmchar = FALSE ; -+ } else { -+ status = cr_tknzr_parse_nmchar -+ (a_this, &tmp_char, NULL) ; -+ } -+ if (status != CR_OK) -+ break; -+ g_string_append_unichar ((*a_str)->stryng, -+ tmp_char); -+ } -+ if (i > 0) { -+ cr_parsing_location_copy -+ (&(*a_str)->location, &loc) ; -+ return CR_OK; -+ } -+ if (str_needs_free == TRUE && *a_str) { -+ cr_string_destroy (*a_str); -+ *a_str = NULL; -+ } -+ cr_tknzr_set_cur_pos (a_this, &init_pos); -+ return CR_PARSING_ERROR; -+} -+ -+/** -+ *Parses a "hash" as defined by the css spec in [4.1.1]: -+ *HASH ::= #{name} -+ */ -+static enum CRStatus -+cr_tknzr_parse_hash (CRTknzr * a_this, CRString ** a_str) -+{ -+ guint32 cur_char = 0; -+ CRInputPos init_pos; -+ enum CRStatus status = CR_OK; -+ gboolean str_needs_free = FALSE; -+ CRParsingLocation loc = {0} ; -+ -+ g_return_val_if_fail (a_this && PRIVATE (a_this) -+ && PRIVATE (a_this)->input, -+ CR_BAD_PARAM_ERROR); -+ -+ RECORD_INITIAL_POS (a_this, &init_pos); -+ READ_NEXT_CHAR (a_this, &cur_char); -+ if (cur_char != '#') { -+ status = CR_PARSING_ERROR; -+ goto error; -+ } -+ if (*a_str == NULL) { -+ *a_str = cr_string_new (); -+ str_needs_free = TRUE; -+ } -+ cr_tknzr_get_parsing_location (a_this, -+ &loc) ; -+ status = cr_tknzr_parse_name (a_this, a_str); -+ cr_parsing_location_copy (&(*a_str)->location, &loc) ; -+ if (status != CR_OK) { -+ goto error; -+ } -+ return CR_OK; -+ -+ error: -+ if (str_needs_free == TRUE && *a_str) { -+ cr_string_destroy (*a_str); -+ *a_str = NULL; -+ } -+ -+ cr_tknzr_set_cur_pos (a_this, &init_pos); -+ return status; -+} -+ -+/** -+ *Parses an uri as defined by the css spec [4.1.1]: -+ * URI ::= url\({w}{string}{w}\) -+ * |url\({w}([!#$%&*-~]|{nonascii}|{escape})*{w}\) -+ * -+ *@param a_this the current instance of #CRTknzr. -+ *@param a_str the successfully parsed url. -+ *@return CR_OK upon successfull completion, an error code otherwise. -+ */ -+static enum CRStatus -+cr_tknzr_parse_uri (CRTknzr * a_this, -+ CRString ** a_str) -+{ -+ guint32 cur_char = 0; -+ CRInputPos init_pos; -+ enum CRStatus status = CR_PARSING_ERROR; -+ guchar tab[4] = { 0 }, *tmp_ptr1 = NULL, *tmp_ptr2 = NULL; -+ CRString *str = NULL; -+ CRParsingLocation location = {0} ; -+ -+ g_return_val_if_fail (a_this -+ && PRIVATE (a_this) -+ && PRIVATE (a_this)->input -+ && a_str, -+ CR_BAD_PARAM_ERROR); -+ -+ RECORD_INITIAL_POS (a_this, &init_pos); -+ -+ PEEK_BYTE (a_this, 1, &tab[0]); -+ PEEK_BYTE (a_this, 2, &tab[1]); -+ PEEK_BYTE (a_this, 3, &tab[2]); -+ PEEK_BYTE (a_this, 4, &tab[3]); -+ -+ if (tab[0] != 'u' || tab[1] != 'r' || tab[2] != 'l' || tab[3] != '(') { -+ status = CR_PARSING_ERROR; -+ goto error; -+ } -+ /* -+ *Here, we want to skip 4 bytes ('u''r''l''('). -+ *But we also need to keep track of the parsing location -+ *of the 'u'. So, we skip 1 byte, we record the parsing -+ *location, then we skip the 3 remaining bytes. -+ */ -+ SKIP_CHARS (a_this, 1); -+ cr_tknzr_get_parsing_location (a_this, &location) ; -+ SKIP_CHARS (a_this, 3); -+ cr_tknzr_try_to_skip_spaces (a_this); -+ status = cr_tknzr_parse_string (a_this, a_str); -+ -+ if (status == CR_OK) { -+ guint32 next_char = 0; -+ status = cr_tknzr_parse_w (a_this, &tmp_ptr1, -+ &tmp_ptr2, NULL); -+ cr_tknzr_try_to_skip_spaces (a_this); -+ PEEK_NEXT_CHAR (a_this, &next_char); -+ if (next_char == ')') { -+ READ_NEXT_CHAR (a_this, &cur_char); -+ status = CR_OK; -+ } else { -+ status = CR_PARSING_ERROR; -+ } -+ } -+ if (status != CR_OK) { -+ str = cr_string_new (); -+ for (;;) { -+ guint32 next_char = 0; -+ PEEK_NEXT_CHAR (a_this, &next_char); -+ if (strchr ("!#$%&", next_char) -+ || (next_char >= '*' && next_char <= '~') -+ || (cr_utils_is_nonascii (next_char) == TRUE)) { -+ READ_NEXT_CHAR (a_this, &cur_char); -+ g_string_append_unichar -+ (str->stryng, cur_char); -+ status = CR_OK; -+ } else { -+ guint32 esc_code = 0; -+ status = cr_tknzr_parse_escape -+ (a_this, &esc_code, NULL); -+ if (status == CR_OK) { -+ g_string_append_unichar -+ (str->stryng, -+ esc_code); -+ } else { -+ status = CR_OK; -+ break; -+ } -+ } -+ } -+ cr_tknzr_try_to_skip_spaces (a_this); -+ READ_NEXT_CHAR (a_this, &cur_char); -+ if (cur_char == ')') { -+ status = CR_OK; -+ } else { -+ status = CR_PARSING_ERROR; -+ goto error; -+ } -+ if (str) { -+ if (*a_str == NULL) { -+ *a_str = str; -+ str = NULL; -+ } else { -+ g_string_append_len -+ ((*a_str)->stryng, -+ str->stryng->str, -+ str->stryng->len); -+ cr_string_destroy (str); -+ } -+ } -+ } -+ -+ cr_parsing_location_copy -+ (&(*a_str)->location, -+ &location) ; -+ return CR_OK ; -+ error: -+ if (str) { -+ cr_string_destroy (str); -+ str = NULL; -+ } -+ cr_tknzr_set_cur_pos (a_this, &init_pos); -+ return status; -+} -+ -+/** -+ *parses an RGB as defined in the css2 spec. -+ *rgb: rgb '('S*{num}%?S* ',' {num}#?S*,S*{num}#?S*')' -+ * -+ *@param a_this the "this pointer" of the current instance of -+ *@param a_rgb out parameter the parsed rgb. -+ *@return CR_OK upon successfull completion, an error code otherwise. -+ */ -+static enum CRStatus -+cr_tknzr_parse_rgb (CRTknzr * a_this, CRRgb ** a_rgb) -+{ -+ enum CRStatus status = CR_OK; -+ CRInputPos init_pos; -+ CRNum *num = NULL; -+ guchar next_bytes[3] = { 0 }, cur_byte = 0; -+ glong red = 0, -+ green = 0, -+ blue = 0, -+ i = 0; -+ gboolean is_percentage = FALSE; -+ CRParsingLocation location = {0} ; -+ -+ g_return_val_if_fail (a_this && PRIVATE (a_this), CR_BAD_PARAM_ERROR); -+ -+ RECORD_INITIAL_POS (a_this, &init_pos); -+ -+ PEEK_BYTE (a_this, 1, &next_bytes[0]); -+ PEEK_BYTE (a_this, 2, &next_bytes[1]); -+ PEEK_BYTE (a_this, 3, &next_bytes[2]); -+ -+ if (((next_bytes[0] == 'r') || (next_bytes[0] == 'R')) -+ && ((next_bytes[1] == 'g') || (next_bytes[1] == 'G')) -+ && ((next_bytes[2] == 'b') || (next_bytes[2] == 'B'))) { -+ SKIP_CHARS (a_this, 1); -+ cr_tknzr_get_parsing_location (a_this, &location) ; -+ SKIP_CHARS (a_this, 2); -+ } else { -+ status = CR_PARSING_ERROR; -+ goto error; -+ } -+ READ_NEXT_BYTE (a_this, &cur_byte); -+ ENSURE_PARSING_COND (cur_byte == '('); -+ -+ cr_tknzr_try_to_skip_spaces (a_this); -+ status = cr_tknzr_parse_num (a_this, &num); -+ ENSURE_PARSING_COND ((status == CR_OK) && (num != NULL)); -+ -+ if (num->val > G_MAXLONG) { -+ status = CR_PARSING_ERROR; -+ goto error; -+ } -+ -+ red = num->val; -+ cr_num_destroy (num); -+ num = NULL; -+ -+ PEEK_BYTE (a_this, 1, &next_bytes[0]); -+ if (next_bytes[0] == '%') { -+ SKIP_CHARS (a_this, 1); -+ is_percentage = TRUE; -+ } -+ cr_tknzr_try_to_skip_spaces (a_this); -+ -+ for (i = 0; i < 2; i++) { -+ READ_NEXT_BYTE (a_this, &cur_byte); -+ ENSURE_PARSING_COND (cur_byte == ','); -+ -+ cr_tknzr_try_to_skip_spaces (a_this); -+ status = cr_tknzr_parse_num (a_this, &num); -+ ENSURE_PARSING_COND ((status == CR_OK) && (num != NULL)); -+ -+ if (num->val > G_MAXLONG) { -+ status = CR_PARSING_ERROR; -+ goto error; -+ } -+ -+ PEEK_BYTE (a_this, 1, &next_bytes[0]); -+ if (next_bytes[0] == '%') { -+ SKIP_CHARS (a_this, 1); -+ is_percentage = 1; -+ } -+ -+ if (i == 0) { -+ green = num->val; -+ } else if (i == 1) { -+ blue = num->val; -+ } -+ -+ if (num) { -+ cr_num_destroy (num); -+ num = NULL; -+ } -+ cr_tknzr_try_to_skip_spaces (a_this); -+ } -+ -+ READ_NEXT_BYTE (a_this, &cur_byte); -+ if (*a_rgb == NULL) { -+ *a_rgb = cr_rgb_new_with_vals (red, green, blue, -+ is_percentage); -+ -+ if (*a_rgb == NULL) { -+ status = CR_ERROR; -+ goto error; -+ } -+ status = CR_OK; -+ } else { -+ (*a_rgb)->red = red; -+ (*a_rgb)->green = green; -+ (*a_rgb)->blue = blue; -+ (*a_rgb)->is_percentage = is_percentage; -+ -+ status = CR_OK; -+ } -+ -+ if (status == CR_OK) { -+ if (a_rgb && *a_rgb) { -+ cr_parsing_location_copy -+ (&(*a_rgb)->location, -+ &location) ; -+ } -+ return CR_OK; -+ } -+ -+ error: -+ if (num) { -+ cr_num_destroy (num); -+ num = NULL; -+ } -+ -+ cr_tknzr_set_cur_pos (a_this, &init_pos); -+ return CR_OK; -+} -+ -+/** -+ *Parses a atkeyword as defined by the css spec in [4.1.1]: -+ *ATKEYWORD ::= @{ident} -+ * -+ *@param a_this the "this pointer" of the current instance of -+ *#CRTknzr. -+ * -+ *@param a_str out parameter. The parsed atkeyword. If *a_str is -+ *set to NULL this function allocates a new instance of CRString and -+ *sets it to the parsed atkeyword. If not, this function just appends -+ *the parsed atkeyword to the end of *a_str. In both cases it is up to -+ *the caller to free *a_str. -+ * -+ *@return CR_OK upon successfull completion, an error code otherwise. -+ */ -+static enum CRStatus -+cr_tknzr_parse_atkeyword (CRTknzr * a_this, -+ CRString ** a_str) -+{ -+ guint32 cur_char = 0; -+ CRInputPos init_pos; -+ gboolean str_needs_free = FALSE; -+ enum CRStatus status = CR_OK; -+ -+ g_return_val_if_fail (a_this && PRIVATE (a_this) -+ && PRIVATE (a_this)->input -+ && a_str, CR_BAD_PARAM_ERROR); -+ -+ RECORD_INITIAL_POS (a_this, &init_pos); -+ -+ READ_NEXT_CHAR (a_this, &cur_char); -+ -+ if (cur_char != '@') { -+ status = CR_PARSING_ERROR; -+ goto error; -+ } -+ -+ if (*a_str == NULL) { -+ *a_str = cr_string_new (); -+ str_needs_free = TRUE; -+ } -+ status = cr_tknzr_parse_ident (a_this, a_str); -+ if (status != CR_OK) { -+ goto error; -+ } -+ return CR_OK; -+ error: -+ -+ if (str_needs_free == TRUE && *a_str) { -+ cr_string_destroy (*a_str); -+ *a_str = NULL; -+ } -+ cr_tknzr_set_cur_pos (a_this, &init_pos); -+ return status; -+} -+ -+static enum CRStatus -+cr_tknzr_parse_important (CRTknzr * a_this, -+ CRParsingLocation *a_location) -+{ -+ guint32 cur_char = 0; -+ CRInputPos init_pos; -+ enum CRStatus status = CR_OK; -+ -+ g_return_val_if_fail (a_this && PRIVATE (a_this) -+ && PRIVATE (a_this)->input, -+ CR_BAD_PARAM_ERROR); -+ -+ RECORD_INITIAL_POS (a_this, &init_pos); -+ READ_NEXT_CHAR (a_this, &cur_char); -+ ENSURE_PARSING_COND (cur_char == '!'); -+ if (a_location) { -+ cr_tknzr_get_parsing_location (a_this, -+ a_location) ; -+ } -+ cr_tknzr_try_to_skip_spaces (a_this); -+ -+ if (BYTE (PRIVATE (a_this)->input, 1, NULL) == 'i' -+ && BYTE (PRIVATE (a_this)->input, 2, NULL) == 'm' -+ && BYTE (PRIVATE (a_this)->input, 3, NULL) == 'p' -+ && BYTE (PRIVATE (a_this)->input, 4, NULL) == 'o' -+ && BYTE (PRIVATE (a_this)->input, 5, NULL) == 'r' -+ && BYTE (PRIVATE (a_this)->input, 6, NULL) == 't' -+ && BYTE (PRIVATE (a_this)->input, 7, NULL) == 'a' -+ && BYTE (PRIVATE (a_this)->input, 8, NULL) == 'n' -+ && BYTE (PRIVATE (a_this)->input, 9, NULL) == 't') { -+ SKIP_BYTES (a_this, 9); -+ if (a_location) { -+ cr_tknzr_get_parsing_location (a_this, -+ a_location) ; -+ } -+ return CR_OK; -+ } else { -+ status = CR_PARSING_ERROR; -+ } -+ -+ error: -+ cr_tknzr_set_cur_pos (a_this, &init_pos); -+ -+ return status; -+} -+ -+/** -+ *Parses a num as defined in the css spec [4.1.1]: -+ *[0-9]+|[0-9]*\.[0-9]+ -+ *@param a_this the current instance of #CRTknzr. -+ *@param a_num out parameter. The parsed number. -+ *@return CR_OK upon successfull completion, -+ *an error code otherwise. -+ * -+ *The CSS specification says that numbers may be -+ *preceeded by '+' or '-' to indicate the sign. -+ *Technically, the "num" construction as defined -+ *by the tokenizer doesn't allow this, but we parse -+ *it here for simplicity. -+ */ -+static enum CRStatus -+cr_tknzr_parse_num (CRTknzr * a_this, -+ CRNum ** a_num) -+{ -+ enum CRStatus status = CR_PARSING_ERROR; -+ enum CRNumType val_type = NUM_GENERIC; -+ gboolean parsing_dec, /* true iff seen decimal point. */ -+ parsed; /* true iff the substring seen so far is a valid CSS -+ number, i.e. `[0-9]+|[0-9]*\.[0-9]+'. */ -+ guint32 cur_char = 0, -+ next_char = 0; -+ gdouble numerator, denominator = 1; -+ CRInputPos init_pos; -+ CRParsingLocation location = {0} ; -+ int sign = 1; -+ -+ g_return_val_if_fail (a_this && PRIVATE (a_this) -+ && PRIVATE (a_this)->input, -+ CR_BAD_PARAM_ERROR); -+ -+ RECORD_INITIAL_POS (a_this, &init_pos); -+ READ_NEXT_CHAR (a_this, &cur_char); -+ -+ if (cur_char == '+' || cur_char == '-') { -+ if (cur_char == '-') { -+ sign = -1; -+ } -+ READ_NEXT_CHAR (a_this, &cur_char); -+ } -+ -+ if (IS_NUM (cur_char)) { -+ numerator = (cur_char - '0'); -+ parsing_dec = FALSE; -+ parsed = TRUE; -+ } else if (cur_char == '.') { -+ numerator = 0; -+ parsing_dec = TRUE; -+ parsed = FALSE; -+ } else { -+ status = CR_PARSING_ERROR; -+ goto error; -+ } -+ cr_tknzr_get_parsing_location (a_this, &location) ; -+ -+ for (;;) { -+ status = cr_tknzr_peek_char (a_this, &next_char); -+ if (status != CR_OK) { -+ if (status == CR_END_OF_INPUT_ERROR) -+ status = CR_OK; -+ break; -+ } -+ if (next_char == '.') { -+ if (parsing_dec) { -+ status = CR_PARSING_ERROR; -+ goto error; -+ } -+ -+ READ_NEXT_CHAR (a_this, &cur_char); -+ parsing_dec = TRUE; -+ parsed = FALSE; /* In CSS, there must be at least -+ one digit after `.'. */ -+ } else if (IS_NUM (next_char)) { -+ READ_NEXT_CHAR (a_this, &cur_char); -+ parsed = TRUE; -+ -+ numerator = numerator * 10 + (cur_char - '0'); -+ if (parsing_dec) { -+ denominator *= 10; -+ } -+ } else { -+ break; -+ } -+ } -+ -+ if (!parsed) { -+ status = CR_PARSING_ERROR; -+ } -+ -+ /* -+ *Now, set the output param values. -+ */ -+ if (status == CR_OK) { -+ gdouble val = (numerator / denominator) * sign; -+ if (*a_num == NULL) { -+ *a_num = cr_num_new_with_val (val, val_type); -+ -+ if (*a_num == NULL) { -+ status = CR_ERROR; -+ goto error; -+ } -+ } else { -+ (*a_num)->val = val; -+ (*a_num)->type = val_type; -+ } -+ cr_parsing_location_copy (&(*a_num)->location, -+ &location) ; -+ return CR_OK; -+ } -+ -+ error: -+ -+ cr_tknzr_set_cur_pos (a_this, &init_pos); -+ -+ return status; -+} -+ -+/********************************************* -+ *PUBLIC methods -+ ********************************************/ -+ -+CRTknzr * -+cr_tknzr_new (CRInput * a_input) -+{ -+ CRTknzr *result = NULL; -+ -+ result = g_try_malloc (sizeof (CRTknzr)); -+ -+ if (result == NULL) { -+ cr_utils_trace_info ("Out of memory"); -+ return NULL; -+ } -+ -+ memset (result, 0, sizeof (CRTknzr)); -+ -+ result->priv = g_try_malloc (sizeof (CRTknzrPriv)); -+ -+ if (result->priv == NULL) { -+ cr_utils_trace_info ("Out of memory"); -+ -+ if (result) { -+ g_free (result); -+ result = NULL; -+ } -+ -+ return NULL; -+ } -+ memset (result->priv, 0, sizeof (CRTknzrPriv)); -+ if (a_input) -+ cr_tknzr_set_input (result, a_input); -+ return result; -+} -+ -+CRTknzr * -+cr_tknzr_new_from_buf (guchar * a_buf, gulong a_len, -+ enum CREncoding a_enc, -+ gboolean a_free_at_destroy) -+{ -+ CRTknzr *result = NULL; -+ CRInput *input = NULL; -+ -+ input = cr_input_new_from_buf (a_buf, a_len, a_enc, -+ a_free_at_destroy); -+ -+ g_return_val_if_fail (input != NULL, NULL); -+ -+ result = cr_tknzr_new (input); -+ -+ return result; -+} -+ -+CRTknzr * -+cr_tknzr_new_from_uri (const guchar * a_file_uri, -+ enum CREncoding a_enc) -+{ -+ CRTknzr *result = NULL; -+ CRInput *input = NULL; -+ -+ input = cr_input_new_from_uri ((const gchar *) a_file_uri, a_enc); -+ g_return_val_if_fail (input != NULL, NULL); -+ -+ result = cr_tknzr_new (input); -+ -+ return result; -+} -+ -+void -+cr_tknzr_ref (CRTknzr * a_this) -+{ -+ g_return_if_fail (a_this && PRIVATE (a_this)); -+ -+ PRIVATE (a_this)->ref_count++; -+} -+ -+gboolean -+cr_tknzr_unref (CRTknzr * a_this) -+{ -+ g_return_val_if_fail (a_this && PRIVATE (a_this), FALSE); -+ -+ if (PRIVATE (a_this)->ref_count > 0) { -+ PRIVATE (a_this)->ref_count--; -+ } -+ -+ if (PRIVATE (a_this)->ref_count == 0) { -+ cr_tknzr_destroy (a_this); -+ return TRUE; -+ } -+ -+ return FALSE; -+} -+ -+enum CRStatus -+cr_tknzr_set_input (CRTknzr * a_this, CRInput * a_input) -+{ -+ g_return_val_if_fail (a_this && PRIVATE (a_this), CR_BAD_PARAM_ERROR); -+ -+ if (PRIVATE (a_this)->input) { -+ cr_input_unref (PRIVATE (a_this)->input); -+ } -+ -+ PRIVATE (a_this)->input = a_input; -+ -+ cr_input_ref (PRIVATE (a_this)->input); -+ -+ return CR_OK; -+} -+ -+enum CRStatus -+cr_tknzr_get_input (CRTknzr * a_this, CRInput ** a_input) -+{ -+ g_return_val_if_fail (a_this && PRIVATE (a_this), CR_BAD_PARAM_ERROR); -+ -+ *a_input = PRIVATE (a_this)->input; -+ -+ return CR_OK; -+} -+ -+/********************************* -+ *Tokenizer input handling routines -+ *********************************/ -+ -+/** -+ *Reads the next byte from the parser input stream. -+ *@param a_this the "this pointer" of the current instance of -+ *#CRParser. -+ *@param a_byte out parameter the place where to store the byte -+ *read. -+ *@return CR_OK upon successfull completion, an error -+ *code otherwise. -+ */ -+enum CRStatus -+cr_tknzr_read_byte (CRTknzr * a_this, guchar * a_byte) -+{ -+ g_return_val_if_fail (a_this && PRIVATE (a_this), CR_BAD_PARAM_ERROR); -+ -+ return cr_input_read_byte (PRIVATE (a_this)->input, a_byte); -+ -+} -+ -+/** -+ *Reads the next char from the parser input stream. -+ *@param a_this the current instance of #CRTknzr. -+ *@param a_char out parameter. The read char. -+ *@return CR_OK upon successfull completion, an error code -+ *otherwise. -+ */ -+enum CRStatus -+cr_tknzr_read_char (CRTknzr * a_this, guint32 * a_char) -+{ -+ g_return_val_if_fail (a_this && PRIVATE (a_this) -+ && PRIVATE (a_this)->input -+ && a_char, CR_BAD_PARAM_ERROR); -+ -+ if (PRIVATE (a_this)->token_cache) { -+ cr_input_set_cur_pos (PRIVATE (a_this)->input, -+ &PRIVATE (a_this)->prev_pos); -+ cr_token_destroy (PRIVATE (a_this)->token_cache); -+ PRIVATE (a_this)->token_cache = NULL; -+ } -+ -+ return cr_input_read_char (PRIVATE (a_this)->input, a_char); -+} -+ -+/** -+ *Peeks a char from the parser input stream. -+ *To "peek a char" means reads the next char without consuming it. -+ *Subsequent calls to this function return the same char. -+ *@param a_this the current instance of #CRTknzr. -+ *@param a_char out parameter. The peeked char uppon successfull completion. -+ *@return CR_OK upon successfull completion, an error code otherwise. -+ */ -+enum CRStatus -+cr_tknzr_peek_char (CRTknzr * a_this, guint32 * a_char) -+{ -+ g_return_val_if_fail (a_this && PRIVATE (a_this) -+ && PRIVATE (a_this)->input -+ && a_char, CR_BAD_PARAM_ERROR); -+ -+ if (PRIVATE (a_this)->token_cache) { -+ cr_input_set_cur_pos (PRIVATE (a_this)->input, -+ &PRIVATE (a_this)->prev_pos); -+ cr_token_destroy (PRIVATE (a_this)->token_cache); -+ PRIVATE (a_this)->token_cache = NULL; -+ } -+ -+ return cr_input_peek_char (PRIVATE (a_this)->input, a_char); -+} -+ -+/** -+ *Peeks a byte ahead at a given postion in the parser input stream. -+ *@param a_this the current instance of #CRTknzr. -+ *@param a_offset the offset of the peeked byte starting from the current -+ *byte in the parser input stream. -+ *@param a_byte out parameter. The peeked byte upon -+ *successfull completion. -+ *@return CR_OK upon successfull completion, an error code otherwise. -+ */ -+enum CRStatus -+cr_tknzr_peek_byte (CRTknzr * a_this, gulong a_offset, guchar * a_byte) -+{ -+ g_return_val_if_fail (a_this && PRIVATE (a_this) -+ && PRIVATE (a_this)->input && a_byte, -+ CR_BAD_PARAM_ERROR); -+ -+ if (PRIVATE (a_this)->token_cache) { -+ cr_input_set_cur_pos (PRIVATE (a_this)->input, -+ &PRIVATE (a_this)->prev_pos); -+ cr_token_destroy (PRIVATE (a_this)->token_cache); -+ PRIVATE (a_this)->token_cache = NULL; -+ } -+ -+ return cr_input_peek_byte (PRIVATE (a_this)->input, -+ CR_SEEK_CUR, a_offset, a_byte); -+} -+ -+/** -+ *Same as cr_tknzr_peek_byte() but this api returns the byte peeked. -+ *@param a_this the current instance of #CRTknzr. -+ *@param a_offset the offset of the peeked byte starting from the current -+ *byte in the parser input stream. -+ *@param a_eof out parameter. If not NULL, is set to TRUE if we reached end of -+ *file, FALE otherwise. If the caller sets it to NULL, this parameter -+ *is just ignored. -+ *@return the peeked byte. -+ */ -+guchar -+cr_tknzr_peek_byte2 (CRTknzr * a_this, gulong a_offset, gboolean * a_eof) -+{ -+ g_return_val_if_fail (a_this && PRIVATE (a_this) -+ && PRIVATE (a_this)->input, 0); -+ -+ return cr_input_peek_byte2 (PRIVATE (a_this)->input, a_offset, a_eof); -+} -+ -+/** -+ *Gets the number of bytes left in the topmost input stream -+ *associated to this parser. -+ *@param a_this the current instance of #CRTknzr -+ *@return the number of bytes left or -1 in case of error. -+ */ -+glong -+cr_tknzr_get_nb_bytes_left (CRTknzr * a_this) -+{ -+ g_return_val_if_fail (a_this && PRIVATE (a_this) -+ && PRIVATE (a_this)->input, CR_BAD_PARAM_ERROR); -+ -+ if (PRIVATE (a_this)->token_cache) { -+ cr_input_set_cur_pos (PRIVATE (a_this)->input, -+ &PRIVATE (a_this)->prev_pos); -+ cr_token_destroy (PRIVATE (a_this)->token_cache); -+ PRIVATE (a_this)->token_cache = NULL; -+ } -+ -+ return cr_input_get_nb_bytes_left (PRIVATE (a_this)->input); -+} -+ -+enum CRStatus -+cr_tknzr_get_cur_pos (CRTknzr * a_this, CRInputPos * a_pos) -+{ -+ g_return_val_if_fail (a_this && PRIVATE (a_this) -+ && PRIVATE (a_this)->input -+ && a_pos, CR_BAD_PARAM_ERROR); -+ -+ if (PRIVATE (a_this)->token_cache) { -+ cr_input_set_cur_pos (PRIVATE (a_this)->input, -+ &PRIVATE (a_this)->prev_pos); -+ cr_token_destroy (PRIVATE (a_this)->token_cache); -+ PRIVATE (a_this)->token_cache = NULL; -+ } -+ -+ return cr_input_get_cur_pos (PRIVATE (a_this)->input, a_pos); -+} -+ -+enum CRStatus -+cr_tknzr_get_parsing_location (CRTknzr *a_this, -+ CRParsingLocation *a_loc) -+{ -+ g_return_val_if_fail (a_this -+ && PRIVATE (a_this) -+ && a_loc, -+ CR_BAD_PARAM_ERROR) ; -+ -+ return cr_input_get_parsing_location -+ (PRIVATE (a_this)->input, a_loc) ; -+} -+ -+enum CRStatus -+cr_tknzr_get_cur_byte_addr (CRTknzr * a_this, guchar ** a_addr) -+{ -+ g_return_val_if_fail (a_this && PRIVATE (a_this) -+ && PRIVATE (a_this)->input, CR_BAD_PARAM_ERROR); -+ if (PRIVATE (a_this)->token_cache) { -+ cr_input_set_cur_pos (PRIVATE (a_this)->input, -+ &PRIVATE (a_this)->prev_pos); -+ cr_token_destroy (PRIVATE (a_this)->token_cache); -+ PRIVATE (a_this)->token_cache = NULL; -+ } -+ -+ return cr_input_get_cur_byte_addr (PRIVATE (a_this)->input, a_addr); -+} -+ -+enum CRStatus -+cr_tknzr_seek_index (CRTknzr * a_this, enum CRSeekPos a_origin, gint a_pos) -+{ -+ g_return_val_if_fail (a_this && PRIVATE (a_this) -+ && PRIVATE (a_this)->input, CR_BAD_PARAM_ERROR); -+ -+ if (PRIVATE (a_this)->token_cache) { -+ cr_input_set_cur_pos (PRIVATE (a_this)->input, -+ &PRIVATE (a_this)->prev_pos); -+ cr_token_destroy (PRIVATE (a_this)->token_cache); -+ PRIVATE (a_this)->token_cache = NULL; -+ } -+ -+ return cr_input_seek_index (PRIVATE (a_this)->input, a_origin, a_pos); -+} -+ -+enum CRStatus -+cr_tknzr_consume_chars (CRTknzr * a_this, guint32 a_char, glong * a_nb_char) -+{ -+ gulong consumed = *(gulong *) a_nb_char; -+ enum CRStatus status; -+ g_return_val_if_fail (a_this && PRIVATE (a_this) -+ && PRIVATE (a_this)->input, CR_BAD_PARAM_ERROR); -+ -+ if (PRIVATE (a_this)->token_cache) { -+ cr_input_set_cur_pos (PRIVATE (a_this)->input, -+ &PRIVATE (a_this)->prev_pos); -+ cr_token_destroy (PRIVATE (a_this)->token_cache); -+ PRIVATE (a_this)->token_cache = NULL; -+ } -+ -+ status = cr_input_consume_chars (PRIVATE (a_this)->input, -+ a_char, &consumed); -+ *a_nb_char = (glong) consumed; -+ return status; -+} -+ -+enum CRStatus -+cr_tknzr_set_cur_pos (CRTknzr * a_this, CRInputPos * a_pos) -+{ -+ g_return_val_if_fail (a_this && PRIVATE (a_this) -+ && PRIVATE (a_this)->input, CR_BAD_PARAM_ERROR); -+ -+ if (PRIVATE (a_this)->token_cache) { -+ cr_token_destroy (PRIVATE (a_this)->token_cache); -+ PRIVATE (a_this)->token_cache = NULL; -+ } -+ -+ return cr_input_set_cur_pos (PRIVATE (a_this)->input, a_pos); -+} -+ -+enum CRStatus -+cr_tknzr_unget_token (CRTknzr * a_this, CRToken * a_token) -+{ -+ g_return_val_if_fail (a_this && PRIVATE (a_this) -+ && PRIVATE (a_this)->token_cache == NULL, -+ CR_BAD_PARAM_ERROR); -+ -+ PRIVATE (a_this)->token_cache = a_token; -+ -+ return CR_OK; -+} -+ -+/** -+ *Returns the next token of the input stream. -+ *This method is really central. Each parsing -+ *method calls it. -+ *@param a_this the current tokenizer. -+ *@param a_tk out parameter. The returned token. -+ *for the sake of mem leak avoidance, *a_tk must -+ *be NULL. -+ *@param CR_OK upon successfull completion, an error code -+ *otherwise. -+ */ -+enum CRStatus -+cr_tknzr_get_next_token (CRTknzr * a_this, CRToken ** a_tk) -+{ -+ enum CRStatus status = CR_OK; -+ CRToken *token = NULL; -+ CRInputPos init_pos; -+ guint32 next_char = 0; -+ guchar next_bytes[4] = { 0 }; -+ gboolean reached_eof = FALSE; -+ CRInput *input = NULL; -+ CRString *str = NULL; -+ CRRgb *rgb = NULL; -+ CRParsingLocation location = {0} ; -+ -+ g_return_val_if_fail (a_this && PRIVATE (a_this) -+ && a_tk && *a_tk == NULL -+ && PRIVATE (a_this)->input, -+ CR_BAD_PARAM_ERROR); -+ -+ if (PRIVATE (a_this)->token_cache) { -+ *a_tk = PRIVATE (a_this)->token_cache; -+ PRIVATE (a_this)->token_cache = NULL; -+ return CR_OK; -+ } -+ -+ RECORD_INITIAL_POS (a_this, &init_pos); -+ -+ status = cr_input_get_end_of_file -+ (PRIVATE (a_this)->input, &reached_eof); -+ ENSURE_PARSING_COND (status == CR_OK); -+ -+ if (reached_eof == TRUE) { -+ status = CR_END_OF_INPUT_ERROR; -+ goto error; -+ } -+ -+ input = PRIVATE (a_this)->input; -+ -+ PEEK_NEXT_CHAR (a_this, &next_char); -+ token = cr_token_new (); -+ ENSURE_PARSING_COND (token); -+ -+ switch (next_char) { -+ case '@': -+ { -+ if (BYTE (input, 2, NULL) == 'f' -+ && BYTE (input, 3, NULL) == 'o' -+ && BYTE (input, 4, NULL) == 'n' -+ && BYTE (input, 5, NULL) == 't' -+ && BYTE (input, 6, NULL) == '-' -+ && BYTE (input, 7, NULL) == 'f' -+ && BYTE (input, 8, NULL) == 'a' -+ && BYTE (input, 9, NULL) == 'c' -+ && BYTE (input, 10, NULL) == 'e') { -+ SKIP_CHARS (a_this, 1); -+ cr_tknzr_get_parsing_location -+ (a_this, &location) ; -+ SKIP_CHARS (a_this, 9); -+ status = cr_token_set_font_face_sym (token); -+ CHECK_PARSING_STATUS (status, TRUE); -+ cr_parsing_location_copy (&token->location, -+ &location) ; -+ goto done; -+ } -+ -+ if (BYTE (input, 2, NULL) == 'c' -+ && BYTE (input, 3, NULL) == 'h' -+ && BYTE (input, 4, NULL) == 'a' -+ && BYTE (input, 5, NULL) == 'r' -+ && BYTE (input, 6, NULL) == 's' -+ && BYTE (input, 7, NULL) == 'e' -+ && BYTE (input, 8, NULL) == 't') { -+ SKIP_CHARS (a_this, 1); -+ cr_tknzr_get_parsing_location -+ (a_this, &location) ; -+ SKIP_CHARS (a_this, 7); -+ status = cr_token_set_charset_sym (token); -+ CHECK_PARSING_STATUS (status, TRUE); -+ cr_parsing_location_copy (&token->location, -+ &location) ; -+ goto done; -+ } -+ -+ if (BYTE (input, 2, NULL) == 'i' -+ && BYTE (input, 3, NULL) == 'm' -+ && BYTE (input, 4, NULL) == 'p' -+ && BYTE (input, 5, NULL) == 'o' -+ && BYTE (input, 6, NULL) == 'r' -+ && BYTE (input, 7, NULL) == 't') { -+ SKIP_CHARS (a_this, 1); -+ cr_tknzr_get_parsing_location -+ (a_this, &location) ; -+ SKIP_CHARS (a_this, 6); -+ status = cr_token_set_import_sym (token); -+ CHECK_PARSING_STATUS (status, TRUE); -+ cr_parsing_location_copy (&token->location, -+ &location) ; -+ goto done; -+ } -+ -+ if (BYTE (input, 2, NULL) == 'm' -+ && BYTE (input, 3, NULL) == 'e' -+ && BYTE (input, 4, NULL) == 'd' -+ && BYTE (input, 5, NULL) == 'i' -+ && BYTE (input, 6, NULL) == 'a') { -+ SKIP_CHARS (a_this, 1); -+ cr_tknzr_get_parsing_location (a_this, -+ &location) ; -+ SKIP_CHARS (a_this, 5); -+ status = cr_token_set_media_sym (token); -+ CHECK_PARSING_STATUS (status, TRUE); -+ cr_parsing_location_copy (&token->location, -+ &location) ; -+ goto done; -+ } -+ -+ if (BYTE (input, 2, NULL) == 'p' -+ && BYTE (input, 3, NULL) == 'a' -+ && BYTE (input, 4, NULL) == 'g' -+ && BYTE (input, 5, NULL) == 'e') { -+ SKIP_CHARS (a_this, 1); -+ cr_tknzr_get_parsing_location (a_this, -+ &location) ; -+ SKIP_CHARS (a_this, 4); -+ status = cr_token_set_page_sym (token); -+ CHECK_PARSING_STATUS (status, TRUE); -+ cr_parsing_location_copy (&token->location, -+ &location) ; -+ goto done; -+ } -+ status = cr_tknzr_parse_atkeyword (a_this, &str); -+ if (status == CR_OK) { -+ status = cr_token_set_atkeyword (token, str); -+ CHECK_PARSING_STATUS (status, TRUE); -+ if (str) { -+ cr_parsing_location_copy (&token->location, -+ &str->location) ; -+ } -+ goto done; -+ } -+ } -+ break; -+ -+ case 'u': -+ -+ if (BYTE (input, 2, NULL) == 'r' -+ && BYTE (input, 3, NULL) == 'l' -+ && BYTE (input, 4, NULL) == '(') { -+ CRString *str2 = NULL; -+ -+ status = cr_tknzr_parse_uri (a_this, &str2); -+ if (status == CR_OK) { -+ status = cr_token_set_uri (token, str2); -+ CHECK_PARSING_STATUS (status, TRUE); -+ if (str2) { -+ cr_parsing_location_copy (&token->location, -+ &str2->location) ; -+ } -+ goto done; -+ } -+ } -+ goto fallback; -+ break; -+ -+ case 'r': -+ if (BYTE (input, 2, NULL) == 'g' -+ && BYTE (input, 3, NULL) == 'b' -+ && BYTE (input, 4, NULL) == '(') { -+ status = cr_tknzr_parse_rgb (a_this, &rgb); -+ if (status == CR_OK && rgb) { -+ status = cr_token_set_rgb (token, rgb); -+ CHECK_PARSING_STATUS (status, TRUE); -+ if (rgb) { -+ cr_parsing_location_copy (&token->location, -+ &rgb->location) ; -+ } -+ rgb = NULL; -+ goto done; -+ } -+ -+ } -+ goto fallback; -+ break; -+ -+ case '<': -+ if (BYTE (input, 2, NULL) == '!' -+ && BYTE (input, 3, NULL) == '-' -+ && BYTE (input, 4, NULL) == '-') { -+ SKIP_CHARS (a_this, 1); -+ cr_tknzr_get_parsing_location (a_this, -+ &location) ; -+ SKIP_CHARS (a_this, 3); -+ status = cr_token_set_cdo (token); -+ CHECK_PARSING_STATUS (status, TRUE); -+ cr_parsing_location_copy (&token->location, -+ &location) ; -+ goto done; -+ } -+ break; -+ -+ case '-': -+ if (BYTE (input, 2, NULL) == '-' -+ && BYTE (input, 3, NULL) == '>') { -+ SKIP_CHARS (a_this, 1); -+ cr_tknzr_get_parsing_location (a_this, -+ &location) ; -+ SKIP_CHARS (a_this, 2); -+ status = cr_token_set_cdc (token); -+ CHECK_PARSING_STATUS (status, TRUE); -+ cr_parsing_location_copy (&token->location, -+ &location) ; -+ goto done; -+ } else { -+ status = cr_tknzr_parse_ident -+ (a_this, &str); -+ if (status == CR_OK) { -+ cr_token_set_ident -+ (token, str); -+ if (str) { -+ cr_parsing_location_copy (&token->location, -+ &str->location) ; -+ } -+ goto done; -+ } else { -+ goto parse_number; -+ } -+ } -+ break; -+ -+ case '~': -+ if (BYTE (input, 2, NULL) == '=') { -+ SKIP_CHARS (a_this, 1); -+ cr_tknzr_get_parsing_location (a_this, -+ &location) ; -+ SKIP_CHARS (a_this, 1); -+ status = cr_token_set_includes (token); -+ CHECK_PARSING_STATUS (status, TRUE); -+ cr_parsing_location_copy (&token->location, -+ &location) ; -+ goto done; -+ } -+ break; -+ -+ case '|': -+ if (BYTE (input, 2, NULL) == '=') { -+ SKIP_CHARS (a_this, 1); -+ cr_tknzr_get_parsing_location (a_this, -+ &location) ; -+ SKIP_CHARS (a_this, 1); -+ status = cr_token_set_dashmatch (token); -+ CHECK_PARSING_STATUS (status, TRUE); -+ cr_parsing_location_copy (&token->location, -+ &location) ; -+ goto done; -+ } -+ break; -+ -+ case '/': -+ if (BYTE (input, 2, NULL) == '*') { -+ status = cr_tknzr_parse_comment (a_this, &str); -+ -+ if (status == CR_OK) { -+ status = cr_token_set_comment (token, str); -+ str = NULL; -+ CHECK_PARSING_STATUS (status, TRUE); -+ if (str) { -+ cr_parsing_location_copy (&token->location, -+ &str->location) ; -+ } -+ goto done; -+ } -+ } -+ break ; -+ -+ case ';': -+ SKIP_CHARS (a_this, 1); -+ cr_tknzr_get_parsing_location (a_this, -+ &location) ; -+ status = cr_token_set_semicolon (token); -+ CHECK_PARSING_STATUS (status, TRUE); -+ cr_parsing_location_copy (&token->location, -+ &location) ; -+ goto done; -+ -+ case '{': -+ SKIP_CHARS (a_this, 1); -+ cr_tknzr_get_parsing_location (a_this, -+ &location) ; -+ status = cr_token_set_cbo (token); -+ CHECK_PARSING_STATUS (status, TRUE); -+ cr_tknzr_get_parsing_location (a_this, -+ &location) ; -+ goto done; -+ -+ case '}': -+ SKIP_CHARS (a_this, 1); -+ cr_tknzr_get_parsing_location (a_this, -+ &location) ; -+ status = cr_token_set_cbc (token); -+ CHECK_PARSING_STATUS (status, TRUE); -+ cr_parsing_location_copy (&token->location, -+ &location) ; -+ goto done; -+ -+ case '(': -+ SKIP_CHARS (a_this, 1); -+ cr_tknzr_get_parsing_location (a_this, -+ &location) ; -+ status = cr_token_set_po (token); -+ CHECK_PARSING_STATUS (status, TRUE); -+ cr_parsing_location_copy (&token->location, -+ &location) ; -+ goto done; -+ -+ case ')': -+ SKIP_CHARS (a_this, 1); -+ cr_tknzr_get_parsing_location (a_this, -+ &location) ; -+ status = cr_token_set_pc (token); -+ CHECK_PARSING_STATUS (status, TRUE); -+ cr_parsing_location_copy (&token->location, -+ &location) ; -+ goto done; -+ -+ case '[': -+ SKIP_CHARS (a_this, 1); -+ cr_tknzr_get_parsing_location (a_this, -+ &location) ; -+ status = cr_token_set_bo (token); -+ CHECK_PARSING_STATUS (status, TRUE); -+ cr_parsing_location_copy (&token->location, -+ &location) ; -+ goto done; -+ -+ case ']': -+ SKIP_CHARS (a_this, 1); -+ cr_tknzr_get_parsing_location (a_this, -+ &location) ; -+ status = cr_token_set_bc (token); -+ CHECK_PARSING_STATUS (status, TRUE); -+ cr_parsing_location_copy (&token->location, -+ &location) ; -+ goto done; -+ -+ case ' ': -+ case '\t': -+ case '\n': -+ case '\f': -+ case '\r': -+ { -+ guchar *start = NULL, -+ *end = NULL; -+ -+ status = cr_tknzr_parse_w (a_this, &start, -+ &end, &location); -+ if (status == CR_OK) { -+ status = cr_token_set_s (token); -+ CHECK_PARSING_STATUS (status, TRUE); -+ cr_tknzr_get_parsing_location (a_this, -+ &location) ; -+ goto done; -+ } -+ } -+ break; -+ -+ case '#': -+ { -+ status = cr_tknzr_parse_hash (a_this, &str); -+ if (status == CR_OK && str) { -+ status = cr_token_set_hash (token, str); -+ CHECK_PARSING_STATUS (status, TRUE); -+ if (str) { -+ cr_parsing_location_copy (&token->location, -+ &str->location) ; -+ } -+ str = NULL; -+ goto done; -+ } -+ } -+ break; -+ -+ case '\'': -+ case '"': -+ status = cr_tknzr_parse_string (a_this, &str); -+ if (status == CR_OK && str) { -+ status = cr_token_set_string (token, str); -+ CHECK_PARSING_STATUS (status, TRUE); -+ if (str) { -+ cr_parsing_location_copy (&token->location, -+ &str->location) ; -+ } -+ str = NULL; -+ goto done; -+ } -+ break; -+ -+ case '!': -+ status = cr_tknzr_parse_important (a_this, &location); -+ if (status == CR_OK) { -+ status = cr_token_set_important_sym (token); -+ CHECK_PARSING_STATUS (status, TRUE); -+ cr_parsing_location_copy (&token->location, -+ &location) ; -+ goto done; -+ } -+ break; -+ -+ case '0': -+ case '1': -+ case '2': -+ case '3': -+ case '4': -+ case '5': -+ case '6': -+ case '7': -+ case '8': -+ case '9': -+ case '.': -+ case '+': -+ /* '-' case is handled separately above for --> comments */ -+ parse_number: -+ { -+ CRNum *num = NULL; -+ -+ status = cr_tknzr_parse_num (a_this, &num); -+ if (status == CR_OK && num) { -+ next_bytes[0] = BYTE (input, 1, NULL); -+ next_bytes[1] = BYTE (input, 2, NULL); -+ next_bytes[2] = BYTE (input, 3, NULL); -+ next_bytes[3] = BYTE (input, 4, NULL); -+ -+ if (next_bytes[0] == 'e' -+ && next_bytes[1] == 'm') { -+ num->type = NUM_LENGTH_EM; -+ status = cr_token_set_ems (token, -+ num); -+ num = NULL; -+ SKIP_CHARS (a_this, 2); -+ } else if (next_bytes[0] == 'e' -+ && next_bytes[1] == 'x') { -+ num->type = NUM_LENGTH_EX; -+ status = cr_token_set_exs (token, -+ num); -+ num = NULL; -+ SKIP_CHARS (a_this, 2); -+ } else if (next_bytes[0] == 'p' -+ && next_bytes[1] == 'x') { -+ num->type = NUM_LENGTH_PX; -+ status = cr_token_set_length -+ (token, num, LENGTH_PX_ET); -+ num = NULL; -+ SKIP_CHARS (a_this, 2); -+ } else if (next_bytes[0] == 'c' -+ && next_bytes[1] == 'm') { -+ num->type = NUM_LENGTH_CM; -+ status = cr_token_set_length -+ (token, num, LENGTH_CM_ET); -+ num = NULL; -+ SKIP_CHARS (a_this, 2); -+ } else if (next_bytes[0] == 'm' -+ && next_bytes[1] == 'm') { -+ num->type = NUM_LENGTH_MM; -+ status = cr_token_set_length -+ (token, num, LENGTH_MM_ET); -+ num = NULL; -+ SKIP_CHARS (a_this, 2); -+ } else if (next_bytes[0] == 'i' -+ && next_bytes[1] == 'n') { -+ num->type = NUM_LENGTH_IN; -+ status = cr_token_set_length -+ (token, num, LENGTH_IN_ET); -+ num = NULL; -+ SKIP_CHARS (a_this, 2); -+ } else if (next_bytes[0] == 'p' -+ && next_bytes[1] == 't') { -+ num->type = NUM_LENGTH_PT; -+ status = cr_token_set_length -+ (token, num, LENGTH_PT_ET); -+ num = NULL; -+ SKIP_CHARS (a_this, 2); -+ } else if (next_bytes[0] == 'p' -+ && next_bytes[1] == 'c') { -+ num->type = NUM_LENGTH_PC; -+ status = cr_token_set_length -+ (token, num, LENGTH_PC_ET); -+ num = NULL; -+ SKIP_CHARS (a_this, 2); -+ } else if (next_bytes[0] == 'd' -+ && next_bytes[1] == 'e' -+ && next_bytes[2] == 'g') { -+ num->type = NUM_ANGLE_DEG; -+ status = cr_token_set_angle -+ (token, num, ANGLE_DEG_ET); -+ num = NULL; -+ SKIP_CHARS (a_this, 3); -+ } else if (next_bytes[0] == 'r' -+ && next_bytes[1] == 'a' -+ && next_bytes[2] == 'd') { -+ num->type = NUM_ANGLE_RAD; -+ status = cr_token_set_angle -+ (token, num, ANGLE_RAD_ET); -+ num = NULL; -+ SKIP_CHARS (a_this, 3); -+ } else if (next_bytes[0] == 'g' -+ && next_bytes[1] == 'r' -+ && next_bytes[2] == 'a' -+ && next_bytes[3] == 'd') { -+ num->type = NUM_ANGLE_GRAD; -+ status = cr_token_set_angle -+ (token, num, ANGLE_GRAD_ET); -+ num = NULL; -+ SKIP_CHARS (a_this, 4); -+ } else if (next_bytes[0] == 'm' -+ && next_bytes[1] == 's') { -+ num->type = NUM_TIME_MS; -+ status = cr_token_set_time -+ (token, num, TIME_MS_ET); -+ num = NULL; -+ SKIP_CHARS (a_this, 2); -+ } else if (next_bytes[0] == 's') { -+ num->type = NUM_TIME_S; -+ status = cr_token_set_time -+ (token, num, TIME_S_ET); -+ num = NULL; -+ SKIP_CHARS (a_this, 1); -+ } else if (next_bytes[0] == 'H' -+ && next_bytes[1] == 'z') { -+ num->type = NUM_FREQ_HZ; -+ status = cr_token_set_freq -+ (token, num, FREQ_HZ_ET); -+ num = NULL; -+ SKIP_CHARS (a_this, 2); -+ } else if (next_bytes[0] == 'k' -+ && next_bytes[1] == 'H' -+ && next_bytes[2] == 'z') { -+ num->type = NUM_FREQ_KHZ; -+ status = cr_token_set_freq -+ (token, num, FREQ_KHZ_ET); -+ num = NULL; -+ SKIP_CHARS (a_this, 3); -+ } else if (next_bytes[0] == '%') { -+ num->type = NUM_PERCENTAGE; -+ status = cr_token_set_percentage -+ (token, num); -+ num = NULL; -+ SKIP_CHARS (a_this, 1); -+ } else { -+ status = cr_tknzr_parse_ident (a_this, -+ &str); -+ if (status == CR_OK && str) { -+ num->type = NUM_UNKNOWN_TYPE; -+ status = cr_token_set_dimen -+ (token, num, str); -+ num = NULL; -+ CHECK_PARSING_STATUS (status, -+ TRUE); -+ str = NULL; -+ } else { -+ status = cr_token_set_number -+ (token, num); -+ num = NULL; -+ CHECK_PARSING_STATUS (status, CR_OK); -+ str = NULL; -+ } -+ } -+ if (token && token->u.num) { -+ cr_parsing_location_copy (&token->location, -+ &token->u.num->location) ; -+ } else { -+ status = CR_ERROR ; -+ } -+ goto done ; -+ } -+ } -+ break; -+ -+ default: -+ fallback: -+ /*process the fallback cases here */ -+ -+ if (next_char == '\\' -+ || (cr_utils_is_nonascii (next_bytes[0]) == TRUE) -+ || ((next_char >= 'a') && (next_char <= 'z')) -+ || ((next_char >= 'A') && (next_char <= 'Z'))) { -+ status = cr_tknzr_parse_ident (a_this, &str); -+ if (status == CR_OK && str) { -+ guint32 next_c = 0; -+ -+ status = cr_input_peek_char -+ (PRIVATE (a_this)->input, &next_c); -+ -+ if (status == CR_OK && next_c == '(') { -+ -+ SKIP_CHARS (a_this, 1); -+ status = cr_token_set_function -+ (token, str); -+ CHECK_PARSING_STATUS (status, TRUE); -+ /*ownership is transfered -+ *to token by cr_token_set_function. -+ */ -+ if (str) { -+ cr_parsing_location_copy (&token->location, -+ &str->location) ; -+ } -+ str = NULL; -+ } else { -+ status = cr_token_set_ident (token, -+ str); -+ CHECK_PARSING_STATUS (status, TRUE); -+ if (str) { -+ cr_parsing_location_copy (&token->location, -+ &str->location) ; -+ } -+ str = NULL; -+ } -+ goto done; -+ } else { -+ if (str) { -+ cr_string_destroy (str); -+ str = NULL; -+ } -+ } -+ } -+ break; -+ } -+ -+ READ_NEXT_CHAR (a_this, &next_char); -+ cr_tknzr_get_parsing_location (a_this, -+ &location) ; -+ status = cr_token_set_delim (token, next_char); -+ CHECK_PARSING_STATUS (status, TRUE); -+ cr_parsing_location_copy (&token->location, -+ &location) ; -+ done: -+ -+ if (status == CR_OK && token) { -+ *a_tk = token; -+ /* -+ *store the previous position input stream pos. -+ */ -+ memmove (&PRIVATE (a_this)->prev_pos, -+ &init_pos, sizeof (CRInputPos)); -+ return CR_OK; -+ } -+ -+ error: -+ if (token) { -+ cr_token_destroy (token); -+ token = NULL; -+ } -+ -+ if (str) { -+ cr_string_destroy (str); -+ str = NULL; -+ } -+ cr_tknzr_set_cur_pos (a_this, &init_pos); -+ return status; -+ -+} -+ -+enum CRStatus -+cr_tknzr_parse_token (CRTknzr * a_this, enum CRTokenType a_type, -+ enum CRTokenExtraType a_et, gpointer a_res, -+ gpointer a_extra_res) -+{ -+ enum CRStatus status = CR_OK; -+ CRToken *token = NULL; -+ -+ g_return_val_if_fail (a_this && PRIVATE (a_this) -+ && PRIVATE (a_this)->input -+ && a_res, CR_BAD_PARAM_ERROR); -+ -+ status = cr_tknzr_get_next_token (a_this, &token); -+ if (status != CR_OK) -+ return status; -+ if (token == NULL) -+ return CR_PARSING_ERROR; -+ -+ if (token->type == a_type) { -+ switch (a_type) { -+ case NO_TK: -+ case S_TK: -+ case CDO_TK: -+ case CDC_TK: -+ case INCLUDES_TK: -+ case DASHMATCH_TK: -+ case IMPORT_SYM_TK: -+ case PAGE_SYM_TK: -+ case MEDIA_SYM_TK: -+ case FONT_FACE_SYM_TK: -+ case CHARSET_SYM_TK: -+ case IMPORTANT_SYM_TK: -+ status = CR_OK; -+ break; -+ -+ case STRING_TK: -+ case IDENT_TK: -+ case HASH_TK: -+ case ATKEYWORD_TK: -+ case FUNCTION_TK: -+ case COMMENT_TK: -+ case URI_TK: -+ *((CRString **) a_res) = token->u.str; -+ token->u.str = NULL; -+ status = CR_OK; -+ break; -+ -+ case EMS_TK: -+ case EXS_TK: -+ case PERCENTAGE_TK: -+ case NUMBER_TK: -+ *((CRNum **) a_res) = token->u.num; -+ token->u.num = NULL; -+ status = CR_OK; -+ break; -+ -+ case LENGTH_TK: -+ case ANGLE_TK: -+ case TIME_TK: -+ case FREQ_TK: -+ if (token->extra_type == a_et) { -+ *((CRNum **) a_res) = token->u.num; -+ token->u.num = NULL; -+ status = CR_OK; -+ } -+ break; -+ -+ case DIMEN_TK: -+ *((CRNum **) a_res) = token->u.num; -+ if (a_extra_res == NULL) { -+ status = CR_BAD_PARAM_ERROR; -+ goto error; -+ } -+ -+ *((CRString **) a_extra_res) = token->dimen; -+ token->u.num = NULL; -+ token->dimen = NULL; -+ status = CR_OK; -+ break; -+ -+ case DELIM_TK: -+ *((guint32 *) a_res) = token->u.unichar; -+ status = CR_OK; -+ break; -+ -+ case UNICODERANGE_TK: -+ default: -+ status = CR_PARSING_ERROR; -+ break; -+ } -+ -+ cr_token_destroy (token); -+ token = NULL; -+ } else { -+ cr_tknzr_unget_token (a_this, token); -+ token = NULL; -+ status = CR_PARSING_ERROR; -+ } -+ -+ return status; -+ -+ error: -+ -+ if (token) { -+ cr_tknzr_unget_token (a_this, token); -+ token = NULL; -+ } -+ -+ return status; -+} -+ -+void -+cr_tknzr_destroy (CRTknzr * a_this) -+{ -+ g_return_if_fail (a_this); -+ -+ if (PRIVATE (a_this) && PRIVATE (a_this)->input) { -+ if (cr_input_unref (PRIVATE (a_this)->input) -+ == TRUE) { -+ PRIVATE (a_this)->input = NULL; -+ } -+ } -+ -+ if (PRIVATE (a_this)->token_cache) { -+ cr_token_destroy (PRIVATE (a_this)->token_cache); -+ PRIVATE (a_this)->token_cache = NULL; -+ } -+ -+ if (PRIVATE (a_this)) { -+ g_free (PRIVATE (a_this)); -+ PRIVATE (a_this) = NULL; -+ } -+ -+ g_free (a_this); -+} -diff --git a/src/st/croco/cr-tknzr.h b/src/st/croco/cr-tknzr.h -new file mode 100644 -index 000000000..13985b30e ---- /dev/null -+++ b/src/st/croco/cr-tknzr.h -@@ -0,0 +1,115 @@ -+/* -*- Mode: C; indent-tabs-mode:nil; c-basic-offset: 8-*- */ -+ -+/* -+ * This file is part of The Croco Library -+ * -+ * 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 -+ * See COPYRIGHTS file for coypyright information. -+ */ -+ -+/** -+ *@file -+ *The declaration of the #CRTknzr (tokenizer) -+ *class. -+ */ -+ -+#ifndef __CR_TKNZR_H__ -+#define __CR_TKNZR_H__ -+ -+#include "cr-utils.h" -+#include "cr-input.h" -+#include "cr-token.h" -+ -+G_BEGIN_DECLS -+ -+ -+typedef struct _CRTknzr CRTknzr ; -+typedef struct _CRTknzrPriv CRTknzrPriv ; -+ -+/** -+ *The tokenizer is the class that knows -+ *about all the css token. Its main job is -+ *to return the next token found in the character -+ *input stream. -+ */ -+struct _CRTknzr -+{ -+ /*the private data of the tokenizer.*/ -+ CRTknzrPriv *priv ; -+} ; -+ -+CRTknzr * cr_tknzr_new (CRInput *a_input) ; -+ -+CRTknzr * cr_tknzr_new_from_uri (const guchar *a_file_uri, -+ enum CREncoding a_enc) ; -+ -+CRTknzr * cr_tknzr_new_from_buf (guchar *a_buf, gulong a_len, -+ enum CREncoding a_enc, -+ gboolean a_free_at_destroy) ; -+ -+gboolean cr_tknzr_unref (CRTknzr *a_this) ; -+ -+void cr_tknzr_ref (CRTknzr *a_this) ; -+ -+enum CRStatus cr_tknzr_read_byte (CRTknzr *a_this, guchar *a_byte) ; -+ -+enum CRStatus cr_tknzr_read_char (CRTknzr *a_this, guint32 *a_char); -+ -+enum CRStatus cr_tknzr_peek_char (CRTknzr *a_this, guint32 *a_char) ; -+ -+enum CRStatus cr_tknzr_peek_byte (CRTknzr *a_this, gulong a_offset, -+ guchar *a_byte) ; -+ -+guchar cr_tknzr_peek_byte2 (CRTknzr *a_this, gulong a_offset, -+ gboolean *a_eof) ; -+ -+enum CRStatus cr_tknzr_set_cur_pos (CRTknzr *a_this, CRInputPos *a_pos) ; -+ -+glong cr_tknzr_get_nb_bytes_left (CRTknzr *a_this) ; -+ -+enum CRStatus cr_tknzr_get_cur_pos (CRTknzr *a_this, CRInputPos *a_pos) ; -+ -+enum CRStatus cr_tknzr_get_parsing_location (CRTknzr *a_this, -+ CRParsingLocation *a_loc) ; -+ -+enum CRStatus cr_tknzr_seek_index (CRTknzr *a_this, -+ enum CRSeekPos a_origin, -+ gint a_pos) ; -+ -+enum CRStatus cr_tknzr_get_cur_byte_addr (CRTknzr *a_this, guchar **a_addr) ; -+ -+ -+enum CRStatus cr_tknzr_consume_chars (CRTknzr *a_this, guint32 a_char, -+ glong *a_nb_char) ; -+ -+enum CRStatus cr_tknzr_get_next_token (CRTknzr *a_this, CRToken ** a_tk) ; -+ -+enum CRStatus cr_tknzr_unget_token (CRTknzr *a_this, CRToken *a_token) ; -+ -+ -+enum CRStatus cr_tknzr_parse_token (CRTknzr *a_this, enum CRTokenType a_type, -+ enum CRTokenExtraType a_et, gpointer a_res, -+ gpointer a_extra_res) ; -+enum CRStatus cr_tknzr_set_input (CRTknzr *a_this, CRInput *a_input) ; -+ -+enum CRStatus cr_tknzr_get_input (CRTknzr *a_this, CRInput **a_input) ; -+ -+void cr_tknzr_destroy (CRTknzr *a_this) ; -+ -+G_END_DECLS -+ -+#endif /*__CR_TKZNR_H__*/ -diff --git a/src/st/croco/cr-token.c b/src/st/croco/cr-token.c -new file mode 100644 -index 000000000..e240ab8f1 ---- /dev/null -+++ b/src/st/croco/cr-token.c -@@ -0,0 +1,636 @@ -+/* -*- Mode: C; indent-tabs-mode:nil; c-basic-offset: 8-*- */ -+ -+/* -+ * This file is part of The Croco Library -+ * -+ * 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 -+ * see COPYRIGHTS file for copyright information. -+ */ -+ -+/** -+ *@file -+ *The definition of the #CRToken class. -+ *Abstracts a css2 token. -+ */ -+#include -+#include "cr-token.h" -+ -+/* -+ *TODO: write a CRToken::to_string() method. -+ */ -+ -+/** -+ *Frees the attributes of the current instance -+ *of #CRtoken. -+ *@param a_this the current instance of #CRToken. -+ */ -+static void -+cr_token_clear (CRToken * a_this) -+{ -+ g_return_if_fail (a_this); -+ -+ switch (a_this->type) { -+ case S_TK: -+ case CDO_TK: -+ case CDC_TK: -+ case INCLUDES_TK: -+ case DASHMATCH_TK: -+ case PAGE_SYM_TK: -+ case MEDIA_SYM_TK: -+ case FONT_FACE_SYM_TK: -+ case CHARSET_SYM_TK: -+ case IMPORT_SYM_TK: -+ case IMPORTANT_SYM_TK: -+ case SEMICOLON_TK: -+ case NO_TK: -+ case DELIM_TK: -+ case CBO_TK: -+ case CBC_TK: -+ case BO_TK: -+ case BC_TK: -+ break; -+ -+ case STRING_TK: -+ case IDENT_TK: -+ case HASH_TK: -+ case URI_TK: -+ case FUNCTION_TK: -+ case COMMENT_TK: -+ case ATKEYWORD_TK: -+ if (a_this->u.str) { -+ cr_string_destroy (a_this->u.str); -+ a_this->u.str = NULL; -+ } -+ break; -+ -+ case EMS_TK: -+ case EXS_TK: -+ case LENGTH_TK: -+ case ANGLE_TK: -+ case TIME_TK: -+ case FREQ_TK: -+ case PERCENTAGE_TK: -+ case NUMBER_TK: -+ case PO_TK: -+ case PC_TK: -+ if (a_this->u.num) { -+ cr_num_destroy (a_this->u.num); -+ a_this->u.num = NULL; -+ } -+ break; -+ -+ case DIMEN_TK: -+ if (a_this->u.num) { -+ cr_num_destroy (a_this->u.num); -+ a_this->u.num = NULL; -+ } -+ -+ if (a_this->dimen) { -+ cr_string_destroy (a_this->dimen); -+ a_this->dimen = NULL; -+ } -+ -+ break; -+ -+ case RGB_TK: -+ if (a_this->u.rgb) { -+ cr_rgb_destroy (a_this->u.rgb) ; -+ a_this->u.rgb = NULL ; -+ } -+ break ; -+ -+ case UNICODERANGE_TK: -+ /*not supported yet. */ -+ break; -+ -+ default: -+ cr_utils_trace_info ("I don't know how to clear this token\n") ; -+ break; -+ } -+ -+ a_this->type = NO_TK; -+} -+ -+/** -+ *Default constructor of -+ *the #CRToken class. -+ *@return the newly built instance of #CRToken. -+ */ -+CRToken * -+cr_token_new (void) -+{ -+ CRToken *result = NULL; -+ -+ result = g_try_malloc (sizeof (CRToken)); -+ -+ if (result == NULL) { -+ cr_utils_trace_info ("Out of memory"); -+ return NULL; -+ } -+ -+ memset (result, 0, sizeof (CRToken)); -+ -+ return result; -+} -+ -+/** -+ *Sets the type of curren instance of -+ *#CRToken to 'S_TK' (S in the css2 spec) -+ *@param a_this the current instance of #CRToken. -+ *@return CR_OK upon successfull completion, an error -+ *code otherwise. -+ */ -+enum CRStatus -+cr_token_set_s (CRToken * a_this) -+{ -+ g_return_val_if_fail (a_this, CR_BAD_PARAM_ERROR); -+ -+ cr_token_clear (a_this); -+ -+ a_this->type = S_TK; -+ -+ return CR_OK; -+} -+ -+/** -+ *Sets the type of the current instance of -+ *#CRToken to 'CDO_TK' (CDO as said by the css2 spec) -+ *@param a_this the current instance of #CRToken. -+ *@return CR_OK upon successfull completion, an error -+ *code otherwise. -+ */ -+enum CRStatus -+cr_token_set_cdo (CRToken * a_this) -+{ -+ g_return_val_if_fail (a_this, CR_BAD_PARAM_ERROR); -+ -+ cr_token_clear (a_this); -+ -+ a_this->type = CDO_TK; -+ -+ return CR_OK; -+} -+ -+/** -+ *Sets the type of the current token to -+ *CDC_TK (CDC as said by the css2 spec). -+ *@param a_this the current instance of #CRToken. -+ *@return CR_OK upon successfull completion, an error -+ *code otherwise. -+ */ -+enum CRStatus -+cr_token_set_cdc (CRToken * a_this) -+{ -+ g_return_val_if_fail (a_this, CR_BAD_PARAM_ERROR); -+ -+ cr_token_clear (a_this); -+ -+ a_this->type = CDC_TK; -+ -+ return CR_OK; -+} -+ -+/** -+ *Sets the type of the current instance of -+ *#CRToken to INCLUDES_TK (INCLUDES as said by the css2 spec). -+ *@param a_this the current instance of #CRToken. -+ *@return CR_OK upon successfull completion, an error -+ *code otherwise. -+ */ -+enum CRStatus -+cr_token_set_includes (CRToken * a_this) -+{ -+ g_return_val_if_fail (a_this, CR_BAD_PARAM_ERROR); -+ -+ cr_token_clear (a_this); -+ -+ a_this->type = INCLUDES_TK; -+ -+ return CR_OK; -+} -+ -+/** -+ *Sets the type of the current instance of -+ *#CRToken to DASHMATCH_TK (DASHMATCH as said by the css2 spec). -+ *@param a_this the current instance of #CRToken. -+ *@return CR_OK upon successfull completion, an error -+ *code otherwise. -+ */ -+enum CRStatus -+cr_token_set_dashmatch (CRToken * a_this) -+{ -+ g_return_val_if_fail (a_this, CR_BAD_PARAM_ERROR); -+ -+ cr_token_clear (a_this); -+ -+ a_this->type = DASHMATCH_TK; -+ -+ return CR_OK; -+} -+ -+enum CRStatus -+cr_token_set_comment (CRToken * a_this, CRString * a_str) -+{ -+ g_return_val_if_fail (a_this, CR_BAD_PARAM_ERROR); -+ -+ cr_token_clear (a_this); -+ a_this->type = COMMENT_TK; -+ a_this->u.str = a_str ; -+ return CR_OK; -+} -+ -+enum CRStatus -+cr_token_set_string (CRToken * a_this, CRString * a_str) -+{ -+ g_return_val_if_fail (a_this, CR_BAD_PARAM_ERROR); -+ -+ cr_token_clear (a_this); -+ -+ a_this->type = STRING_TK; -+ -+ a_this->u.str = a_str ; -+ -+ return CR_OK; -+} -+ -+enum CRStatus -+cr_token_set_ident (CRToken * a_this, CRString * a_ident) -+{ -+ g_return_val_if_fail (a_this, CR_BAD_PARAM_ERROR); -+ -+ cr_token_clear (a_this); -+ a_this->type = IDENT_TK; -+ a_this->u.str = a_ident; -+ return CR_OK; -+} -+ -+ -+enum CRStatus -+cr_token_set_function (CRToken * a_this, CRString * a_fun_name) -+{ -+ g_return_val_if_fail (a_this, -+ CR_BAD_PARAM_ERROR); -+ -+ cr_token_clear (a_this); -+ a_this->type = FUNCTION_TK; -+ a_this->u.str = a_fun_name; -+ return CR_OK; -+} -+ -+enum CRStatus -+cr_token_set_hash (CRToken * a_this, CRString * a_hash) -+{ -+ g_return_val_if_fail (a_this, CR_BAD_PARAM_ERROR); -+ -+ cr_token_clear (a_this); -+ a_this->type = HASH_TK; -+ a_this->u.str = a_hash; -+ -+ return CR_OK; -+} -+ -+enum CRStatus -+cr_token_set_rgb (CRToken * a_this, CRRgb * a_rgb) -+{ -+ g_return_val_if_fail (a_this, CR_BAD_PARAM_ERROR); -+ -+ cr_token_clear (a_this); -+ a_this->type = RGB_TK; -+ a_this->u.rgb = a_rgb; -+ -+ return CR_OK; -+} -+ -+enum CRStatus -+cr_token_set_import_sym (CRToken * a_this) -+{ -+ g_return_val_if_fail (a_this, CR_BAD_PARAM_ERROR); -+ -+ cr_token_clear (a_this); -+ -+ a_this->type = IMPORT_SYM_TK; -+ -+ return CR_OK; -+} -+ -+enum CRStatus -+cr_token_set_page_sym (CRToken * a_this) -+{ -+ g_return_val_if_fail (a_this, CR_BAD_PARAM_ERROR); -+ -+ cr_token_clear (a_this); -+ -+ a_this->type = PAGE_SYM_TK; -+ -+ return CR_OK; -+} -+ -+enum CRStatus -+cr_token_set_media_sym (CRToken * a_this) -+{ -+ g_return_val_if_fail (a_this, CR_BAD_PARAM_ERROR); -+ -+ cr_token_clear (a_this); -+ -+ a_this->type = MEDIA_SYM_TK; -+ -+ return CR_OK; -+} -+ -+enum CRStatus -+cr_token_set_font_face_sym (CRToken * a_this) -+{ -+ g_return_val_if_fail (a_this, CR_BAD_PARAM_ERROR); -+ -+ cr_token_clear (a_this); -+ a_this->type = FONT_FACE_SYM_TK; -+ -+ return CR_OK; -+} -+ -+enum CRStatus -+cr_token_set_charset_sym (CRToken * a_this) -+{ -+ g_return_val_if_fail (a_this, CR_BAD_PARAM_ERROR); -+ -+ cr_token_clear (a_this); -+ a_this->type = CHARSET_SYM_TK; -+ -+ return CR_OK; -+} -+ -+enum CRStatus -+cr_token_set_atkeyword (CRToken * a_this, CRString * a_atname) -+{ -+ g_return_val_if_fail (a_this, CR_BAD_PARAM_ERROR); -+ -+ cr_token_clear (a_this); -+ a_this->type = ATKEYWORD_TK; -+ a_this->u.str = a_atname; -+ return CR_OK; -+} -+ -+enum CRStatus -+cr_token_set_important_sym (CRToken * a_this) -+{ -+ g_return_val_if_fail (a_this, CR_BAD_PARAM_ERROR); -+ cr_token_clear (a_this); -+ a_this->type = IMPORTANT_SYM_TK; -+ return CR_OK; -+} -+ -+enum CRStatus -+cr_token_set_ems (CRToken * a_this, CRNum * a_num) -+{ -+ g_return_val_if_fail (a_this, CR_BAD_PARAM_ERROR); -+ cr_token_clear (a_this); -+ a_this->type = EMS_TK; -+ a_this->u.num = a_num; -+ return CR_OK; -+} -+ -+enum CRStatus -+cr_token_set_exs (CRToken * a_this, CRNum * a_num) -+{ -+ g_return_val_if_fail (a_this, CR_BAD_PARAM_ERROR); -+ cr_token_clear (a_this); -+ a_this->type = EXS_TK; -+ a_this->u.num = a_num; -+ return CR_OK; -+} -+ -+enum CRStatus -+cr_token_set_length (CRToken * a_this, CRNum * a_num, -+ enum CRTokenExtraType a_et) -+{ -+ g_return_val_if_fail (a_this, CR_BAD_PARAM_ERROR); -+ -+ cr_token_clear (a_this); -+ -+ a_this->type = LENGTH_TK; -+ a_this->extra_type = a_et; -+ a_this->u.num = a_num; -+ -+ return CR_OK; -+} -+ -+enum CRStatus -+cr_token_set_angle (CRToken * a_this, CRNum * a_num, -+ enum CRTokenExtraType a_et) -+{ -+ g_return_val_if_fail (a_this, CR_BAD_PARAM_ERROR); -+ -+ cr_token_clear (a_this); -+ -+ a_this->type = ANGLE_TK; -+ a_this->extra_type = a_et; -+ a_this->u.num = a_num; -+ -+ return CR_OK; -+} -+ -+enum CRStatus -+cr_token_set_time (CRToken * a_this, CRNum * a_num, -+ enum CRTokenExtraType a_et) -+{ -+ g_return_val_if_fail (a_this, CR_BAD_PARAM_ERROR); -+ -+ cr_token_clear (a_this); -+ -+ a_this->type = TIME_TK; -+ a_this->extra_type = a_et; -+ a_this->u.num = a_num; -+ -+ return CR_OK; -+} -+ -+enum CRStatus -+cr_token_set_freq (CRToken * a_this, CRNum * a_num, -+ enum CRTokenExtraType a_et) -+{ -+ g_return_val_if_fail (a_this, CR_BAD_PARAM_ERROR); -+ -+ cr_token_clear (a_this); -+ -+ a_this->type = FREQ_TK; -+ a_this->extra_type = a_et; -+ a_this->u.num = a_num; -+ -+ return CR_OK; -+} -+ -+enum CRStatus -+cr_token_set_dimen (CRToken * a_this, CRNum * a_num, -+ CRString * a_dim) -+{ -+ g_return_val_if_fail (a_this, CR_BAD_PARAM_ERROR); -+ cr_token_clear (a_this); -+ a_this->type = DIMEN_TK; -+ a_this->u.num = a_num; -+ a_this->dimen = a_dim; -+ return CR_OK; -+ -+} -+ -+enum CRStatus -+cr_token_set_percentage (CRToken * a_this, CRNum * a_num) -+{ -+ g_return_val_if_fail (a_this, CR_BAD_PARAM_ERROR); -+ -+ cr_token_clear (a_this); -+ -+ a_this->type = PERCENTAGE_TK; -+ a_this->u.num = a_num; -+ -+ return CR_OK; -+} -+ -+enum CRStatus -+cr_token_set_number (CRToken * a_this, CRNum * a_num) -+{ -+ g_return_val_if_fail (a_this, CR_BAD_PARAM_ERROR); -+ -+ cr_token_clear (a_this); -+ -+ a_this->type = NUMBER_TK; -+ a_this->u.num = a_num; -+ return CR_OK; -+} -+ -+enum CRStatus -+cr_token_set_uri (CRToken * a_this, CRString * a_uri) -+{ -+ g_return_val_if_fail (a_this, CR_BAD_PARAM_ERROR); -+ -+ cr_token_clear (a_this); -+ -+ a_this->type = URI_TK; -+ a_this->u.str = a_uri; -+ -+ return CR_OK; -+} -+ -+enum CRStatus -+cr_token_set_delim (CRToken * a_this, guint32 a_char) -+{ -+ g_return_val_if_fail (a_this, CR_BAD_PARAM_ERROR); -+ -+ cr_token_clear (a_this); -+ -+ a_this->type = DELIM_TK; -+ a_this->u.unichar = a_char; -+ -+ return CR_OK; -+} -+ -+enum CRStatus -+cr_token_set_semicolon (CRToken * a_this) -+{ -+ g_return_val_if_fail (a_this, CR_BAD_PARAM_ERROR); -+ -+ cr_token_clear (a_this); -+ -+ a_this->type = SEMICOLON_TK; -+ -+ return CR_OK; -+} -+ -+enum CRStatus -+cr_token_set_cbo (CRToken * a_this) -+{ -+ g_return_val_if_fail (a_this, CR_BAD_PARAM_ERROR); -+ -+ cr_token_clear (a_this); -+ -+ a_this->type = CBO_TK; -+ -+ return CR_OK; -+} -+ -+enum CRStatus -+cr_token_set_cbc (CRToken * a_this) -+{ -+ g_return_val_if_fail (a_this, CR_BAD_PARAM_ERROR); -+ -+ cr_token_clear (a_this); -+ -+ a_this->type = CBC_TK; -+ -+ return CR_OK; -+} -+ -+enum CRStatus -+cr_token_set_po (CRToken * a_this) -+{ -+ g_return_val_if_fail (a_this, CR_BAD_PARAM_ERROR); -+ -+ cr_token_clear (a_this); -+ -+ a_this->type = PO_TK; -+ -+ return CR_OK; -+} -+ -+enum CRStatus -+cr_token_set_pc (CRToken * a_this) -+{ -+ g_return_val_if_fail (a_this, CR_BAD_PARAM_ERROR); -+ -+ cr_token_clear (a_this); -+ -+ a_this->type = PC_TK; -+ -+ return CR_OK; -+} -+ -+enum CRStatus -+cr_token_set_bo (CRToken * a_this) -+{ -+ g_return_val_if_fail (a_this, CR_BAD_PARAM_ERROR); -+ -+ cr_token_clear (a_this); -+ -+ a_this->type = BO_TK; -+ -+ return CR_OK; -+} -+ -+enum CRStatus -+cr_token_set_bc (CRToken * a_this) -+{ -+ g_return_val_if_fail (a_this, CR_BAD_PARAM_ERROR); -+ -+ cr_token_clear (a_this); -+ -+ a_this->type = BC_TK; -+ -+ return CR_OK; -+} -+ -+/** -+ *The destructor of the #CRToken class. -+ *@param a_this the current instance of #CRToken. -+ */ -+void -+cr_token_destroy (CRToken * a_this) -+{ -+ g_return_if_fail (a_this); -+ -+ cr_token_clear (a_this); -+ -+ g_free (a_this); -+} -diff --git a/src/st/croco/cr-token.h b/src/st/croco/cr-token.h -new file mode 100644 -index 000000000..f1257b7a8 ---- /dev/null -+++ b/src/st/croco/cr-token.h -@@ -0,0 +1,212 @@ -+/* -*- Mode: C; indent-tabs-mode:nil; c-basic-offset: 8-*- */ -+ -+/* -+ * This file is part of The Croco Library -+ * -+ * 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 -+ * See COPYRIGHTS file for copyright information. -+ */ -+ -+#ifndef __CR_TOKEN_H__ -+#define __CR_TOKEN_H__ -+ -+#include "cr-utils.h" -+#include "cr-input.h" -+#include "cr-num.h" -+#include "cr-rgb.h" -+#include "cr-string.h" -+#include "cr-parsing-location.h" -+ -+G_BEGIN_DECLS -+ -+enum CRTokenType -+{ -+ NO_TK, -+ S_TK, -+ CDO_TK, -+ CDC_TK, -+ INCLUDES_TK, -+ DASHMATCH_TK, -+ COMMENT_TK, -+ STRING_TK, -+ IDENT_TK, -+ HASH_TK, -+ IMPORT_SYM_TK, -+ PAGE_SYM_TK, -+ MEDIA_SYM_TK, -+ FONT_FACE_SYM_TK, -+ CHARSET_SYM_TK, -+ ATKEYWORD_TK, -+ IMPORTANT_SYM_TK, -+ EMS_TK, -+ EXS_TK, -+ LENGTH_TK, -+ ANGLE_TK, -+ TIME_TK, -+ FREQ_TK, -+ DIMEN_TK, -+ PERCENTAGE_TK, -+ NUMBER_TK, -+ RGB_TK, -+ URI_TK, -+ FUNCTION_TK, -+ UNICODERANGE_TK, -+ SEMICOLON_TK, -+ CBO_TK, /*opening curly bracket*/ -+ CBC_TK, /*closing curly bracket*/ -+ PO_TK, /*opening parenthesis*/ -+ PC_TK, /*closing parenthesis*/ -+ BO_TK, /*opening bracket*/ -+ BC_TK, /*closing bracket*/ -+ DELIM_TK -+} ; -+ -+enum CRTokenExtraType -+{ -+ NO_ET = 0, -+ LENGTH_PX_ET, -+ LENGTH_CM_ET, -+ LENGTH_MM_ET, -+ LENGTH_IN_ET, -+ LENGTH_PT_ET, -+ LENGTH_PC_ET, -+ ANGLE_DEG_ET, -+ ANGLE_RAD_ET, -+ ANGLE_GRAD_ET, -+ TIME_MS_ET, -+ TIME_S_ET, -+ FREQ_HZ_ET, -+ FREQ_KHZ_ET -+} ; -+ -+typedef struct _CRToken CRToken ; -+ -+/** -+ *This class abstracts a css2 token. -+ */ -+struct _CRToken -+{ -+ enum CRTokenType type ; -+ enum CRTokenExtraType extra_type ; -+ CRInputPos pos ; -+ -+ union -+ { -+ CRString *str ; -+ CRRgb *rgb ; -+ CRNum *num ; -+ guint32 unichar ; -+ } u ; -+ -+ CRString * dimen ; -+ CRParsingLocation location ; -+} ; -+ -+CRToken* cr_token_new (void) ; -+ -+enum CRStatus cr_token_set_s (CRToken *a_this) ; -+ -+enum CRStatus cr_token_set_cdo (CRToken *a_this) ; -+ -+enum CRStatus cr_token_set_cdc (CRToken *a_this) ; -+ -+enum CRStatus cr_token_set_includes (CRToken *a_this) ; -+ -+enum CRStatus cr_token_set_dashmatch (CRToken *a_this) ; -+ -+enum CRStatus cr_token_set_comment (CRToken *a_this, CRString *a_str) ; -+ -+enum CRStatus cr_token_set_string (CRToken *a_this, CRString *a_str) ; -+ -+enum CRStatus cr_token_set_ident (CRToken *a_this, CRString * a_ident) ; -+ -+enum CRStatus cr_token_set_hash (CRToken *a_this, CRString *a_hash) ; -+ -+enum CRStatus cr_token_set_rgb (CRToken *a_this, CRRgb *a_rgb) ; -+ -+enum CRStatus cr_token_set_import_sym (CRToken *a_this) ; -+ -+enum CRStatus cr_token_set_page_sym (CRToken *a_this) ; -+ -+enum CRStatus cr_token_set_media_sym (CRToken *a_this) ; -+ -+enum CRStatus cr_token_set_font_face_sym (CRToken *a_this) ; -+ -+enum CRStatus cr_token_set_charset_sym (CRToken *a_this) ; -+ -+enum CRStatus cr_token_set_atkeyword (CRToken *a_this, CRString *a_atname) ; -+ -+enum CRStatus cr_token_set_important_sym (CRToken *a_this) ; -+ -+enum CRStatus cr_token_set_ems (CRToken *a_this, CRNum *a_num) ; -+ -+enum CRStatus cr_token_set_exs (CRToken *a_this, CRNum *a_num) ; -+ -+enum CRStatus cr_token_set_length (CRToken *a_this, CRNum *a_num, -+ enum CRTokenExtraType a_et) ; -+ -+enum CRStatus cr_token_set_angle (CRToken *a_this, CRNum *a_num, -+ enum CRTokenExtraType a_et) ; -+ -+enum CRStatus cr_token_set_time (CRToken *a_this, CRNum *a_num, -+ enum CRTokenExtraType a_et) ; -+ -+enum CRStatus cr_token_set_freq (CRToken *a_this, CRNum *a_num, -+ enum CRTokenExtraType a_et) ; -+ -+enum CRStatus cr_token_set_dimen (CRToken *a_this, CRNum *a_num, -+ CRString *a_dim) ; -+ -+enum CRStatus cr_token_set_percentage (CRToken *a_this, CRNum *a_num) ; -+ -+enum CRStatus cr_token_set_number (CRToken *a_this, CRNum *a_num) ; -+ -+enum CRStatus cr_token_set_uri (CRToken *a_this, CRString *a_uri) ; -+ -+enum CRStatus cr_token_set_function (CRToken *a_this, -+ CRString *a_fun_name) ; -+ -+enum CRStatus cr_token_set_bc (CRToken *a_this) ; -+ -+enum CRStatus cr_token_set_bo (CRToken *a_this) ; -+ -+enum CRStatus cr_token_set_po (CRToken *a_this) ; -+ -+enum CRStatus cr_token_set_pc (CRToken *a_this) ; -+ -+enum CRStatus cr_token_set_cbc (CRToken *a_this) ; -+ -+enum CRStatus cr_token_set_cbo (CRToken *a_this) ; -+ -+enum CRStatus cr_token_set_semicolon (CRToken *a_this) ; -+ -+enum CRStatus cr_token_set_delim (CRToken *a_this, guint32 a_char) ; -+ -+ -+/* -+ enum CRStatus -+ cr_token_set_unicoderange (CRToken *a_this, -+ CRUnicodeRange *a_range) ; -+*/ -+ -+void -+cr_token_destroy (CRToken *a_this) ; -+ -+ -+G_END_DECLS -+ -+#endif /*__CR_TOKEN_H__*/ -diff --git a/src/st/croco/cr-utils.c b/src/st/croco/cr-utils.c -new file mode 100644 -index 000000000..2420cec7c ---- /dev/null -+++ b/src/st/croco/cr-utils.c -@@ -0,0 +1,1330 @@ -+/* -*- Mode: C; indent-tabs-mode: nil; c-basic-offset: 8 -*- */ -+ -+/* -+ * This file is part of The Croco Library -+ * -+ * 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 -+ * See COPYRIGHTS file for copyright information. -+ */ -+ -+#include "cr-utils.h" -+#include "cr-string.h" -+ -+/** -+ *@file: -+ *Some misc utility functions used -+ *in the libcroco. -+ *Note that troughout this file I will -+ *refer to the CSS SPECIFICATIONS DOCUMENTATION -+ *written by the w3c guys. You can find that document -+ *at http://www.w3.org/TR/REC-CSS2/ . -+ */ -+ -+/**************************** -+ *Encoding transformations and -+ *encoding helpers -+ ****************************/ -+ -+/* -+ *Here is the correspondance between the ucs-4 charactere codes -+ *and there matching utf-8 encoding pattern as dscribed by RFC 2279: -+ * -+ *UCS-4 range (hex.) UTF-8 octet sequence (binary) -+ *------------------ ----------------------------- -+ *0000 0000-0000 007F 0xxxxxxx -+ *0000 0080-0000 07FF 110xxxxx 10xxxxxx -+ *0000 0800-0000 FFFF 1110xxxx 10xxxxxx 10xxxxxx -+ *0001 0000-001F FFFF 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx -+ *0020 0000-03FF FFFF 111110xx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx -+ *0400 0000-7FFF FFFF 1111110x 10xxxxxx ... 10xxxxxx -+ */ -+ -+/** -+ *Given an utf8 string buffer, calculates -+ *the length of this string if it was encoded -+ *in ucs4. -+ *@param a_in_start a pointer to the begining of -+ *the input utf8 string. -+ *@param a_in_end a pointre to the end of the input -+ *utf8 string (points to the last byte of the buffer) -+ *@param a_len out parameter the calculated length. -+ *@return CR_OK upon succesfull completion, an error code -+ *otherwise. -+ */ -+enum CRStatus -+cr_utils_utf8_str_len_as_ucs4 (const guchar * a_in_start, -+ const guchar * a_in_end, gulong * a_len) -+{ -+ guchar *byte_ptr = NULL; -+ gint len = 0; -+ -+ /* -+ *to store the final decoded -+ *unicode char -+ */ -+ guint c = 0; -+ -+ g_return_val_if_fail (a_in_start && a_in_end && a_len, -+ CR_BAD_PARAM_ERROR); -+ *a_len = 0; -+ -+ for (byte_ptr = (guchar *) a_in_start; -+ byte_ptr <= a_in_end; byte_ptr++) { -+ gint nb_bytes_2_decode = 0; -+ -+ if (*byte_ptr <= 0x7F) { -+ /* -+ *7 bits long char -+ *encoded over 1 byte: -+ * 0xxx xxxx -+ */ -+ c = *byte_ptr; -+ nb_bytes_2_decode = 1; -+ -+ } else if ((*byte_ptr & 0xE0) == 0xC0) { -+ /* -+ *up to 11 bits long char. -+ *encoded over 2 bytes: -+ *110x xxxx 10xx xxxx -+ */ -+ c = *byte_ptr & 0x1F; -+ nb_bytes_2_decode = 2; -+ -+ } else if ((*byte_ptr & 0xF0) == 0xE0) { -+ /* -+ *up to 16 bit long char -+ *encoded over 3 bytes: -+ *1110 xxxx 10xx xxxx 10xx xxxx -+ */ -+ c = *byte_ptr & 0x0F; -+ nb_bytes_2_decode = 3; -+ -+ } else if ((*byte_ptr & 0xF8) == 0xF0) { -+ /* -+ *up to 21 bits long char -+ *encoded over 4 bytes: -+ *1111 0xxx 10xx xxxx 10xx xxxx 10xx xxxx -+ */ -+ c = *byte_ptr & 0x7; -+ nb_bytes_2_decode = 4; -+ -+ } else if ((*byte_ptr & 0xFC) == 0xF8) { -+ /* -+ *up to 26 bits long char -+ *encoded over 5 bytes. -+ *1111 10xx 10xx xxxx 10xx xxxx -+ *10xx xxxx 10xx xxxx -+ */ -+ c = *byte_ptr & 3; -+ nb_bytes_2_decode = 5; -+ -+ } else if ((*byte_ptr & 0xFE) == 0xFC) { -+ /* -+ *up to 31 bits long char -+ *encoded over 6 bytes: -+ *1111 110x 10xx xxxx 10xx xxxx -+ *10xx xxxx 10xx xxxx 10xx xxxx -+ */ -+ c = *byte_ptr & 1; -+ nb_bytes_2_decode = 6; -+ -+ } else { -+ /* -+ *BAD ENCODING -+ */ -+ return CR_ENCODING_ERROR; -+ } -+ -+ /* -+ *Go and decode the remaining byte(s) -+ *(if any) to get the current character. -+ */ -+ for (; nb_bytes_2_decode > 1; nb_bytes_2_decode--) { -+ /*decode the next byte */ -+ byte_ptr++; -+ -+ /*byte pattern must be: 10xx xxxx */ -+ if ((*byte_ptr & 0xC0) != 0x80) { -+ return CR_ENCODING_ERROR; -+ } -+ -+ c = (c << 6) | (*byte_ptr & 0x3F); -+ } -+ -+ len++; -+ } -+ -+ *a_len = len; -+ -+ return CR_OK; -+} -+ -+/** -+ *Given an ucs4 string, this function -+ *returns the size (in bytes) this string -+ *would have occupied if it was encoded in utf-8. -+ *@param a_in_start a pointer to the beginning of the input -+ *buffer. -+ *@param a_in_end a pointer to the end of the input buffer. -+ *@param a_len out parameter. The computed length. -+ *@return CR_OK upon successfull completion, an error code otherwise. -+ */ -+enum CRStatus -+cr_utils_ucs4_str_len_as_utf8 (const guint32 * a_in_start, -+ const guint32 * a_in_end, gulong * a_len) -+{ -+ gint len = 0; -+ guint32 *char_ptr = NULL; -+ -+ g_return_val_if_fail (a_in_start && a_in_end && a_len, -+ CR_BAD_PARAM_ERROR); -+ -+ for (char_ptr = (guint32 *) a_in_start; -+ char_ptr <= a_in_end; char_ptr++) { -+ if (*char_ptr <= 0x7F) { -+ /*the utf-8 char would take 1 byte */ -+ len += 1; -+ } else if (*char_ptr <= 0x7FF) { -+ /*the utf-8 char would take 2 bytes */ -+ len += 2; -+ } else if (*char_ptr <= 0xFFFF) { -+ len += 3; -+ } else if (*char_ptr <= 0x1FFFFF) { -+ len += 4; -+ } else if (*char_ptr <= 0x3FFFFFF) { -+ len += 5; -+ } else if (*char_ptr <= 0x7FFFFFFF) { -+ len += 6; -+ } -+ } -+ -+ *a_len = len; -+ return CR_OK; -+} -+ -+/** -+ *Given an ucsA string, this function -+ *returns the size (in bytes) this string -+ *would have occupied if it was encoded in utf-8. -+ *@param a_in_start a pointer to the beginning of the input -+ *buffer. -+ *@param a_in_end a pointer to the end of the input buffer. -+ *@param a_len out parameter. The computed length. -+ *@return CR_OK upon successfull completion, an error code otherwise. -+ */ -+enum CRStatus -+cr_utils_ucs1_str_len_as_utf8 (const guchar * a_in_start, -+ const guchar * a_in_end, gulong * a_len) -+{ -+ gint len = 0; -+ guchar *char_ptr = NULL; -+ -+ g_return_val_if_fail (a_in_start && a_in_end && a_len, -+ CR_BAD_PARAM_ERROR); -+ -+ for (char_ptr = (guchar *) a_in_start; -+ char_ptr <= a_in_end; char_ptr++) { -+ if (*char_ptr <= 0x7F) { -+ /*the utf-8 char would take 1 byte */ -+ len += 1; -+ } else { -+ /*the utf-8 char would take 2 bytes */ -+ len += 2; -+ } -+ } -+ -+ *a_len = len; -+ return CR_OK; -+} -+ -+/** -+ *Converts an utf8 buffer into an ucs4 buffer. -+ * -+ *@param a_in the input utf8 buffer to convert. -+ *@param a_in_len in/out parameter. The size of the -+ *input buffer to convert. After return, this parameter contains -+ *the actual number of bytes consumed. -+ *@param a_out the output converted ucs4 buffer. Must be allocated by -+ *the caller. -+ *@param a_out_len in/out parameter. The size of the output buffer. -+ *If this size is actually smaller than the real needed size, the function -+ *just converts what it can and returns a success status. After return, -+ *this param points to the actual number of characters decoded. -+ *@return CR_OK upon successfull completion, an error code otherwise. -+ */ -+enum CRStatus -+cr_utils_utf8_to_ucs4 (const guchar * a_in, -+ gulong * a_in_len, guint32 * a_out, gulong * a_out_len) -+{ -+ gulong in_len = 0, -+ out_len = 0, -+ in_index = 0, -+ out_index = 0; -+ enum CRStatus status = CR_OK; -+ -+ /* -+ *to store the final decoded -+ *unicode char -+ */ -+ guint c = 0; -+ -+ g_return_val_if_fail (a_in && a_in_len -+ && a_out && a_out_len, CR_BAD_PARAM_ERROR); -+ -+ if (*a_in_len < 1) { -+ status = CR_OK; -+ goto end; -+ } -+ -+ in_len = *a_in_len; -+ out_len = *a_out_len; -+ -+ for (in_index = 0, out_index = 0; -+ (in_index < in_len) && (out_index < out_len); -+ in_index++, out_index++) { -+ gint nb_bytes_2_decode = 0; -+ -+ if (a_in[in_index] <= 0x7F) { -+ /* -+ *7 bits long char -+ *encoded over 1 byte: -+ * 0xxx xxxx -+ */ -+ c = a_in[in_index]; -+ nb_bytes_2_decode = 1; -+ -+ } else if ((a_in[in_index] & 0xE0) == 0xC0) { -+ /* -+ *up to 11 bits long char. -+ *encoded over 2 bytes: -+ *110x xxxx 10xx xxxx -+ */ -+ c = a_in[in_index] & 0x1F; -+ nb_bytes_2_decode = 2; -+ -+ } else if ((a_in[in_index] & 0xF0) == 0xE0) { -+ /* -+ *up to 16 bit long char -+ *encoded over 3 bytes: -+ *1110 xxxx 10xx xxxx 10xx xxxx -+ */ -+ c = a_in[in_index] & 0x0F; -+ nb_bytes_2_decode = 3; -+ -+ } else if ((a_in[in_index] & 0xF8) == 0xF0) { -+ /* -+ *up to 21 bits long char -+ *encoded over 4 bytes: -+ *1111 0xxx 10xx xxxx 10xx xxxx 10xx xxxx -+ */ -+ c = a_in[in_index] & 0x7; -+ nb_bytes_2_decode = 4; -+ -+ } else if ((a_in[in_index] & 0xFC) == 0xF8) { -+ /* -+ *up to 26 bits long char -+ *encoded over 5 bytes. -+ *1111 10xx 10xx xxxx 10xx xxxx -+ *10xx xxxx 10xx xxxx -+ */ -+ c = a_in[in_index] & 3; -+ nb_bytes_2_decode = 5; -+ -+ } else if ((a_in[in_index] & 0xFE) == 0xFC) { -+ /* -+ *up to 31 bits long char -+ *encoded over 6 bytes: -+ *1111 110x 10xx xxxx 10xx xxxx -+ *10xx xxxx 10xx xxxx 10xx xxxx -+ */ -+ c = a_in[in_index] & 1; -+ nb_bytes_2_decode = 6; -+ -+ } else { -+ /*BAD ENCODING */ -+ goto end; -+ } -+ -+ /* -+ *Go and decode the remaining byte(s) -+ *(if any) to get the current character. -+ */ -+ for (; nb_bytes_2_decode > 1; nb_bytes_2_decode--) { -+ /*decode the next byte */ -+ in_index++; -+ -+ /*byte pattern must be: 10xx xxxx */ -+ if ((a_in[in_index] & 0xC0) != 0x80) { -+ goto end; -+ } -+ -+ c = (c << 6) | (a_in[in_index] & 0x3F); -+ } -+ -+ /* -+ *The decoded ucs4 char is now -+ *in c. -+ */ -+ -+ /************************ -+ *Some security tests -+ ***********************/ -+ -+ /*be sure c is a char */ -+ if (c == 0xFFFF || c == 0xFFFE) -+ goto end; -+ -+ /*be sure c is inferior to the max ucs4 char value */ -+ if (c > 0x10FFFF) -+ goto end; -+ -+ /* -+ *c must be less than UTF16 "lower surrogate begin" -+ *or higher than UTF16 "High surrogate end" -+ */ -+ if (c >= 0xD800 && c <= 0xDFFF) -+ goto end; -+ -+ /*Avoid characters that equals zero */ -+ if (c == 0) -+ goto end; -+ -+ a_out[out_index] = c; -+ } -+ -+ end: -+ *a_out_len = out_index + 1; -+ *a_in_len = in_index + 1; -+ -+ return status; -+} -+ -+/** -+ *Reads a character from an utf8 buffer. -+ *Actually decode the next character code (unicode character code) -+ *and returns it. -+ *@param a_in the starting address of the utf8 buffer. -+ *@param a_in_len the length of the utf8 buffer. -+ *@param a_out output parameter. The resulting read char. -+ *@param a_consumed the number of the bytes consumed to -+ *decode the returned character code. -+ *@return CR_OK upon successfull completion, an error code otherwise. -+ */ -+enum CRStatus -+cr_utils_read_char_from_utf8_buf (const guchar * a_in, -+ gulong a_in_len, -+ guint32 * a_out, gulong * a_consumed) -+{ -+ gulong in_index = 0, -+ nb_bytes_2_decode = 0; -+ enum CRStatus status = CR_OK; -+ -+ /* -+ *to store the final decoded -+ *unicode char -+ */ -+ guint32 c = 0; -+ -+ g_return_val_if_fail (a_in && a_out && a_out -+ && a_consumed, CR_BAD_PARAM_ERROR); -+ -+ if (a_in_len < 1) { -+ status = CR_OK; -+ goto end; -+ } -+ -+ if (*a_in <= 0x7F) { -+ /* -+ *7 bits long char -+ *encoded over 1 byte: -+ * 0xxx xxxx -+ */ -+ c = *a_in; -+ nb_bytes_2_decode = 1; -+ -+ } else if ((*a_in & 0xE0) == 0xC0) { -+ /* -+ *up to 11 bits long char. -+ *encoded over 2 bytes: -+ *110x xxxx 10xx xxxx -+ */ -+ c = *a_in & 0x1F; -+ nb_bytes_2_decode = 2; -+ -+ } else if ((*a_in & 0xF0) == 0xE0) { -+ /* -+ *up to 16 bit long char -+ *encoded over 3 bytes: -+ *1110 xxxx 10xx xxxx 10xx xxxx -+ */ -+ c = *a_in & 0x0F; -+ nb_bytes_2_decode = 3; -+ -+ } else if ((*a_in & 0xF8) == 0xF0) { -+ /* -+ *up to 21 bits long char -+ *encoded over 4 bytes: -+ *1111 0xxx 10xx xxxx 10xx xxxx 10xx xxxx -+ */ -+ c = *a_in & 0x7; -+ nb_bytes_2_decode = 4; -+ -+ } else if ((*a_in & 0xFC) == 0xF8) { -+ /* -+ *up to 26 bits long char -+ *encoded over 5 bytes. -+ *1111 10xx 10xx xxxx 10xx xxxx -+ *10xx xxxx 10xx xxxx -+ */ -+ c = *a_in & 3; -+ nb_bytes_2_decode = 5; -+ -+ } else if ((*a_in & 0xFE) == 0xFC) { -+ /* -+ *up to 31 bits long char -+ *encoded over 6 bytes: -+ *1111 110x 10xx xxxx 10xx xxxx -+ *10xx xxxx 10xx xxxx 10xx xxxx -+ */ -+ c = *a_in & 1; -+ nb_bytes_2_decode = 6; -+ -+ } else { -+ /*BAD ENCODING */ -+ goto end; -+ } -+ -+ if (nb_bytes_2_decode > a_in_len) { -+ status = CR_END_OF_INPUT_ERROR; -+ goto end; -+ } -+ -+ /* -+ *Go and decode the remaining byte(s) -+ *(if any) to get the current character. -+ */ -+ for (in_index = 1; in_index < nb_bytes_2_decode; in_index++) { -+ /*byte pattern must be: 10xx xxxx */ -+ if ((a_in[in_index] & 0xC0) != 0x80) { -+ goto end; -+ } -+ -+ c = (c << 6) | (a_in[in_index] & 0x3F); -+ } -+ -+ /* -+ *The decoded ucs4 char is now -+ *in c. -+ */ -+ -+ /************************ -+ *Some security tests -+ ***********************/ -+ -+ /*be sure c is a char */ -+ if (c == 0xFFFF || c == 0xFFFE) -+ goto end; -+ -+ /*be sure c is inferior to the max ucs4 char value */ -+ if (c > 0x10FFFF) -+ goto end; -+ -+ /* -+ *c must be less than UTF16 "lower surrogate begin" -+ *or higher than UTF16 "High surrogate end" -+ */ -+ if (c >= 0xD800 && c <= 0xDFFF) -+ goto end; -+ -+ /*Avoid characters that equals zero */ -+ if (c == 0) -+ goto end; -+ -+ *a_out = c; -+ -+ end: -+ *a_consumed = nb_bytes_2_decode; -+ -+ return status; -+} -+ -+/** -+ * -+ */ -+enum CRStatus -+cr_utils_utf8_str_len_as_ucs1 (const guchar * a_in_start, -+ const guchar * a_in_end, gulong * a_len) -+{ -+ /* -+ *Note: this function can be made shorter -+ *but it considers all the cases of the utf8 encoding -+ *to ease further extensions ... -+ */ -+ -+ guchar *byte_ptr = NULL; -+ gint len = 0; -+ -+ /* -+ *to store the final decoded -+ *unicode char -+ */ -+ guint c = 0; -+ -+ g_return_val_if_fail (a_in_start && a_in_end && a_len, -+ CR_BAD_PARAM_ERROR); -+ *a_len = 0; -+ -+ for (byte_ptr = (guchar *) a_in_start; -+ byte_ptr <= a_in_end; byte_ptr++) { -+ gint nb_bytes_2_decode = 0; -+ -+ if (*byte_ptr <= 0x7F) { -+ /* -+ *7 bits long char -+ *encoded over 1 byte: -+ * 0xxx xxxx -+ */ -+ c = *byte_ptr; -+ nb_bytes_2_decode = 1; -+ -+ } else if ((*byte_ptr & 0xE0) == 0xC0) { -+ /* -+ *up to 11 bits long char. -+ *encoded over 2 bytes: -+ *110x xxxx 10xx xxxx -+ */ -+ c = *byte_ptr & 0x1F; -+ nb_bytes_2_decode = 2; -+ -+ } else if ((*byte_ptr & 0xF0) == 0xE0) { -+ /* -+ *up to 16 bit long char -+ *encoded over 3 bytes: -+ *1110 xxxx 10xx xxxx 10xx xxxx -+ */ -+ c = *byte_ptr & 0x0F; -+ nb_bytes_2_decode = 3; -+ -+ } else if ((*byte_ptr & 0xF8) == 0xF0) { -+ /* -+ *up to 21 bits long char -+ *encoded over 4 bytes: -+ *1111 0xxx 10xx xxxx 10xx xxxx 10xx xxxx -+ */ -+ c = *byte_ptr & 0x7; -+ nb_bytes_2_decode = 4; -+ -+ } else if ((*byte_ptr & 0xFC) == 0xF8) { -+ /* -+ *up to 26 bits long char -+ *encoded over 5 bytes. -+ *1111 10xx 10xx xxxx 10xx xxxx -+ *10xx xxxx 10xx xxxx -+ */ -+ c = *byte_ptr & 3; -+ nb_bytes_2_decode = 5; -+ -+ } else if ((*byte_ptr & 0xFE) == 0xFC) { -+ /* -+ *up to 31 bits long char -+ *encoded over 6 bytes: -+ *1111 110x 10xx xxxx 10xx xxxx -+ *10xx xxxx 10xx xxxx 10xx xxxx -+ */ -+ c = *byte_ptr & 1; -+ nb_bytes_2_decode = 6; -+ -+ } else { -+ /* -+ *BAD ENCODING -+ */ -+ return CR_ENCODING_ERROR; -+ } -+ -+ /* -+ *Go and decode the remaining byte(s) -+ *(if any) to get the current character. -+ */ -+ for (; nb_bytes_2_decode > 1; nb_bytes_2_decode--) { -+ /*decode the next byte */ -+ byte_ptr++; -+ -+ /*byte pattern must be: 10xx xxxx */ -+ if ((*byte_ptr & 0xC0) != 0x80) { -+ return CR_ENCODING_ERROR; -+ } -+ -+ c = (c << 6) | (*byte_ptr & 0x3F); -+ } -+ -+ /* -+ *The decoded ucs4 char is now -+ *in c. -+ */ -+ -+ if (c <= 0xFF) { /*Add other conditions to support -+ *other char sets (ucs2, ucs3, ucs4). -+ */ -+ len++; -+ } else { -+ /*the char is too long to fit -+ *into the supposed charset len. -+ */ -+ return CR_ENCODING_ERROR; -+ } -+ } -+ -+ *a_len = len; -+ -+ return CR_OK; -+} -+ -+/** -+ *Converts an utf8 string into an ucs4 string. -+ *@param a_in the input string to convert. -+ *@param a_in_len in/out parameter. The length of the input -+ *string. After return, points to the actual number of bytes -+ *consumed. This can be usefull to debug the input stream in case -+ *of encoding error. -+ *@param a_out out parameter. Points to the output string. It is allocated -+ *by this function and must be freed by the caller. -+ *@param a_out_len out parameter. The length of the output string. -+ *@return CR_OK upon successfull completion, an error code otherwise. -+ * -+ */ -+enum CRStatus -+cr_utils_utf8_str_to_ucs4 (const guchar * a_in, -+ gulong * a_in_len, -+ guint32 ** a_out, gulong * a_out_len) -+{ -+ enum CRStatus status = CR_OK; -+ -+ g_return_val_if_fail (a_in && a_in_len -+ && a_out && a_out_len, CR_BAD_PARAM_ERROR); -+ -+ status = cr_utils_utf8_str_len_as_ucs4 (a_in, -+ &a_in[*a_in_len - 1], -+ a_out_len); -+ -+ g_return_val_if_fail (status == CR_OK, status); -+ -+ *a_out = g_malloc0 (*a_out_len * sizeof (guint32)); -+ -+ status = cr_utils_utf8_to_ucs4 (a_in, a_in_len, *a_out, a_out_len); -+ -+ return status; -+} -+ -+/** -+ *Converts an ucs4 buffer into an utf8 buffer. -+ * -+ *@param a_in the input ucs4 buffer to convert. -+ *@param a_in_len in/out parameter. The size of the -+ *input buffer to convert. After return, this parameter contains -+ *the actual number of characters consumed. -+ *@param a_out the output converted utf8 buffer. Must be allocated by -+ *the caller. -+ *@param a_out_len in/out parameter. The size of the output buffer. -+ *If this size is actually smaller than the real needed size, the function -+ *just converts what it can and returns a success status. After return, -+ *this param points to the actual number of bytes in the buffer. -+ *@return CR_OK upon successfull completion, an error code otherwise. -+ */ -+enum CRStatus -+cr_utils_ucs4_to_utf8 (const guint32 * a_in, -+ gulong * a_in_len, guchar * a_out, gulong * a_out_len) -+{ -+ gulong in_len = 0, -+ in_index = 0, -+ out_index = 0; -+ enum CRStatus status = CR_OK; -+ -+ g_return_val_if_fail (a_in && a_in_len && a_out && a_out_len, -+ CR_BAD_PARAM_ERROR); -+ -+ if (*a_in_len < 1) { -+ status = CR_OK; -+ goto end; -+ } -+ -+ in_len = *a_in_len; -+ -+ for (in_index = 0; in_index < in_len; in_index++) { -+ /* -+ *FIXME: return whenever we encounter forbidden char values. -+ */ -+ -+ if (a_in[in_index] <= 0x7F) { -+ a_out[out_index] = a_in[in_index]; -+ out_index++; -+ } else if (a_in[in_index] <= 0x7FF) { -+ a_out[out_index] = (0xC0 | (a_in[in_index] >> 6)); -+ a_out[out_index + 1] = -+ (0x80 | (a_in[in_index] & 0x3F)); -+ out_index += 2; -+ } else if (a_in[in_index] <= 0xFFFF) { -+ a_out[out_index] = (0xE0 | (a_in[in_index] >> 12)); -+ a_out[out_index + 1] = -+ (0x80 | ((a_in[in_index] >> 6) & 0x3F)); -+ a_out[out_index + 2] = -+ (0x80 | (a_in[in_index] & 0x3F)); -+ out_index += 3; -+ } else if (a_in[in_index] <= 0x1FFFFF) { -+ a_out[out_index] = (0xF0 | (a_in[in_index] >> 18)); -+ a_out[out_index + 1] -+ = (0x80 | ((a_in[in_index] >> 12) & 0x3F)); -+ a_out[out_index + 2] -+ = (0x80 | ((a_in[in_index] >> 6) & 0x3F)); -+ a_out[out_index + 3] -+ = (0x80 | (a_in[in_index] & 0x3F)); -+ out_index += 4; -+ } else if (a_in[in_index] <= 0x3FFFFFF) { -+ a_out[out_index] = (0xF8 | (a_in[in_index] >> 24)); -+ a_out[out_index + 1] = -+ (0x80 | (a_in[in_index] >> 18)); -+ a_out[out_index + 2] -+ = (0x80 | ((a_in[in_index] >> 12) & 0x3F)); -+ a_out[out_index + 3] -+ = (0x80 | ((a_in[in_index] >> 6) & 0x3F)); -+ a_out[out_index + 4] -+ = (0x80 | (a_in[in_index] & 0x3F)); -+ out_index += 5; -+ } else if (a_in[in_index] <= 0x7FFFFFFF) { -+ a_out[out_index] = (0xFC | (a_in[in_index] >> 30)); -+ a_out[out_index + 1] = -+ (0x80 | (a_in[in_index] >> 24)); -+ a_out[out_index + 2] -+ = (0x80 | ((a_in[in_index] >> 18) & 0x3F)); -+ a_out[out_index + 3] -+ = (0x80 | ((a_in[in_index] >> 12) & 0x3F)); -+ a_out[out_index + 4] -+ = (0x80 | ((a_in[in_index] >> 6) & 0x3F)); -+ a_out[out_index + 4] -+ = (0x80 | (a_in[in_index] & 0x3F)); -+ out_index += 6; -+ } else { -+ status = CR_ENCODING_ERROR; -+ goto end; -+ } -+ } /*end for */ -+ -+ end: -+ *a_in_len = in_index + 1; -+ *a_out_len = out_index + 1; -+ -+ return status; -+} -+ -+/** -+ *Converts an ucs4 string into an utf8 string. -+ *@param a_in the input string to convert. -+ *@param a_in_len in/out parameter. The length of the input -+ *string. After return, points to the actual number of characters -+ *consumed. This can be usefull to debug the input string in case -+ *of encoding error. -+ *@param a_out out parameter. Points to the output string. It is allocated -+ *by this function and must be freed by the caller. -+ *@param a_out_len out parameter. The length (in bytes) of the output string. -+ *@return CR_OK upon successfull completion, an error code otherwise. -+ */ -+enum CRStatus -+cr_utils_ucs4_str_to_utf8 (const guint32 * a_in, -+ gulong * a_in_len, -+ guchar ** a_out, gulong * a_out_len) -+{ -+ enum CRStatus status = CR_OK; -+ -+ g_return_val_if_fail (a_in && a_in_len && a_out -+ && a_out_len, CR_BAD_PARAM_ERROR); -+ -+ status = cr_utils_ucs4_str_len_as_utf8 (a_in, -+ &a_in[*a_out_len - 1], -+ a_out_len); -+ -+ g_return_val_if_fail (status == CR_OK, status); -+ -+ status = cr_utils_ucs4_to_utf8 (a_in, a_in_len, *a_out, a_out_len); -+ -+ return status; -+} -+ -+/** -+ *Converts an ucs1 buffer into an utf8 buffer. -+ *The caller must know the size of the resulting buffer and -+ *allocate it prior to calling this function. -+ * -+ *@param a_in the input ucs1 buffer. -+ * -+ *@param a_in_len in/out parameter. The length of the input buffer. -+ *After return, points to the number of bytes actually consumed even -+ *in case of encoding error. -+ * -+ *@param a_out out parameter. The output utf8 converted buffer. -+ * -+ *@param a_out_len in/out parameter. The size of the output buffer. -+ *If the output buffer size is shorter than the actual needed size, -+ *this function just convert what it can. -+ * -+ *@return CR_OK upon successfull completion, an error code otherwise. -+ * -+ */ -+enum CRStatus -+cr_utils_ucs1_to_utf8 (const guchar * a_in, -+ gulong * a_in_len, guchar * a_out, gulong * a_out_len) -+{ -+ gulong out_index = 0, -+ in_index = 0, -+ in_len = 0, -+ out_len = 0; -+ enum CRStatus status = CR_OK; -+ -+ g_return_val_if_fail (a_in && a_in_len -+ && a_out_len, -+ CR_BAD_PARAM_ERROR); -+ -+ if (*a_in_len == 0) { -+ *a_out_len = 0 ; -+ return status; -+ } -+ g_return_val_if_fail (a_out, CR_BAD_PARAM_ERROR) ; -+ -+ in_len = *a_in_len; -+ out_len = *a_out_len; -+ -+ for (in_index = 0, out_index = 0; -+ (in_index < in_len) && (out_index < out_len); in_index++) { -+ /* -+ *FIXME: return whenever we encounter forbidden char values. -+ */ -+ -+ if (a_in[in_index] <= 0x7F) { -+ a_out[out_index] = a_in[in_index]; -+ out_index++; -+ } else { -+ a_out[out_index] = (0xC0 | (a_in[in_index] >> 6)); -+ a_out[out_index + 1] = -+ (0x80 | (a_in[in_index] & 0x3F)); -+ out_index += 2; -+ } -+ } /*end for */ -+ -+ *a_in_len = in_index; -+ *a_out_len = out_index; -+ -+ return status; -+} -+ -+/** -+ *Converts an ucs1 string into an utf8 string. -+ *@param a_in_start the beginning of the input string to convert. -+ *@param a_in_end the end of the input string to convert. -+ *@param a_out out parameter. The converted string. -+ *@param a_out out parameter. The length of the converted string. -+ *@return CR_OK upon successfull completion, an error code otherwise. -+ * -+ */ -+enum CRStatus -+cr_utils_ucs1_str_to_utf8 (const guchar * a_in, -+ gulong * a_in_len, -+ guchar ** a_out, gulong * a_out_len) -+{ -+ gulong out_len = 0; -+ enum CRStatus status = CR_OK; -+ -+ g_return_val_if_fail (a_in && a_in_len && a_out -+ && a_out_len, CR_BAD_PARAM_ERROR); -+ -+ if (*a_in_len < 1) { -+ *a_out_len = 0; -+ *a_out = NULL; -+ return CR_OK; -+ } -+ -+ status = cr_utils_ucs1_str_len_as_utf8 (a_in, &a_in[*a_in_len - 1], -+ &out_len); -+ -+ g_return_val_if_fail (status == CR_OK, status); -+ -+ *a_out = g_malloc0 (out_len); -+ -+ status = cr_utils_ucs1_to_utf8 (a_in, a_in_len, *a_out, &out_len); -+ -+ *a_out_len = out_len; -+ -+ return status; -+} -+ -+/** -+ *Converts an utf8 buffer into an ucs1 buffer. -+ *The caller must know the size of the resulting -+ *converted buffer, and allocated it prior to calling this -+ *function. -+ * -+ *@param a_in the input utf8 buffer to convert. -+ * -+ *@param a_in_len in/out parameter. The size of the input utf8 buffer. -+ *After return, points to the number of bytes consumed -+ *by the function even in case of encoding error. -+ * -+ *@param a_out out parameter. Points to the resulting buffer. -+ *Must be allocated by the caller. If the size of a_out is shorter -+ *than its required size, this function converts what it can and return -+ *a successfull status. -+ * -+ *@param a_out_len in/out parameter. The size of the output buffer. -+ *After return, points to the number of bytes consumed even in case of -+ *encoding error. -+ * -+ *@return CR_OK upon successfull completion, an error code otherwise. -+ */ -+enum CRStatus -+cr_utils_utf8_to_ucs1 (const guchar * a_in, -+ gulong * a_in_len, guchar * a_out, gulong * a_out_len) -+{ -+ gulong in_index = 0, -+ out_index = 0, -+ in_len = 0, -+ out_len = 0; -+ enum CRStatus status = CR_OK; -+ -+ /* -+ *to store the final decoded -+ *unicode char -+ */ -+ guint32 c = 0; -+ -+ g_return_val_if_fail (a_in && a_in_len -+ && a_out && a_out_len, CR_BAD_PARAM_ERROR); -+ -+ if (*a_in_len < 1) { -+ goto end; -+ } -+ -+ in_len = *a_in_len; -+ out_len = *a_out_len; -+ -+ for (in_index = 0, out_index = 0; -+ (in_index < in_len) && (out_index < out_len); -+ in_index++, out_index++) { -+ gint nb_bytes_2_decode = 0; -+ -+ if (a_in[in_index] <= 0x7F) { -+ /* -+ *7 bits long char -+ *encoded over 1 byte: -+ * 0xxx xxxx -+ */ -+ c = a_in[in_index]; -+ nb_bytes_2_decode = 1; -+ -+ } else if ((a_in[in_index] & 0xE0) == 0xC0) { -+ /* -+ *up to 11 bits long char. -+ *encoded over 2 bytes: -+ *110x xxxx 10xx xxxx -+ */ -+ c = a_in[in_index] & 0x1F; -+ nb_bytes_2_decode = 2; -+ -+ } else if ((a_in[in_index] & 0xF0) == 0xE0) { -+ /* -+ *up to 16 bit long char -+ *encoded over 3 bytes: -+ *1110 xxxx 10xx xxxx 10xx xxxx -+ */ -+ c = a_in[in_index] & 0x0F; -+ nb_bytes_2_decode = 3; -+ -+ } else if ((a_in[in_index] & 0xF8) == 0xF0) { -+ /* -+ *up to 21 bits long char -+ *encoded over 4 bytes: -+ *1111 0xxx 10xx xxxx 10xx xxxx 10xx xxxx -+ */ -+ c = a_in[in_index] & 0x7; -+ nb_bytes_2_decode = 4; -+ -+ } else if ((a_in[in_index] & 0xFC) == 0xF8) { -+ /* -+ *up to 26 bits long char -+ *encoded over 5 bytes. -+ *1111 10xx 10xx xxxx 10xx xxxx -+ *10xx xxxx 10xx xxxx -+ */ -+ c = a_in[in_index] & 3; -+ nb_bytes_2_decode = 5; -+ -+ } else if ((a_in[in_index] & 0xFE) == 0xFC) { -+ /* -+ *up to 31 bits long char -+ *encoded over 6 bytes: -+ *1111 110x 10xx xxxx 10xx xxxx -+ *10xx xxxx 10xx xxxx 10xx xxxx -+ */ -+ c = a_in[in_index] & 1; -+ nb_bytes_2_decode = 6; -+ -+ } else { -+ /*BAD ENCODING */ -+ status = CR_ENCODING_ERROR; -+ goto end; -+ } -+ -+ /* -+ *Go and decode the remaining byte(s) -+ *(if any) to get the current character. -+ */ -+ if (in_index + nb_bytes_2_decode - 1 >= in_len) { -+ goto end; -+ } -+ -+ for (; nb_bytes_2_decode > 1; nb_bytes_2_decode--) { -+ /*decode the next byte */ -+ in_index++; -+ -+ /*byte pattern must be: 10xx xxxx */ -+ if ((a_in[in_index] & 0xC0) != 0x80) { -+ status = CR_ENCODING_ERROR; -+ goto end; -+ } -+ -+ c = (c << 6) | (a_in[in_index] & 0x3F); -+ } -+ -+ /* -+ *The decoded ucs4 char is now -+ *in c. -+ */ -+ -+ if (c > 0xFF) { -+ status = CR_ENCODING_ERROR; -+ goto end; -+ } -+ -+ a_out[out_index] = c; -+ } -+ -+ end: -+ *a_out_len = out_index; -+ *a_in_len = in_index; -+ -+ return status; -+} -+ -+/** -+ *Converts an utf8 buffer into an -+ *ucs1 buffer. -+ *@param a_in_start the start of the input buffer. -+ *@param a_in_end the end of the input buffer. -+ *@param a_out out parameter. The resulting converted ucs4 buffer. -+ *Must be freed by the caller. -+ *@param a_out_len out parameter. The length of the converted buffer. -+ *@return CR_OK upon successfull completion, an error code otherwise. -+ *Note that out parameters are valid if and only if this function -+ *returns CR_OK. -+ */ -+enum CRStatus -+cr_utils_utf8_str_to_ucs1 (const guchar * a_in, -+ gulong * a_in_len, -+ guchar ** a_out, gulong * a_out_len) -+{ -+ enum CRStatus status = CR_OK; -+ -+ g_return_val_if_fail (a_in && a_in_len -+ && a_out && a_out_len, CR_BAD_PARAM_ERROR); -+ -+ if (*a_in_len < 1) { -+ *a_out_len = 0; -+ *a_out = NULL; -+ return CR_OK; -+ } -+ -+ status = cr_utils_utf8_str_len_as_ucs4 (a_in, &a_in[*a_in_len - 1], -+ a_out_len); -+ -+ g_return_val_if_fail (status == CR_OK, status); -+ -+ *a_out = g_malloc0 (*a_out_len * sizeof (guint32)); -+ -+ status = cr_utils_utf8_to_ucs1 (a_in, a_in_len, *a_out, a_out_len); -+ return status; -+} -+ -+/***************************************** -+ *CSS basic types identification utilities -+ *****************************************/ -+ -+/** -+ *Returns TRUE if a_char is a white space as -+ *defined in the css spec in chap 4.1.1. -+ * -+ *white-space ::= ' '| \t|\r|\n|\f -+ * -+ *@param a_char the character to test. -+ *return TRUE if is a white space, false otherwise. -+ */ -+gboolean -+cr_utils_is_white_space (guint32 a_char) -+{ -+ switch (a_char) { -+ case ' ': -+ case '\t': -+ case '\r': -+ case '\n': -+ case '\f': -+ return TRUE; -+ break; -+ default: -+ return FALSE; -+ } -+} -+ -+/** -+ *Returns true if the character is a newline -+ *as defined in the css spec in the chap 4.1.1. -+ * -+ *nl ::= \n|\r\n|\r|\f -+ * -+ *@param a_char the character to test. -+ *@return TRUE if the character is a newline, FALSE otherwise. -+ */ -+gboolean -+cr_utils_is_newline (guint32 a_char) -+{ -+ switch (a_char) { -+ case '\n': -+ case '\r': -+ case '\f': -+ return TRUE; -+ break; -+ default: -+ return FALSE; -+ } -+} -+ -+/** -+ *returns TRUE if the char is part of an hexa num char: -+ *i.e hexa_char ::= [0-9A-F] -+ */ -+gboolean -+cr_utils_is_hexa_char (guint32 a_char) -+{ -+ if ((a_char >= '0' && a_char <= '9') -+ || (a_char >= 'A' && a_char <= 'F')) { -+ return TRUE; -+ } -+ return FALSE; -+} -+ -+/** -+ *Returns true if the character is a nonascii -+ *character (as defined in the css spec chap 4.1.1): -+ * -+ *nonascii ::= [^\0-\177] -+ * -+ *@param a_char the character to test. -+ *@return TRUE if the character is a nonascii char, -+ *FALSE otherwise. -+ */ -+gboolean -+cr_utils_is_nonascii (guint32 a_char) -+{ -+ if (a_char <= 177) { -+ return FALSE; -+ } -+ -+ return TRUE; -+} -+ -+/** -+ *Dumps a character a_nb times on a file. -+ *@param a_char the char to dump -+ *@param a_fp the destination file pointer -+ *@param a_nb the number of times a_char is to be dumped. -+ */ -+void -+cr_utils_dump_n_chars (guchar a_char, FILE * a_fp, glong a_nb) -+{ -+ glong i = 0; -+ -+ for (i = 0; i < a_nb; i++) { -+ fprintf (a_fp, "%c", a_char); -+ } -+} -+ -+void -+cr_utils_dump_n_chars2 (guchar a_char, GString * a_string, glong a_nb) -+{ -+ glong i = 0; -+ -+ g_return_if_fail (a_string); -+ -+ for (i = 0; i < a_nb; i++) { -+ g_string_append_printf (a_string, "%c", a_char); -+ } -+} -+ -+/** -+ *Duplicates a list of GString instances. -+ *@return the duplicated list of GString instances or NULL if -+ *something bad happened. -+ *@param a_list_of_strings the list of strings to be duplicated. -+ */ -+GList * -+cr_utils_dup_glist_of_string (GList const * a_list_of_strings) -+{ -+ GList const *cur = NULL; -+ GList *result = NULL; -+ -+ g_return_val_if_fail (a_list_of_strings, NULL); -+ -+ for (cur = a_list_of_strings; cur; cur = cur->next) { -+ GString *str = NULL; -+ -+ str = g_string_new_len (((GString *) cur->data)->str, -+ ((GString *) cur->data)->len); -+ if (str) -+ result = g_list_append (result, str); -+ } -+ -+ return result; -+} -+ -+/** -+ *Duplicate a GList where the GList::data is a CRString. -+ *@param a_list_of_strings the list to duplicate -+ *@return the duplicated list, or NULL if something bad -+ *happened. -+ */ -+GList * -+cr_utils_dup_glist_of_cr_string (GList const * a_list_of_strings) -+{ -+ GList const *cur = NULL; -+ GList *result = NULL; -+ -+ g_return_val_if_fail (a_list_of_strings, NULL); -+ -+ for (cur = a_list_of_strings; cur; cur = cur->next) { -+ CRString *str = NULL; -+ -+ str = cr_string_dup ((CRString const *) cur->data) ; -+ if (str) -+ result = g_list_append (result, str); -+ } -+ -+ return result; -+} -diff --git a/src/st/croco/cr-utils.h b/src/st/croco/cr-utils.h -new file mode 100644 -index 000000000..54aa24973 ---- /dev/null -+++ b/src/st/croco/cr-utils.h -@@ -0,0 +1,246 @@ -+/* -*- Mode: C; indent-tabs-mode: nil; c-basic-offset: 8 -*- */ -+ -+/* -+ * This file is part of The Croco Library -+ * -+ * 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 -+ * Look at file COPYRIGHTS for copyright information -+ */ -+ -+#ifndef __CR_DEFS_H__ -+#define __CR_DEFS_H__ -+ -+#include -+#include -+#include "libcroco-config.h" -+ -+G_BEGIN_DECLS -+ -+/** -+ *@file -+ *The Croco library basic types definitions -+ *And global definitions. -+ */ -+ -+/** -+ *The status type returned -+ *by the methods of the croco library. -+ */ -+enum CRStatus { -+ CR_OK, -+ CR_BAD_PARAM_ERROR, -+ CR_INSTANCIATION_FAILED_ERROR, -+ CR_UNKNOWN_TYPE_ERROR, -+ CR_UNKNOWN_PROP_ERROR, -+ CR_UNKNOWN_PROP_VAL_ERROR, -+ CR_UNEXPECTED_POSITION_SCHEME, -+ CR_START_OF_INPUT_ERROR, -+ CR_END_OF_INPUT_ERROR, -+ CR_OUTPUT_TOO_SHORT_ERROR, -+ CR_INPUT_TOO_SHORT_ERROR, -+ CR_OUT_OF_BOUNDS_ERROR, -+ CR_EMPTY_PARSER_INPUT_ERROR, -+ CR_ENCODING_ERROR, -+ CR_ENCODING_NOT_FOUND_ERROR, -+ CR_PARSING_ERROR, -+ CR_SYNTAX_ERROR, -+ CR_NO_ROOT_NODE_ERROR, -+ CR_NO_TOKEN, -+ CR_OUT_OF_MEMORY_ERROR, -+ CR_PSEUDO_CLASS_SEL_HANDLER_NOT_FOUND_ERROR, -+ CR_BAD_PSEUDO_CLASS_SEL_HANDLER_ERROR, -+ CR_ERROR, -+ CR_FILE_NOT_FOUND_ERROR, -+ CR_VALUE_NOT_FOUND_ERROR -+} ; -+ -+/** -+ *Values used by -+ *cr_input_seek_position() ; -+ */ -+enum CRSeekPos { -+ CR_SEEK_CUR, -+ CR_SEEK_BEGIN, -+ CR_SEEK_END -+} ; -+ -+/** -+ *Encoding values. -+ */ -+enum CREncoding -+{ -+ CR_UCS_4 = 1/*Must be not NULL*/, -+ CR_UCS_1, -+ CR_ISO_8859_1, -+ CR_ASCII, -+ CR_UTF_8, -+ CR_UTF_16, -+ CR_AUTO/*should be the last one*/ -+} ; -+ -+ -+ -+ -+#define CROCO_LOG_DOMAIN "LIBCROCO" -+ -+#ifdef __GNUC__ -+#define cr_utils_trace(a_log_level, a_msg) \ -+g_log (CROCO_LOG_DOMAIN, \ -+ G_LOG_LEVEL_CRITICAL, \ -+ "file %s: line %d (%s): %s\n", \ -+ __FILE__, \ -+ __LINE__, \ -+ __PRETTY_FUNCTION__, \ -+ a_msg) -+#else /*__GNUC__*/ -+ -+#define cr_utils_trace(a_log_level, a_msg) \ -+g_log (CROCO_LOG_DOMAIN, \ -+ G_LOG_LEVEL_CRITICAL, \ -+ "file %s: line %d: %s\n", \ -+ __FILE__, \ -+ __LINE__, \ -+ a_msg) -+#endif -+ -+/** -+ *Traces an info message. -+ *The file, line and enclosing function -+ *of the message will be automatically -+ *added to the message. -+ *@param a_msg the msg to trace. -+ */ -+#define cr_utils_trace_info(a_msg) \ -+cr_utils_trace (G_LOG_LEVEL_INFO, a_msg) -+ -+/** -+ *Trace a debug message. -+ *The file, line and enclosing function -+ *of the message will be automatically -+ *added to the message. -+ *@param a_msg the msg to trace. -+ */ -+#define cr_utils_trace_debug(a_msg) \ -+cr_utils_trace (G_LOG_LEVEL_DEBUG, a_msg) ; -+ -+ -+/**************************** -+ *Encoding transformations and -+ *encoding helpers -+ ****************************/ -+ -+enum CRStatus -+cr_utils_read_char_from_utf8_buf (const guchar * a_in, gulong a_in_len, -+ guint32 *a_out, gulong *a_consumed) ; -+ -+enum CRStatus -+cr_utils_ucs1_to_utf8 (const guchar *a_in, gulong *a_in_len, -+ guchar *a_out, gulong *a_out_len) ; -+ -+enum CRStatus -+cr_utils_utf8_to_ucs1 (const guchar * a_in, gulong * a_in_len, -+ guchar *a_out, gulong *a_out_len) ; -+ -+enum CRStatus -+cr_utils_ucs4_to_utf8 (const guint32 *a_in, gulong *a_in_len, -+ guchar *a_out, gulong *a_out_len) ; -+ -+enum CRStatus -+cr_utils_utf8_str_len_as_ucs4 (const guchar *a_in_start, -+ const guchar *a_in_end, -+ gulong *a_len) ; -+enum CRStatus -+cr_utils_ucs1_str_len_as_utf8 (const guchar *a_in_start, -+ const guchar *a_in_end, -+ gulong *a_len) ; -+enum CRStatus -+cr_utils_utf8_str_len_as_ucs1 (const guchar *a_in_start, -+ const guchar *a_in_end, -+ gulong *a_len) ; -+enum CRStatus -+cr_utils_ucs4_str_len_as_utf8 (const guint32 *a_in_start, -+ const guint32 *a_in_end, -+ gulong *a_len) ; -+ -+enum CRStatus -+cr_utils_ucs1_str_to_utf8 (const guchar *a_in_start, -+ gulong *a_in_len, -+ guchar **a_out, -+ gulong *a_len) ; -+ -+enum CRStatus -+cr_utils_utf8_str_to_ucs1 (const guchar * a_in_start, -+ gulong * a_in_len, -+ guchar **a_out, -+ gulong *a_out_len) ; -+ -+enum CRStatus -+cr_utils_utf8_to_ucs4 (const guchar * a_in, -+ gulong * a_in_len, -+ guint32 *a_out, gulong *a_out_len) ; -+ -+enum CRStatus -+cr_utils_ucs4_str_to_utf8 (const guint32 *a_in, -+ gulong *a_in_len, -+ guchar **a_out, gulong *a_out_len) ; -+ -+enum CRStatus -+cr_utils_utf8_str_to_ucs4 (const guchar * a_in, -+ gulong *a_in_len, -+ guint32 **a_out, -+ gulong *a_out_len) ; -+ -+ -+/***************************************** -+ *CSS basic types identification utilities -+ *****************************************/ -+ -+gboolean -+cr_utils_is_newline (guint32 a_char) ; -+ -+gboolean -+cr_utils_is_white_space (guint32 a_char) ; -+ -+gboolean -+cr_utils_is_nonascii (guint32 a_char) ; -+ -+gboolean -+cr_utils_is_hexa_char (guint32 a_char) ; -+ -+ -+/********************************** -+ *Miscellaneous utility functions -+ ***********************************/ -+ -+void -+cr_utils_dump_n_chars (guchar a_char, -+ FILE *a_fp, -+ glong a_nb) ; -+ -+void -+cr_utils_dump_n_chars2 (guchar a_char, -+ GString *a_string, -+ glong a_nb) ; -+GList * -+cr_utils_dup_glist_of_string (GList const *a_list) ; -+ -+GList * -+cr_utils_dup_glist_of_cr_string (GList const * a_list_of_strings) ; -+ -+G_END_DECLS -+ -+#endif /*__CR_DEFS_H__*/ -diff --git a/src/st/croco/libcroco-config.h b/src/st/croco/libcroco-config.h -new file mode 100644 -index 000000000..1ffb758ea ---- /dev/null -+++ b/src/st/croco/libcroco-config.h -@@ -0,0 +1,13 @@ -+#ifndef LIBCROCO_VERSION_NUMBER -+#define LIBCROCO_VERSION_NUMBER 612 -+#endif -+ -+#ifndef LIBCROCO_VERSION -+#define LIBCROCO_VERSION "0.6.12" -+#endif -+ -+#ifndef G_DISABLE_CHECKS -+#if 0 -+#define G_DISABLE_CHECKS 0 -+#endif -+#endif -diff --git a/src/st/croco/libcroco.h b/src/st/croco/libcroco.h -new file mode 100644 -index 000000000..6187a7cb9 ---- /dev/null -+++ b/src/st/croco/libcroco.h -@@ -0,0 +1,42 @@ -+/* -+ * This file is part of The Croco Library -+ * -+ * Copyright (C) 2002-2003 Dodji Seketeli -+ * -+ * 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 -+ */ -+ -+#ifndef __LIBCROCO_H__ -+#define __LIBCROCO_H__ -+ -+#include "libcroco-config.h" -+ -+#include "cr-utils.h" -+#include "cr-pseudo.h" -+#include "cr-term.h" -+#include "cr-attr-sel.h" -+#include "cr-simple-sel.h" -+#include "cr-selector.h" -+#include "cr-enc-handler.h" -+#include "cr-doc-handler.h" -+#include "cr-input.h" -+#include "cr-parser.h" -+#include "cr-statement.h" -+#include "cr-stylesheet.h" -+#include "cr-om-parser.h" -+#include "cr-prop-list.h" -+#include "cr-string.h" -+ -+#endif /*__LIBCROCO_H__*/ -diff --git a/src/st/meson.build b/src/st/meson.build -index 97ce6134d..c1994755b 100644 ---- a/src/st/meson.build -+++ b/src/st/meson.build -@@ -1,3 +1,4 @@ -+# please, keep this sorted alphabetically - st_headers = [ - 'st-adjustment.h', - 'st-bin.h', -@@ -43,13 +44,68 @@ st_h = configure_file( - - st_inc = include_directories('.', '..') - -+# please, keep this sorted alphabetically - st_private_headers = [ -+ 'croco/cr-additional-sel.h', -+ 'croco/cr-attr-sel.h', -+ 'croco/cr-cascade.h', -+ 'croco/cr-declaration.h', -+ 'croco/cr-doc-handler.h', -+ 'croco/cr-enc-handler.h', -+ 'croco/cr-fonts.h', -+ 'croco/cr-input.h', -+ 'croco/cr-num.h', -+ 'croco/cr-om-parser.h', -+ 'croco/cr-parser.h', -+ 'croco/cr-parsing-location.h', -+ 'croco/cr-prop-list.h', -+ 'croco/cr-pseudo.h', -+ 'croco/cr-rgb.h', -+ 'croco/cr-selector.h', -+ 'croco/cr-simple-sel.h', -+ 'croco/cr-statement.h', -+ 'croco/cr-string.h', -+ 'croco/cr-stylesheet.h', -+ 'croco/cr-term.h', -+ 'croco/cr-tknzr.h', -+ 'croco/cr-token.h', -+ 'croco/cr-utils.h', -+ 'croco/libcroco-config.h', -+ 'croco/libcroco.h', - 'st-private.h', - 'st-theme-private.h', - 'st-theme-node-private.h', - 'st-theme-node-transition.h' - ] - -+# please, keep this sorted alphabetically -+croco_sources = [ -+ 'croco/cr-additional-sel.c', -+ 'croco/cr-attr-sel.c', -+ 'croco/cr-cascade.c', -+ 'croco/cr-declaration.c', -+ 'croco/cr-doc-handler.c', -+ 'croco/cr-enc-handler.c', -+ 'croco/cr-fonts.c', -+ 'croco/cr-input.c', -+ 'croco/cr-num.c', -+ 'croco/cr-om-parser.c', -+ 'croco/cr-parser.c', -+ 'croco/cr-parsing-location.c', -+ 'croco/cr-prop-list.c', -+ 'croco/cr-pseudo.c', -+ 'croco/cr-rgb.c', -+ 'croco/cr-selector.c', -+ 'croco/cr-simple-sel.c', -+ 'croco/cr-statement.c', -+ 'croco/cr-string.c', -+ 'croco/cr-stylesheet.c', -+ 'croco/cr-term.c', -+ 'croco/cr-tknzr.c', -+ 'croco/cr-token.c', -+ 'croco/cr-utils.c', -+] -+ - # please, keep this sorted alphabetically - st_sources = [ - 'st-adjustment.c', -@@ -119,9 +175,9 @@ st_cflags = [ - - # Currently meson requires a shared library for building girs - libst = shared_library('st-1.0', -- sources: st_gir_sources + st_non_gir_sources, -+ sources: st_gir_sources + st_non_gir_sources + croco_sources, - c_args: st_cflags, -- dependencies: [clutter_dep, gtk_dep, croco_dep, x11_dep, m_dep], -+ dependencies: [clutter_dep, gtk_dep, x11_dep, m_dep], - install_rpath: mutter_typelibdir, - install_dir: pkglibdir, - install: true -@@ -134,7 +190,7 @@ libst_dep = declare_dependency(link_with: libst, - test_theme = executable('test-theme', - sources: 'test-theme.c', - c_args: st_cflags, -- dependencies: [clutter_dep, gtk_dep], -+ dependencies: [clutter_dep, gtk_dep, libxml_dep], - link_with: libst - ) - -diff --git a/src/st/st-theme-node-private.h b/src/st/st-theme-node-private.h -index 2e6b232f6..659bc37ba 100644 ---- a/src/st/st-theme-node-private.h -+++ b/src/st/st-theme-node-private.h -@@ -25,7 +25,7 @@ - #include - - #include "st-theme-node.h" --#include -+#include "croco/libcroco.h" - #include "st-types.h" - - G_BEGIN_DECLS -diff --git a/src/st/st-theme-private.h b/src/st/st-theme-private.h -index 08f3a1864..2083a7c84 100644 ---- a/src/st/st-theme-private.h -+++ b/src/st/st-theme-private.h -@@ -21,7 +21,7 @@ - #ifndef __ST_THEME_PRIVATE_H__ - #define __ST_THEME_PRIVATE_H__ - --#include -+#include "croco/libcroco.h" - #include "st-theme.h" - - G_BEGIN_DECLS --- -2.23.0 - diff --git a/gnome-shell.spec b/gnome-shell.spec index e5d830b..f0a8f25 100644 --- a/gnome-shell.spec +++ b/gnome-shell.spec @@ -1,6 +1,6 @@ Name: gnome-shell Version: 3.30.1 -Release: 6 +Release: 5 Summary: Core user interface functions for the GNOME 3 desktop Group: User Interface/Desktops License: GPLv2+ @@ -11,7 +11,6 @@ Patch1: gnome-shell-favourite-apps-firefox.patch Patch2: 0001-endSessionDialog-Immediately-add-buttons-to-the-dial.patch Patch3: 0002-endSessionDialog-Support-rebooting-into-the-bootload.patch Patch4: 0001-keyboardManager-Avoid-idempotent-calls-to-meta_backe.patch -Patch5: 0001-Include-the-libcroco-sources-directly-under-src-st-c.patch BuildRequires: meson git ibus-devel chrpath dbus-glib-devel desktop-file-utils BuildRequires: evolution-data-server-devel gcr-devel gjs-devel glib2-devel @@ -121,10 +120,6 @@ glib-compile-schemas --allow-any-name %{_datadir}/glib-2.0/schemas &> /dev/null %{_mandir}/man1/%{name}.1.gz %changelog -* Thu Dec 03 2020 wangxiao -3.30.1-6 -- move the libcroco sources directly under src/st - remove the libcroco dependency from the meson.build files - * Fri Dec 27 2019 Jiangping Hu - 3.30.1-5 - Type:bugfix - Id:NA -- Gitee