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