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 = (CRSimpleSel *)g_try_malloc (sizeof (CRSimpleSel));
37 if (!result) {
38 cr_utils_trace_info ("Out of memory");
39 return NULL;
40 }
41 memset (result, 0, sizeof (CRSimpleSel));
43 return result;
44 }
46 /**
47 *Appends a simpe selector to the current list of simple selector.
48 *
49 *@param a_this the this pointer of the current instance of #CRSimpleSel.
50 *@param a_sel the simple selector to append.
51 *@return the new list upon successfull completion, an error code otherwise.
52 */
53 CRSimpleSel *
54 cr_simple_sel_append_simple_sel (CRSimpleSel * a_this, CRSimpleSel * a_sel)
55 {
56 CRSimpleSel *cur = NULL;
58 g_return_val_if_fail (a_sel, NULL);
60 if (a_this == NULL)
61 return a_sel;
63 for (cur = a_this; cur->next; cur = cur->next) ;
65 cur->next = a_sel;
66 a_sel->prev = cur;
68 return a_this;
69 }
71 /**
72 *Prepends a simple selector to the current list of simple selectors.
73 *@param a_this the this pointer of the current instance of #CRSimpleSel.
74 *@param a_sel the simple selector to prepend.
75 *@return the new list upon successfull completion, an error code otherwise.
76 */
77 CRSimpleSel *
78 cr_simple_sel_prepend_simple_sel (CRSimpleSel * a_this, CRSimpleSel * a_sel)
79 {
80 g_return_val_if_fail (a_sel, NULL);
82 if (a_this == NULL)
83 return a_sel;
85 a_sel->next = a_this;
86 a_this->prev = a_sel;
88 return a_sel;
89 }
91 guchar *
92 cr_simple_sel_to_string (CRSimpleSel * a_this)
93 {
94 GString *str_buf = NULL;
95 guchar *result = NULL;
97 CRSimpleSel *cur = NULL;
99 g_return_val_if_fail (a_this, NULL);
101 str_buf = g_string_new (NULL);
102 for (cur = a_this; cur; cur = cur->next) {
103 if (cur->name) {
104 gchar *str = g_strndup (cur->name->stryng->str,
105 cur->name->stryng->len);
107 if (str) {
108 switch (cur->combinator) {
109 case COMB_WS:
110 g_string_append (str_buf, " ");
111 break;
113 case COMB_PLUS:
114 g_string_append (str_buf, "+");
115 break;
117 case COMB_GT:
118 g_string_append (str_buf, ">");
119 break;
121 default:
122 break;
123 }
125 g_string_append (str_buf, str);
126 g_free (str);
127 str = NULL;
128 }
129 }
131 if (cur->add_sel) {
133 gchar *tmp_str = (gchar *)cr_additional_sel_to_string (cur->add_sel);
134 if (tmp_str) {
135 g_string_append (str_buf, tmp_str);
136 g_free (tmp_str);
137 tmp_str = NULL;
138 }
139 }
140 }
142 if (str_buf) {
143 result = (guchar *)str_buf->str;
144 g_string_free (str_buf, FALSE);
145 str_buf = NULL;
146 }
148 return result;
149 }
152 guchar *
153 cr_simple_sel_one_to_string (CRSimpleSel * a_this)
154 {
155 GString *str_buf = NULL;
156 guchar *result = NULL;
158 g_return_val_if_fail (a_this, NULL);
160 str_buf = g_string_new (NULL);
161 if (a_this->name) {
162 gchar *str = g_strndup (a_this->name->stryng->str,
163 a_this->name->stryng->len);
165 if (str) {
166 g_string_append_printf (str_buf, "%s", str);
167 g_free (str);
168 str = NULL;
169 }
170 }
172 if (a_this->add_sel) {
174 gchar *tmp_str = (gchar *)cr_additional_sel_to_string (a_this->add_sel);
175 if (tmp_str) {
176 g_string_append_printf
177 (str_buf, "%s", tmp_str);
178 g_free (tmp_str);
179 tmp_str = NULL;
180 }
181 }
183 if (str_buf) {
184 result = (guchar *)str_buf->str;
185 g_string_free (str_buf, FALSE);
186 str_buf = NULL;
187 }
189 return result;
190 }
192 /**
193 *Dumps the selector to a file.
194 *TODO: add the support of unicode in the dump.
195 *
196 *@param a_this the current instance of #CRSimpleSel.
197 *@param a_fp the destination file pointer.
198 *@return CR_OK upon successfull completion, an error code
199 *otherwise.
200 */
201 enum CRStatus
202 cr_simple_sel_dump (CRSimpleSel * a_this, FILE * a_fp)
203 {
204 guchar *tmp_str = NULL;
206 g_return_val_if_fail (a_fp, CR_BAD_PARAM_ERROR);
208 if (a_this) {
209 tmp_str = cr_simple_sel_to_string (a_this);
210 if (tmp_str) {
211 fprintf (a_fp, "%s", tmp_str);
212 g_free (tmp_str);
213 tmp_str = NULL;
214 }
215 }
217 return CR_OK;
218 }
220 /**
221 *Computes the selector (combinator separated list of simple selectors)
222 *as defined in the css2 spec in chapter 6.4.3
223 *@param a_this the current instance of #CRSimpleSel
224 *@return CR_OK upon successfull completion, an error code otherwise.
225 */
226 enum CRStatus
227 cr_simple_sel_compute_specificity (CRSimpleSel * a_this)
228 {
229 CRAdditionalSel *cur_add_sel = NULL;
230 CRSimpleSel *cur_sel = NULL;
231 gulong a = 0,
232 b = 0,
233 c = 0;
235 g_return_val_if_fail (a_this, CR_BAD_PARAM_ERROR);
237 for (cur_sel = a_this; cur_sel; cur_sel = cur_sel->next) {
238 if (cur_sel->type_mask | TYPE_SELECTOR) {
239 c++; /*hmmh, is this a new language ? */
240 } else if (!cur_sel->name
241 || !cur_sel->name->stryng
242 || !cur_sel->name->stryng->str) {
243 if (cur_sel->add_sel->type ==
244 PSEUDO_CLASS_ADD_SELECTOR) {
245 /*
246 *this is a pseudo element, and
247 *the spec says, "ignore pseudo elements".
248 */
249 continue;
250 }
251 }
253 for (cur_add_sel = cur_sel->add_sel;
254 cur_add_sel; cur_add_sel = cur_add_sel->next) {
255 switch (cur_add_sel->type) {
256 case ID_ADD_SELECTOR:
257 a++;
258 break;
260 case NO_ADD_SELECTOR:
261 continue;
263 default:
264 b++;
265 break;
266 }
267 }
268 }
270 /*we suppose a, b and c have 1 to 3 digits */
271 a_this->specificity = a * 1000000 + b * 1000 + c;
273 return CR_OK;
274 }
276 /**
277 *The destructor of the current instance of
278 *#CRSimpleSel.
279 *@param a_this the this pointer of the current instance of #CRSimpleSel.
280 *
281 */
282 void
283 cr_simple_sel_destroy (CRSimpleSel * a_this)
284 {
285 g_return_if_fail (a_this);
287 if (a_this->name) {
288 cr_string_destroy (a_this->name);
289 a_this->name = NULL;
290 }
292 if (a_this->add_sel) {
293 cr_additional_sel_destroy (a_this->add_sel);
294 a_this->add_sel = NULL;
295 }
297 if (a_this->next) {
298 cr_simple_sel_destroy (a_this->next);
299 }
301 if (a_this) {
302 g_free (a_this);
303 }
304 }