• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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