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 3 of the GNU 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 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 
35 #include <config.h>
36 #include "cr-additional-sel.h"
37 #include "string.h"
38 
39 /**
40  * CRAdditionalSel:
41  *
42  * #CRAdditionalSel abstracts an additionnal selector.
43  * An additional selector is the selector part
44  * that comes after the combination of type selectors.
45  * It can be either "a class selector (the .class part),
46  * a pseudo class selector, an attribute selector
47  * or an id selector.
48  */
49 
50 /**
51  * cr_additional_sel_new:
52  *
53  * Default constructor of #CRAdditionalSel.
54  * Returns the newly build instance of #CRAdditionalSel.
55  */
56 CRAdditionalSel *
cr_additional_sel_new(void)57 cr_additional_sel_new (void)
58 {
59         CRAdditionalSel *result = NULL;
60 
61         result = g_try_malloc (sizeof (CRAdditionalSel));
62 
63         if (result == NULL) {
64                 cr_utils_trace_debug ("Out of memory");
65                 return NULL;
66         }
67 
68         memset (result, 0, sizeof (CRAdditionalSel));
69 
70         return result;
71 }
72 
73 /**
74  * cr_additional_sel_new_with_type:
75  * @a_sel_type: the type of the newly built instance
76  * of #CRAdditionalSel.
77  *
78  * Constructor of #CRAdditionalSel.
79  * Returns the newly built instance of #CRAdditionalSel.
80  */
81 CRAdditionalSel *
cr_additional_sel_new_with_type(enum AddSelectorType a_sel_type)82 cr_additional_sel_new_with_type (enum AddSelectorType a_sel_type)
83 {
84         CRAdditionalSel *result = NULL;
85 
86         result = cr_additional_sel_new ();
87 
88         g_return_val_if_fail (result, NULL);
89 
90         result->type = a_sel_type;
91 
92         return result;
93 }
94 
95 /**
96  * cr_additional_sel_set_class_name:
97  * @a_this: the "this pointer" of the current instance
98  * of #CRAdditionalSel .
99  * @a_class_name: the new class name to set.
100  *
101  * Sets a new class name to a
102  * CLASS additional selector.
103  */
104 void
cr_additional_sel_set_class_name(CRAdditionalSel * a_this,CRString * a_class_name)105 cr_additional_sel_set_class_name (CRAdditionalSel * a_this,
106                                   CRString * a_class_name)
107 {
108         g_return_if_fail (a_this && a_this->type == CLASS_ADD_SELECTOR);
109 
110         if (a_this->content.class_name) {
111                 cr_string_destroy (a_this->content.class_name);
112         }
113 
114         a_this->content.class_name = a_class_name;
115 }
116 
117 /**
118  * cr_additional_sel_set_id_name:
119  * @a_this: the "this pointer" of the current instance
120  * of #CRAdditionalSel .
121  * @a_id: the new id to set.
122  *
123  * Sets a new id name to an
124  * ID additional selector.
125  */
126 void
cr_additional_sel_set_id_name(CRAdditionalSel * a_this,CRString * a_id)127 cr_additional_sel_set_id_name (CRAdditionalSel * a_this, CRString * a_id)
128 {
129         g_return_if_fail (a_this && a_this->type == ID_ADD_SELECTOR);
130 
131         if (a_this->content.id_name) {
132                 cr_string_destroy (a_this->content.id_name);
133         }
134 
135         a_this->content.id_name = a_id;
136 }
137 
138 /**
139  * cr_additional_sel_set_pseudo:
140  * @a_this: the "this pointer" of the current instance
141  * of #CRAdditionalSel .
142  * @a_pseudo: the new pseudo to set.
143  *
144  * Sets a new pseudo to a
145  * PSEUDO additional selector.
146  */
147 void
cr_additional_sel_set_pseudo(CRAdditionalSel * a_this,CRPseudo * a_pseudo)148 cr_additional_sel_set_pseudo (CRAdditionalSel * a_this, CRPseudo * a_pseudo)
149 {
150         g_return_if_fail (a_this
151                           && a_this->type == PSEUDO_CLASS_ADD_SELECTOR);
152 
153         if (a_this->content.pseudo) {
154                 cr_pseudo_destroy (a_this->content.pseudo);
155         }
156 
157         a_this->content.pseudo = a_pseudo;
158 }
159 
160 /**
161  * cr_additional_sel_set_attr_sel:
162  * @a_this: the "this pointer" of the current instance
163  * of #CRAdditionalSel .
164  * @a_sel: the new instance of #CRAttrSel to set.
165  *
166  * Sets a new instance of #CRAttrSel to
167  * a ATTRIBUTE additional selector.
168  */
169 void
cr_additional_sel_set_attr_sel(CRAdditionalSel * a_this,CRAttrSel * a_sel)170 cr_additional_sel_set_attr_sel (CRAdditionalSel * a_this, CRAttrSel * a_sel)
171 {
172         g_return_if_fail (a_this && a_this->type == ATTRIBUTE_ADD_SELECTOR);
173 
174         if (a_this->content.attr_sel) {
175                 cr_attr_sel_destroy (a_this->content.attr_sel);
176         }
177 
178         a_this->content.attr_sel = a_sel;
179 }
180 
181 /**
182  * cr_additional_sel_append:
183  * @a_this: the "this pointer" of the current instance
184  * of #CRAdditionalSel .
185  * @a_sel: the new instance to #CRAdditional to append.
186  *
187  * Appends a new instance of #CRAdditional to the
188  * current list of #CRAdditional.
189  *
190  * Returns the new list of CRAdditionalSel or NULL if an error arises.
191  */
192 CRAdditionalSel *
cr_additional_sel_append(CRAdditionalSel * a_this,CRAdditionalSel * a_sel)193 cr_additional_sel_append (CRAdditionalSel * a_this, CRAdditionalSel * a_sel)
194 {
195         CRAdditionalSel *cur_sel = NULL;
196 
197         g_return_val_if_fail (a_sel, NULL);
198 
199         if (a_this == NULL) {
200                 return a_sel;
201         }
202 
203         if (a_sel == NULL)
204                 return NULL;
205 
206         for (cur_sel = a_this;
207              cur_sel && cur_sel->next; cur_sel = cur_sel->next) ;
208 
209         g_return_val_if_fail (cur_sel != NULL, NULL);
210 
211         cur_sel->next = a_sel;
212         a_sel->prev = cur_sel;
213 
214         return a_this;
215 }
216 
217 /**
218  * cr_additional_sel_prepend:
219  * @a_this: the "this pointer" of the current instance
220  * of #CRAdditionalSel .
221  * @a_sel: the new instance to #CRAdditional to preappend.
222  *
223  * Preppends a new instance of #CRAdditional to the
224  * current list of #CRAdditional.
225  *
226  * Returns the new list of CRAdditionalSel or NULL if an error arises.
227  */
228 CRAdditionalSel *
cr_additional_sel_prepend(CRAdditionalSel * a_this,CRAdditionalSel * a_sel)229 cr_additional_sel_prepend (CRAdditionalSel * a_this, CRAdditionalSel * a_sel)
230 {
231         g_return_val_if_fail (a_sel, NULL);
232 
233         if (a_this == NULL) {
234                 return a_sel;
235         }
236 
237         a_sel->next = a_this;
238         a_this->prev = a_sel;
239 
240         return a_sel;
241 }
242 
243 guchar *
cr_additional_sel_to_string(CRAdditionalSel const * a_this)244 cr_additional_sel_to_string (CRAdditionalSel const * a_this)
245 {
246         guchar *result = NULL;
247         GString *str_buf = NULL;
248         CRAdditionalSel const *cur = NULL;
249 
250         g_return_val_if_fail (a_this, NULL);
251 
252         str_buf = g_string_new (NULL);
253 
254         for (cur = a_this; cur; cur = cur->next) {
255                 switch (cur->type) {
256                 case CLASS_ADD_SELECTOR:
257                         {
258                                 guchar *name = NULL;
259 
260                                 if (cur->content.class_name) {
261                                         name = (guchar *) g_strndup
262                                                 (cur->content.class_name->stryng->str,
263                                                  cur->content.class_name->stryng->len);
264 
265                                         if (name) {
266                                                 g_string_append_printf
267                                                         (str_buf, ".%s",
268                                                          name);
269                                                 g_free (name);
270                                                 name = NULL;
271                                         }
272                                 }
273                         }
274                         break;
275 
276                 case ID_ADD_SELECTOR:
277                         {
278                                 guchar *name = NULL;
279 
280                                 if (cur->content.id_name) {
281                                         name = (guchar *) g_strndup
282                                                 (cur->content.id_name->stryng->str,
283                                                  cur->content.id_name->stryng->len);
284 
285                                         if (name) {
286                                                 g_string_append_printf
287                                                         (str_buf, "#%s",
288                                                          name);
289                                                 g_free (name);
290                                                 name = NULL;
291                                         }
292                                 }
293                         }
294 
295                         break;
296 
297                 case PSEUDO_CLASS_ADD_SELECTOR:
298                         {
299                                 if (cur->content.pseudo) {
300                                         guchar *tmp_str = NULL;
301 
302                                         tmp_str = cr_pseudo_to_string
303                                                 (cur->content.pseudo);
304                                         if (tmp_str) {
305                                                 g_string_append_printf
306                                                         (str_buf, ":%s",
307                                                          tmp_str);
308                                                 g_free (tmp_str);
309                                                 tmp_str = NULL;
310                                         }
311                                 }
312                         }
313                         break;
314 
315                 case ATTRIBUTE_ADD_SELECTOR:
316                         if (cur->content.attr_sel) {
317                                 guchar *tmp_str = NULL;
318 
319                                 g_string_append_c (str_buf, '[');
320                                 tmp_str = cr_attr_sel_to_string
321                                         (cur->content.attr_sel);
322                                 if (tmp_str) {
323                                         g_string_append_printf
324                                                 (str_buf, "%s]", tmp_str);
325                                         g_free (tmp_str);
326                                         tmp_str = NULL;
327                                 }
328                         }
329                         break;
330 
331                 default:
332                         break;
333                 }
334         }
335 
336         if (str_buf) {
337                 result = (guchar *) str_buf->str;
338                 g_string_free (str_buf, FALSE);
339                 str_buf = NULL;
340         }
341 
342         return result;
343 }
344 
345 guchar *
cr_additional_sel_one_to_string(CRAdditionalSel const * a_this)346 cr_additional_sel_one_to_string (CRAdditionalSel const *a_this)
347 {
348         guchar *result = NULL;
349         GString *str_buf = NULL;
350 
351         g_return_val_if_fail (a_this, NULL) ;
352 
353         str_buf = g_string_new (NULL) ;
354 
355         switch (a_this->type) {
356         case CLASS_ADD_SELECTOR:
357         {
358                 guchar *name = NULL;
359 
360                 if (a_this->content.class_name) {
361                         name = (guchar *) g_strndup
362                                 (a_this->content.class_name->stryng->str,
363                                  a_this->content.class_name->stryng->len);
364 
365                         if (name) {
366                                 g_string_append_printf
367                                         (str_buf, ".%s",
368                                          name);
369                                 g_free (name);
370                                 name = NULL;
371                         }
372                 }
373         }
374         break;
375 
376         case ID_ADD_SELECTOR:
377         {
378                 guchar *name = NULL;
379 
380                 if (a_this->content.id_name) {
381                         name = (guchar *) g_strndup
382                                 (a_this->content.id_name->stryng->str,
383                                  a_this->content.id_name->stryng->len);
384 
385                         if (name) {
386                                 g_string_append_printf
387                                         (str_buf, "#%s",
388                                          name);
389                                 g_free (name);
390                                 name = NULL;
391                         }
392                 }
393         }
394 
395         break;
396 
397         case PSEUDO_CLASS_ADD_SELECTOR:
398         {
399                 if (a_this->content.pseudo) {
400                         guchar *tmp_str = NULL;
401 
402                         tmp_str = cr_pseudo_to_string
403                                 (a_this->content.pseudo);
404                         if (tmp_str) {
405                                 g_string_append_printf
406                                         (str_buf, ":%s",
407                                          tmp_str);
408                                 g_free (tmp_str);
409                                 tmp_str = NULL;
410                         }
411                 }
412         }
413         break;
414 
415         case ATTRIBUTE_ADD_SELECTOR:
416                 if (a_this->content.attr_sel) {
417                         guchar *tmp_str = NULL;
418 
419                         g_string_append_printf (str_buf, "[");
420                         tmp_str = cr_attr_sel_to_string
421                                 (a_this->content.attr_sel);
422                         if (tmp_str) {
423                                 g_string_append_printf
424                                         (str_buf, "%s]", tmp_str);
425                                 g_free (tmp_str);
426                                 tmp_str = NULL;
427                         }
428                 }
429                 break;
430 
431         default:
432                 break;
433         }
434 
435         if (str_buf) {
436                 result = (guchar *) str_buf->str;
437                 g_string_free (str_buf, FALSE);
438                 str_buf = NULL;
439         }
440 
441         return result;
442 }
443 
444 /**
445  * cr_additional_sel_dump:
446  * @a_this: the "this pointer" of the current instance of
447  * #CRAdditionalSel.
448  * @a_fp: the destination file.
449  *
450  * Dumps the current instance of #CRAdditionalSel to a file
451  */
452 void
cr_additional_sel_dump(CRAdditionalSel const * a_this,FILE * a_fp)453 cr_additional_sel_dump (CRAdditionalSel const * a_this, FILE * a_fp)
454 {
455         guchar *tmp_str = NULL;
456 
457         g_return_if_fail (a_fp);
458 
459         if (a_this) {
460                 tmp_str = cr_additional_sel_to_string (a_this);
461                 if (tmp_str) {
462                         fprintf (a_fp, "%s", tmp_str);
463                         g_free (tmp_str);
464                         tmp_str = NULL;
465                 }
466         }
467 }
468 
469 /**
470  * cr_additional_sel_destroy:
471  * @a_this: the "this pointer" of the current instance
472  * of #CRAdditionalSel .
473  *
474  * Destroys an instance of #CRAdditional.
475  */
476 void
cr_additional_sel_destroy(CRAdditionalSel * a_this)477 cr_additional_sel_destroy (CRAdditionalSel * a_this)
478 {
479         g_return_if_fail (a_this);
480 
481         switch (a_this->type) {
482         case CLASS_ADD_SELECTOR:
483                 cr_string_destroy (a_this->content.class_name);
484                 a_this->content.class_name = NULL;
485                 break;
486 
487         case PSEUDO_CLASS_ADD_SELECTOR:
488                 cr_pseudo_destroy (a_this->content.pseudo);
489                 a_this->content.pseudo = NULL;
490                 break;
491 
492         case ID_ADD_SELECTOR:
493                 cr_string_destroy (a_this->content.id_name);
494                 a_this->content.id_name = NULL;
495                 break;
496 
497         case ATTRIBUTE_ADD_SELECTOR:
498                 cr_attr_sel_destroy (a_this->content.attr_sel);
499                 a_this->content.attr_sel = NULL;
500                 break;
501 
502         default:
503                 break;
504         }
505 
506         if (a_this->next) {
507                 cr_additional_sel_destroy (a_this->next);
508         }
509 
510         g_free (a_this);
511 }
512