1/* -*- Mode: C; indent-tabs-mode:nil; c-basic-offset: 8-*- */ 2 3/* 4 * This file is part of The Croco Library 5 * 6 * This program is free software; you can redistribute it and/or 7 * modify it under the terms of version 2.1 of the GNU General Public 8 * License as published by the Free Software Foundation. 9 * 10 * This program is distributed in the hope that it will be useful, 11 * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 * GNU General Public License for more details. 14 * 15 * You should have received a copy of the GNU General Public License 16 * along with this program; if not, write to the Free Software 17 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 18 * USA 19 * 20 * Author: Dodji Seketeli 21 * See COPYRIGHTS file for copyright information. 22 */ 23 24#include <config.h> 25#include <string.h> 26#include <glib.h> 27#include "cr-simple-sel.h" 28 29/** 30 * cr_simple_sel_new: 31 * 32 *The constructor of #CRSimpleSel. 33 * 34 *Returns the new instance of #CRSimpleSel. 35 */ 36CRSimpleSel * 37cr_simple_sel_new (void) 38{ 39 CRSimpleSel *result = NULL; 40 41 result = g_try_malloc (sizeof (CRSimpleSel)); 42 if (!result) { 43 cr_utils_trace_info ("Out of memory"); 44 return NULL; 45 } 46 memset (result, 0, sizeof (CRSimpleSel)); 47 48 return result; 49} 50 51/** 52 * cr_simple_sel_append_simple_sel: 53 * 54 *Appends a simpe selector to the current list of simple selector. 55 * 56 *@a_this: the this pointer of the current instance of #CRSimpleSel. 57 *@a_sel: the simple selector to append. 58 *Returns: the new list upon successfull completion, an error code otherwise. 59 */ 60CRSimpleSel * 61cr_simple_sel_append_simple_sel (CRSimpleSel * a_this, CRSimpleSel * a_sel) 62{ 63 CRSimpleSel *cur = NULL; 64 65 g_return_val_if_fail (a_sel, NULL); 66 67 if (a_this == NULL) 68 return a_sel; 69 70 for (cur = a_this; cur->next; cur = cur->next) ; 71 72 cur->next = a_sel; 73 a_sel->prev = cur; 74 75 return a_this; 76} 77 78/** 79 * cr_simple_sel_prepend_simple_sel: 80 * 81 *@a_this: the this pointer of the current instance of #CRSimpleSel. 82 *@a_sel: the simple selector to prepend. 83 * 84 *Prepends a simple selector to the current list of simple selectors. 85 * 86 *Returns the new list upon successfull completion, an error code otherwise. 87 */ 88CRSimpleSel * 89cr_simple_sel_prepend_simple_sel (CRSimpleSel * a_this, CRSimpleSel * a_sel) 90{ 91 g_return_val_if_fail (a_sel, NULL); 92 93 if (a_this == NULL) 94 return a_sel; 95 96 a_sel->next = a_this; 97 a_this->prev = a_sel; 98 99 return a_sel; 100} 101 102guchar * 103cr_simple_sel_to_string (CRSimpleSel * a_this) 104{ 105 GString *str_buf = NULL; 106 guchar *result = NULL; 107 108 CRSimpleSel *cur = NULL; 109 110 g_return_val_if_fail (a_this, NULL); 111 112 str_buf = g_string_new (NULL); 113 for (cur = a_this; cur; cur = cur->next) { 114 if (cur->name) { 115 guchar *str = g_strndup (cur->name->stryng->str, 116 cur->name->stryng->len); 117 118 if (str) { 119 switch (cur->combinator) { 120 case COMB_WS: 121 g_string_append (str_buf, " "); 122 break; 123 124 case COMB_PLUS: 125 g_string_append (str_buf, "+"); 126 break; 127 128 case COMB_GT: 129 g_string_append (str_buf, ">"); 130 break; 131 132 default: 133 break; 134 } 135 136 g_string_append (str_buf, str); 137 g_free (str); 138 str = NULL; 139 } 140 } 141 142 if (cur->add_sel) { 143 guchar *tmp_str = NULL; 144 145 tmp_str = cr_additional_sel_to_string (cur->add_sel); 146 if (tmp_str) { 147 g_string_append (str_buf, tmp_str); 148 g_free (tmp_str); 149 tmp_str = NULL; 150 } 151 } 152 } 153 154 if (str_buf) { 155 result = str_buf->str; 156 g_string_free (str_buf, FALSE); 157 str_buf = NULL; 158 } 159 160 return result; 161} 162 163 164guchar * 165cr_simple_sel_one_to_string (CRSimpleSel * a_this) 166{ 167 GString *str_buf = NULL; 168 guchar *result = NULL; 169 170 g_return_val_if_fail (a_this, NULL); 171 172 str_buf = g_string_new (NULL); 173 if (a_this->name) { 174 guchar *str = g_strndup (a_this->name->stryng->str, 175 a_this->name->stryng->len); 176 177 if (str) { 178 g_string_append_printf (str_buf, "%s", str); 179 g_free (str); 180 str = NULL; 181 } 182 } 183 184 if (a_this->add_sel) { 185 guchar *tmp_str = NULL; 186 187 tmp_str = cr_additional_sel_to_string (a_this->add_sel); 188 if (tmp_str) { 189 g_string_append_printf 190 (str_buf, "%s", tmp_str); 191 g_free (tmp_str); 192 tmp_str = NULL; 193 } 194 } 195 196 if (str_buf) { 197 result = str_buf->str; 198 g_string_free (str_buf, FALSE); 199 str_buf = NULL; 200 } 201 202 return result; 203} 204 205/** 206 * cr_simple_sel_dump: 207 *@a_this: the current instance of #CRSimpleSel. 208 *@a_fp: the destination file pointer. 209 * 210 *Dumps the selector to a file. 211 *TODO: add the support of unicode in the dump. 212 * 213 *Returns CR_OK upon successfull completion, an error code 214 *otherwise. 215 */ 216enum CRStatus 217cr_simple_sel_dump (CRSimpleSel * a_this, FILE * a_fp) 218{ 219 guchar *tmp_str = NULL; 220 221 g_return_val_if_fail (a_fp, CR_BAD_PARAM_ERROR); 222 223 if (a_this) { 224 tmp_str = cr_simple_sel_to_string (a_this); 225 if (tmp_str) { 226 fprintf (a_fp, "%s", tmp_str); 227 g_free (tmp_str); 228 tmp_str = NULL; 229 } 230 } 231 232 return CR_OK; 233} 234 235/** 236 * cr_simple_sel_compute_specificity: 237 * 238 *@a_this: the current instance of #CRSimpleSel 239 * 240 *Computes the selector (combinator separated list of simple selectors) 241 *as defined in the css2 spec in chapter 6.4.3 242 * 243 *Returns CR_OK upon successfull completion, an error code otherwise. 244 */ 245enum CRStatus 246cr_simple_sel_compute_specificity (CRSimpleSel * a_this) 247{ 248 CRAdditionalSel *cur_add_sel = NULL; 249 CRSimpleSel *cur_sel = NULL; 250 gulong a = 0, 251 b = 0, 252 c = 0; 253 254 g_return_val_if_fail (a_this, CR_BAD_PARAM_ERROR); 255 256 for (cur_sel = a_this; cur_sel; cur_sel = cur_sel->next) { 257 if (cur_sel->type_mask | TYPE_SELECTOR) { 258 c++; /*hmmh, is this a new language ? */ 259 } else if (!cur_sel->name 260 || !cur_sel->name->stryng 261 || !cur_sel->name->stryng->str) { 262 if (cur_sel->add_sel->type == 263 PSEUDO_CLASS_ADD_SELECTOR) { 264 /* 265 *this is a pseudo element, and 266 *the spec says, "ignore pseudo elements". 267 */ 268 continue; 269 } 270 } 271 272 for (cur_add_sel = cur_sel->add_sel; 273 cur_add_sel; cur_add_sel = cur_add_sel->next) { 274 switch (cur_add_sel->type) { 275 case ID_ADD_SELECTOR: 276 a++; 277 break; 278 279 case NO_ADD_SELECTOR: 280 continue; 281 282 default: 283 b++; 284 break; 285 } 286 } 287 } 288 289 /*we suppose a, b and c have 1 to 3 digits */ 290 a_this->specificity = a * 1000000 + b * 1000 + c; 291 292 return CR_OK; 293} 294 295/** 296 * cr_simple_sel_destroy: 297 * 298 *@a_this: the this pointer of the current instance of #CRSimpleSel. 299 * 300 *The destructor of the current instance of 301 *#CRSimpleSel. 302 */ 303void 304cr_simple_sel_destroy (CRSimpleSel * a_this) 305{ 306 g_return_if_fail (a_this); 307 308 if (a_this->name) { 309 cr_string_destroy (a_this->name); 310 a_this->name = NULL; 311 } 312 313 if (a_this->add_sel) { 314 cr_additional_sel_destroy (a_this->add_sel); 315 a_this->add_sel = NULL; 316 } 317 318 if (a_this->next) { 319 cr_simple_sel_destroy (a_this->next); 320 } 321 322 if (a_this) { 323 g_free (a_this); 324 } 325} 326