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