1 /* -*- Mode: C; indent-tabs-mode:nil; c-basic-offset: 8-*- */
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 Lesser 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 Lesser 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 */
24 #include <string.h>
25 #include <glib.h>
26 #include "cr-simple-sel.h"
28 /**
29 *The constructor of #CRSimpleSel.
30 *
31 *@return the new instance of #CRSimpleSel.
32 */
33 CRSimpleSel *
34 cr_simple_sel_new (void)
35 {
36 CRSimpleSel *result = NULL;
38 result = g_try_malloc (sizeof (CRSimpleSel));
39 if (!result) {
40 cr_utils_trace_info ("Out of memory");
41 return NULL;
42 }
43 memset (result, 0, sizeof (CRSimpleSel));
45 return result;
46 }
48 /**
49 *Appends a simpe selector to the current list of simple selector.
50 *
51 *@param a_this the this pointer of the current instance of #CRSimpleSel.
52 *@param a_sel the simple selector to append.
53 *@return the new list upon successfull completion, an error code otherwise.
54 */
55 CRSimpleSel *
56 cr_simple_sel_append_simple_sel (CRSimpleSel * a_this, CRSimpleSel * a_sel)
57 {
58 CRSimpleSel *cur = NULL;
60 g_return_val_if_fail (a_sel, NULL);
62 if (a_this == NULL)
63 return a_sel;
65 for (cur = a_this; cur->next; cur = cur->next) ;
67 cur->next = a_sel;
68 a_sel->prev = cur;
70 return a_this;
71 }
73 /**
74 *Prepends a simple selector to the current list of simple selectors.
75 *@param a_this the this pointer of the current instance of #CRSimpleSel.
76 *@param a_sel the simple selector to prepend.
77 *@return the new list upon successfull completion, an error code otherwise.
78 */
79 CRSimpleSel *
80 cr_simple_sel_prepend_simple_sel (CRSimpleSel * a_this, CRSimpleSel * a_sel)
81 {
82 g_return_val_if_fail (a_sel, NULL);
84 if (a_this == NULL)
85 return a_sel;
87 a_sel->next = a_this;
88 a_this->prev = a_sel;
90 return a_sel;
91 }
93 guchar *
94 cr_simple_sel_to_string (CRSimpleSel * a_this)
95 {
96 GString *str_buf = NULL;
97 guchar *result = NULL;
99 CRSimpleSel *cur = NULL;
101 g_return_val_if_fail (a_this, NULL);
103 str_buf = g_string_new (NULL);
104 for (cur = a_this; cur; cur = cur->next) {
105 if (cur->name) {
106 guchar *str = g_strndup (cur->name->stryng->str,
107 cur->name->stryng->len);
109 if (str) {
110 switch (cur->combinator) {
111 case COMB_WS:
112 g_string_append (str_buf, " ");
113 break;
115 case COMB_PLUS:
116 g_string_append (str_buf, "+");
117 break;
119 case COMB_GT:
120 g_string_append (str_buf, ">");
121 break;
123 default:
124 break;
125 }
127 g_string_append (str_buf, str);
128 g_free (str);
129 str = NULL;
130 }
131 }
133 if (cur->add_sel) {
134 guchar *tmp_str = NULL;
136 tmp_str = cr_additional_sel_to_string (cur->add_sel);
137 if (tmp_str) {
138 g_string_append (str_buf, tmp_str);
139 g_free (tmp_str);
140 tmp_str = NULL;
141 }
142 }
143 }
145 if (str_buf) {
146 result = str_buf->str;
147 g_string_free (str_buf, FALSE);
148 str_buf = NULL;
149 }
151 return result;
152 }
155 guchar *
156 cr_simple_sel_one_to_string (CRSimpleSel * a_this)
157 {
158 GString *str_buf = NULL;
159 guchar *result = NULL;
161 g_return_val_if_fail (a_this, NULL);
163 str_buf = g_string_new (NULL);
164 if (a_this->name) {
165 guchar *str = g_strndup (a_this->name->stryng->str,
166 a_this->name->stryng->len);
168 if (str) {
169 g_string_append_printf (str_buf, "%s", str);
170 g_free (str);
171 str = NULL;
172 }
173 }
175 if (a_this->add_sel) {
176 guchar *tmp_str = NULL;
178 tmp_str = cr_additional_sel_to_string (a_this->add_sel);
179 if (tmp_str) {
180 g_string_append_printf
181 (str_buf, "%s", tmp_str);
182 g_free (tmp_str);
183 tmp_str = NULL;
184 }
185 }
187 if (str_buf) {
188 result = str_buf->str;
189 g_string_free (str_buf, FALSE);
190 str_buf = NULL;
191 }
193 return result;
194 }
196 /**
197 *Dumps the selector to a file.
198 *TODO: add the support of unicode in the dump.
199 *
200 *@param a_this the current instance of #CRSimpleSel.
201 *@param a_fp the destination file pointer.
202 *@return CR_OK upon successfull completion, an error code
203 *otherwise.
204 */
205 enum CRStatus
206 cr_simple_sel_dump (CRSimpleSel * a_this, FILE * a_fp)
207 {
208 guchar *tmp_str = NULL;
210 g_return_val_if_fail (a_fp, CR_BAD_PARAM_ERROR);
212 if (a_this) {
213 tmp_str = cr_simple_sel_to_string (a_this);
214 if (tmp_str) {
215 fprintf (a_fp, "%s", tmp_str);
216 g_free (tmp_str);
217 tmp_str = NULL;
218 }
219 }
221 return CR_OK;
222 }
224 /**
225 *Computes the selector (combinator separated list of simple selectors)
226 *as defined in the css2 spec in chapter 6.4.3
227 *@param a_this the current instance of #CRSimpleSel
228 *@return CR_OK upon successfull completion, an error code otherwise.
229 */
230 enum CRStatus
231 cr_simple_sel_compute_specificity (CRSimpleSel * a_this)
232 {
233 CRAdditionalSel *cur_add_sel = NULL;
234 CRSimpleSel *cur_sel = NULL;
235 gulong a = 0,
236 b = 0,
237 c = 0;
239 g_return_val_if_fail (a_this, CR_BAD_PARAM_ERROR);
241 for (cur_sel = a_this; cur_sel; cur_sel = cur_sel->next) {
242 if (cur_sel->type_mask | TYPE_SELECTOR) {
243 c++; /*hmmh, is this a new language ? */
244 } else if (!cur_sel->name
245 || !cur_sel->name->stryng
246 || !cur_sel->name->stryng->str) {
247 if (cur_sel->add_sel->type ==
248 PSEUDO_CLASS_ADD_SELECTOR) {
249 /*
250 *this is a pseudo element, and
251 *the spec says, "ignore pseudo elements".
252 */
253 continue;
254 }
255 }
257 for (cur_add_sel = cur_sel->add_sel;
258 cur_add_sel; cur_add_sel = cur_add_sel->next) {
259 switch (cur_add_sel->type) {
260 case ID_ADD_SELECTOR:
261 a++;
262 break;
264 case NO_ADD_SELECTOR:
265 continue;
267 default:
268 b++;
269 break;
270 }
271 }
272 }
274 /*we suppose a, b and c have 1 to 3 digits */
275 a_this->specificity = a * 1000000 + b * 1000 + c;
277 return CR_OK;
278 }
280 /**
281 *The destructor of the current instance of
282 *#CRSimpleSel.
283 *@param a_this the this pointer of the current instance of #CRSimpleSel.
284 *
285 */
286 void
287 cr_simple_sel_destroy (CRSimpleSel * a_this)
288 {
289 g_return_if_fail (a_this);
291 if (a_this->name) {
292 cr_string_destroy (a_this->name);
293 a_this->name = NULL;
294 }
296 if (a_this->add_sel) {
297 cr_additional_sel_destroy (a_this->add_sel);
298 a_this->add_sel = NULL;
299 }
301 if (a_this->next) {
302 cr_simple_sel_destroy (a_this->next);
303 }
305 if (a_this) {
306 g_free (a_this);
307 }
308 }