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
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