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
32 #include <config.h>
33 #include <string.h>
34 #include "cr-selector.h"
35 #include "cr-parser.h"
36
37 /**
38 * cr_selector_new:
39 *
40 *@a_simple_sel: the initial simple selector list
41 *of the current instance of #CRSelector.
42 *
43 *Creates a new instance of #CRSelector.
44 *
45 *Returns the newly built instance of #CRSelector, or
46 *NULL in case of failure.
47 */
48 CRSelector *
cr_selector_new(CRSimpleSel * a_simple_sel)49 cr_selector_new (CRSimpleSel * a_simple_sel)
50 {
51 CRSelector *result = NULL;
52
53 result = g_try_malloc (sizeof (CRSelector));
54 if (!result) {
55 cr_utils_trace_info ("Out of memory");
56 return NULL;
57 }
58 memset (result, 0, sizeof (CRSelector));
59 result->simple_sel = a_simple_sel;
60 return result;
61 }
62
63 CRSelector *
cr_selector_parse_from_buf(const guchar * a_char_buf,enum CREncoding a_enc)64 cr_selector_parse_from_buf (const guchar * a_char_buf, enum CREncoding a_enc)
65 {
66 CRParser *parser = NULL;
67
68 g_return_val_if_fail (a_char_buf, NULL);
69
70 parser = cr_parser_new_from_buf ((guchar*)a_char_buf, strlen ((const char *) a_char_buf),
71 a_enc, FALSE);
72 g_return_val_if_fail (parser, NULL);
73
74 return NULL;
75 }
76
77 /**
78 * cr_selector_append:
79 *
80 *@a_this: the current instance of #CRSelector.
81 *@a_new: the instance of #CRSelector to be appended.
82 *
83 *Appends a new instance of #CRSelector to the current selector list.
84 *
85 *Returns the new list.
86 */
87 CRSelector *
cr_selector_append(CRSelector * a_this,CRSelector * a_new)88 cr_selector_append (CRSelector * a_this, CRSelector * a_new)
89 {
90 CRSelector *cur = NULL;
91
92 if (!a_this) {
93 return a_new;
94 }
95
96 /*walk forward the list headed by a_this to get the list tail */
97 for (cur = a_this; cur && cur->next; cur = cur->next) ;
98
99 cur->next = a_new;
100 a_new->prev = cur;
101
102 return a_this;
103 }
104
105 /**
106 * cr_selector_prepend:
107 *
108 *@a_this: the current instance of #CRSelector list.
109 *@a_new: the instance of #CRSelector.
110 *
111 *Prepends an element to the #CRSelector list.
112 *
113 *Returns the new list.
114 */
115 CRSelector *
cr_selector_prepend(CRSelector * a_this,CRSelector * a_new)116 cr_selector_prepend (CRSelector * a_this, CRSelector * a_new)
117 {
118 CRSelector *cur = NULL;
119
120 a_new->next = a_this;
121 a_this->prev = a_new;
122
123 for (cur = a_new; cur && cur->prev; cur = cur->prev) ;
124
125 return cur;
126 }
127
128 /**
129 * cr_selector_append_simple_sel:
130 *
131 *@a_this: the current instance of #CRSelector.
132 *@a_simple_sel: the simple selector to append.
133 *
134 *append a simple selector to the current #CRSelector list.
135 *
136 *Returns the new list or NULL in case of failure.
137 */
138 CRSelector *
cr_selector_append_simple_sel(CRSelector * a_this,CRSimpleSel * a_simple_sel)139 cr_selector_append_simple_sel (CRSelector * a_this,
140 CRSimpleSel * a_simple_sel)
141 {
142 CRSelector *selector = NULL;
143
144 selector = cr_selector_new (a_simple_sel);
145 g_return_val_if_fail (selector, NULL);
146
147 return cr_selector_append (a_this, selector);
148 }
149
150 guchar *
cr_selector_to_string(CRSelector const * a_this)151 cr_selector_to_string (CRSelector const * a_this)
152 {
153 guchar *result = NULL;
154 GString *str_buf = NULL;
155
156 str_buf = g_string_new (NULL);
157 g_return_val_if_fail (str_buf, NULL);
158
159 if (a_this) {
160 CRSelector const *cur = NULL;
161
162 for (cur = a_this; cur; cur = cur->next) {
163 if (cur->simple_sel) {
164 guchar *tmp_str = NULL;
165
166 tmp_str = cr_simple_sel_to_string
167 (cur->simple_sel);
168
169 if (tmp_str) {
170 if (cur->prev)
171 g_string_append (str_buf,
172 ", ");
173
174 g_string_append (str_buf, (const gchar *) tmp_str);
175
176 g_free (tmp_str);
177 tmp_str = NULL;
178 }
179 }
180 }
181 }
182
183 if (str_buf) {
184 result = (guchar *) str_buf->str;
185 g_string_free (str_buf, FALSE);
186 str_buf = NULL;
187 }
188
189 return result;
190 }
191
192 /**
193 * cr_selector_dump:
194 *
195 *@a_this: the current instance of #CRSelector.
196 *@a_fp: the destination file.
197 *
198 *Serializes the current instance of #CRSelector to a file.
199 */
200 void
cr_selector_dump(CRSelector const * a_this,FILE * a_fp)201 cr_selector_dump (CRSelector const * a_this, FILE * a_fp)
202 {
203 guchar *tmp_buf = NULL;
204
205 if (a_this) {
206 tmp_buf = cr_selector_to_string (a_this);
207 if (tmp_buf) {
208 fprintf (a_fp, "%s", tmp_buf);
209 g_free (tmp_buf);
210 tmp_buf = NULL;
211 }
212 }
213 }
214
215 /**
216 * cr_selector_ref:
217 *
218 *@a_this: the current instance of #CRSelector.
219 *
220 *Increments the ref count of the current instance
221 *of #CRSelector.
222 */
223 void
cr_selector_ref(CRSelector * a_this)224 cr_selector_ref (CRSelector * a_this)
225 {
226 g_return_if_fail (a_this);
227
228 a_this->ref_count++;
229 }
230
231 /**
232 * cr_selector_unref:
233 *
234 *@a_this: the current instance of #CRSelector.
235 *
236 *Decrements the ref count of the current instance of
237 *#CRSelector.
238 *If the ref count reaches zero, the current instance of
239 *#CRSelector is destroyed.
240 *
241 *Returns TRUE if this function destroyed the current instance
242 *of #CRSelector, FALSE otherwise.
243 */
244 gboolean
cr_selector_unref(CRSelector * a_this)245 cr_selector_unref (CRSelector * a_this)
246 {
247 g_return_val_if_fail (a_this, FALSE);
248
249 if (a_this->ref_count) {
250 a_this->ref_count--;
251 }
252
253 if (a_this->ref_count == 0) {
254 cr_selector_destroy (a_this);
255 return TRUE;
256 }
257
258 return FALSE;
259 }
260
261 /**
262 * cr_selector_destroy:
263 *
264 *@a_this: the current instance of #CRSelector.
265 *
266 *Destroys the selector list.
267 */
268 void
cr_selector_destroy(CRSelector * a_this)269 cr_selector_destroy (CRSelector * a_this)
270 {
271 CRSelector *cur = NULL;
272
273 g_return_if_fail (a_this);
274
275 /*
276 *go and get the list tail. In the same time, free
277 *all the simple selectors contained in the list.
278 */
279 for (cur = a_this; cur && cur->next; cur = cur->next) {
280 if (cur->simple_sel) {
281 cr_simple_sel_destroy (cur->simple_sel);
282 cur->simple_sel = NULL;
283 }
284 }
285
286 if (cur) {
287 if (cur->simple_sel) {
288 cr_simple_sel_destroy (cur->simple_sel);
289 cur->simple_sel = NULL;
290 }
291 }
292
293 /*in case the list has only one element */
294 if (cur && !cur->prev) {
295 g_free (cur);
296 return;
297 }
298
299 /*walk backward the list and free each "next element" */
300 for (cur = cur->prev; cur && cur->prev; cur = cur->prev) {
301 if (cur->next) {
302 g_free (cur->next);
303 cur->next = NULL;
304 }
305 }
306
307 if (!cur)
308 return;
309
310 if (cur->next) {
311 g_free (cur->next);
312 cur->next = NULL;
313 }
314
315 g_free (cur);
316 }
317