1 /* libcroco - Library for parsing and applying CSS
2 * Copyright (C) 2006-2019 Free Software Foundation, Inc.
3 *
4 * This file is not part of the GNU gettext program, but is used with
5 * GNU gettext.
6 *
7 * The original copyright notice is as follows:
8 */
9
10 /*
11 * This file is part of The Croco Library
12 *
13 * Copyright (C) 2003-2004 Dodji Seketeli. All Rights Reserved.
14 *
15 * This program is free software; you can redistribute it and/or
16 * modify it under the terms of version 2.1 of the GNU Lesser General Public
17 * License as published by the Free Software Foundation.
18 *
19 * This program is distributed in the hope that it will be useful,
20 * but WITHOUT ANY WARRANTY; without even the implied warranty of
21 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
22 * GNU General Public License for more details.
23 *
24 * You should have received a copy of the GNU Lesser General Public License
25 * along with this program; if not, write to the Free Software
26 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
27 * USA
28 *
29 * Author: Dodji Seketeli
30 */
31
32 #include <config.h>
33 #include <string.h>
34 #include "cr-prop-list.h"
35
36 #define PRIVATE(a_obj) (a_obj)->priv
37
38 struct _CRPropListPriv {
39 CRString *prop;
40 CRDeclaration *decl;
41 CRPropList *next;
42 CRPropList *prev;
43 };
44
45 static CRPropList *cr_prop_list_allocate (void);
46
47 /**
48 *Default allocator of CRPropList
49 *@return the newly allocated CRPropList or NULL
50 *if an error arises.
51 */
52 static CRPropList *
cr_prop_list_allocate(void)53 cr_prop_list_allocate (void)
54 {
55 CRPropList *result = NULL;
56
57 result = g_try_malloc (sizeof (CRPropList));
58 if (!result) {
59 cr_utils_trace_info ("could not allocate CRPropList");
60 return NULL;
61 }
62 memset (result, 0, sizeof (CRPropList));
63 PRIVATE (result) = g_try_malloc (sizeof (CRPropListPriv));
64 if (!result) {
65 cr_utils_trace_info ("could not allocate CRPropListPriv");
66 g_free (result);
67 return NULL;
68 }
69 memset (PRIVATE (result), 0, sizeof (CRPropListPriv));
70 return result;
71 }
72
73 /****************
74 *public methods
75 ***************/
76
77 /**
78 * cr_prop_list_append:
79 *@a_this: the current instance of #CRPropList
80 *@a_to_append: the property list to append
81 *
82 *Appends a property list to the current one.
83 *
84 *Returns the resulting prop list, or NULL if an error
85 *occurred
86 */
87 CRPropList *
cr_prop_list_append(CRPropList * a_this,CRPropList * a_to_append)88 cr_prop_list_append (CRPropList * a_this, CRPropList * a_to_append)
89 {
90 CRPropList *cur = NULL;
91
92 g_return_val_if_fail (a_to_append, NULL);
93
94 if (!a_this)
95 return a_to_append;
96
97 /*go fetch the last element of the list */
98 for (cur = a_this;
99 cur && PRIVATE (cur) && PRIVATE (cur)->next;
100 cur = PRIVATE (cur)->next) ;
101 g_return_val_if_fail (cur, NULL);
102 PRIVATE (cur)->next = a_to_append;
103 PRIVATE (a_to_append)->prev = cur;
104 return a_this;
105 }
106
107 /**
108 * cr_prop_list_append2:
109 *Appends a pair of prop/declaration to
110 *the current prop list.
111 *@a_this: the current instance of #CRPropList
112 *@a_prop: the property to consider
113 *@a_decl: the declaration to consider
114 *
115 *Returns the resulting property list, or NULL in case
116 *of an error.
117 */
118 CRPropList *
cr_prop_list_append2(CRPropList * a_this,CRString * a_prop,CRDeclaration * a_decl)119 cr_prop_list_append2 (CRPropList * a_this,
120 CRString * a_prop,
121 CRDeclaration * a_decl)
122 {
123 CRPropList *list = NULL,
124 *result = NULL;
125
126 g_return_val_if_fail (a_prop && a_decl, NULL);
127
128 list = cr_prop_list_allocate ();
129 g_return_val_if_fail (list && PRIVATE (list), NULL);
130
131 PRIVATE (list)->prop = a_prop;
132 PRIVATE (list)->decl = a_decl;
133
134 result = cr_prop_list_append (a_this, list);
135 return result;
136 }
137
138 /**
139 * cr_prop_list_prepend:
140 *@a_this: the current instance of #CRPropList
141 *@a_to_prepend: the new list to prepend.
142 *
143 *Prepends a list to the current list
144 *Returns the new properties list.
145 */
146 CRPropList *
cr_prop_list_prepend(CRPropList * a_this,CRPropList * a_to_prepend)147 cr_prop_list_prepend (CRPropList * a_this, CRPropList * a_to_prepend)
148 {
149 CRPropList *cur = NULL;
150
151 g_return_val_if_fail (a_to_prepend, NULL);
152
153 if (!a_this)
154 return a_to_prepend;
155
156 for (cur = a_to_prepend; cur && PRIVATE (cur)->next;
157 cur = PRIVATE (cur)->next) ;
158 g_return_val_if_fail (cur, NULL);
159 PRIVATE (cur)->next = a_this;
160 PRIVATE (a_this)->prev = cur;
161 return a_to_prepend;
162 }
163
164 /**
165 * cr_prop_list_prepend2:
166 *@a_this: the current instance of #CRPropList
167 *@a_prop_name: property name to append
168 *@a_decl: the property value to append.
169 *
170 *Prepends a propertie to a list of properties
171 *
172 *Returns the new property list.
173 */
174 CRPropList *
cr_prop_list_prepend2(CRPropList * a_this,CRString * a_prop_name,CRDeclaration * a_decl)175 cr_prop_list_prepend2 (CRPropList * a_this,
176 CRString * a_prop_name, CRDeclaration * a_decl)
177 {
178 CRPropList *list = NULL,
179 *result = NULL;
180
181 g_return_val_if_fail (a_this && PRIVATE (a_this)
182 && a_prop_name && a_decl, NULL);
183
184 list = cr_prop_list_allocate ();
185 g_return_val_if_fail (list, NULL);
186 PRIVATE (list)->prop = a_prop_name;
187 PRIVATE (list)->decl = a_decl;
188 result = cr_prop_list_prepend (a_this, list);
189 return result;
190 }
191
192 /**
193 * cr_prop_list_set_prop:
194 *@a_this: the current instance of #CRPropList
195 *@a_prop: the property to set
196 *
197 *Sets the property of a CRPropList
198 */
199 enum CRStatus
cr_prop_list_set_prop(CRPropList * a_this,CRString * a_prop)200 cr_prop_list_set_prop (CRPropList * a_this, CRString * a_prop)
201 {
202 g_return_val_if_fail (a_this && PRIVATE (a_this)
203 && a_prop, CR_BAD_PARAM_ERROR);
204
205 PRIVATE (a_this)->prop = a_prop;
206 return CR_OK;
207 }
208
209 /**
210 * cr_prop_list_get_prop:
211 *@a_this: the current instance of #CRPropList
212 *@a_prop: out parameter. The returned property
213 *
214 *Getter of the property associated to the current instance
215 *of #CRPropList
216 *
217 *Returns CR_OK upon successful completion, an error code
218 *otherwise.
219 */
220 enum CRStatus
cr_prop_list_get_prop(CRPropList const * a_this,CRString ** a_prop)221 cr_prop_list_get_prop (CRPropList const * a_this, CRString ** a_prop)
222 {
223 g_return_val_if_fail (a_this && PRIVATE (a_this)
224 && a_prop, CR_BAD_PARAM_ERROR);
225
226 *a_prop = PRIVATE (a_this)->prop;
227 return CR_OK;
228 }
229
230 /**
231 * cr_prop_list_set_decl:
232 * @a_this: the current instance of #CRPropList
233 * @a_decl: the new property value.
234 *
235 * Returns CR_OK upon successful completion, an error code otherwise.
236 */
237 enum CRStatus
cr_prop_list_set_decl(CRPropList * a_this,CRDeclaration * a_decl)238 cr_prop_list_set_decl (CRPropList * a_this, CRDeclaration * a_decl)
239 {
240 g_return_val_if_fail (a_this && PRIVATE (a_this)
241 && a_decl, CR_BAD_PARAM_ERROR);
242
243 PRIVATE (a_this)->decl = a_decl;
244 return CR_OK;
245 }
246
247 /**
248 * cr_prop_list_get_decl:
249 * @a_this: the current instance of #CRPropList
250 * @a_decl: out parameter. The property value
251 *
252 * Returns CR_OK upon successful completion.
253 */
254 enum CRStatus
cr_prop_list_get_decl(CRPropList const * a_this,CRDeclaration ** a_decl)255 cr_prop_list_get_decl (CRPropList const * a_this, CRDeclaration ** a_decl)
256 {
257 g_return_val_if_fail (a_this && PRIVATE (a_this)
258 && a_decl, CR_BAD_PARAM_ERROR);
259
260 *a_decl = PRIVATE (a_this)->decl;
261 return CR_OK;
262 }
263
264 /**
265 * cr_prop_list_lookup_prop:
266 *@a_this: the current instance of #CRPropList
267 *@a_prop: the property to lookup
268 *@a_prop_list: out parameter. The property/declaration
269 *pair found (if and only if the function returned code if CR_OK)
270 *
271 *Lookup a given property/declaration pair
272 *
273 *Returns CR_OK if a prop/decl pair has been found,
274 *CR_VALUE_NOT_FOUND_ERROR if not, or an error code if something
275 *bad happens.
276 */
277 enum CRStatus
cr_prop_list_lookup_prop(CRPropList * a_this,CRString * a_prop,CRPropList ** a_pair)278 cr_prop_list_lookup_prop (CRPropList * a_this,
279 CRString * a_prop, CRPropList ** a_pair)
280 {
281 CRPropList *cur = NULL;
282
283 g_return_val_if_fail (a_prop && a_pair, CR_BAD_PARAM_ERROR);
284
285 if (!a_this)
286 return CR_VALUE_NOT_FOUND_ERROR;
287
288 g_return_val_if_fail (PRIVATE (a_this), CR_BAD_PARAM_ERROR);
289
290 for (cur = a_this; cur; cur = PRIVATE (cur)->next) {
291 if (PRIVATE (cur)->prop
292 && PRIVATE (cur)->prop->stryng
293 && PRIVATE (cur)->prop->stryng->str
294 && a_prop->stryng
295 && a_prop->stryng->str
296 && !strcmp (PRIVATE (cur)->prop->stryng->str,
297 a_prop->stryng->str))
298 break;
299 }
300
301 if (cur) {
302 *a_pair = cur;
303 return CR_OK;
304 }
305
306 return CR_VALUE_NOT_FOUND_ERROR;
307 }
308
309 /**
310 * cr_prop_list_get_next:
311 *@a_this: the current instance of CRPropList
312 *
313 *Gets the next prop/decl pair in the list
314 *
315 *Returns the next prop/declaration pair of the list,
316 *or NULL if we reached end of list (or if an error occurs)
317 */
318 CRPropList *
cr_prop_list_get_next(CRPropList * a_this)319 cr_prop_list_get_next (CRPropList * a_this)
320 {
321 g_return_val_if_fail (a_this && PRIVATE (a_this), NULL);
322
323 return PRIVATE (a_this)->next;
324 }
325
326 /**
327 * cr_prop_list_get_prev:
328 *@a_this: the current instance of CRPropList
329 *
330 *Gets the previous prop/decl pair in the list
331 *
332 *Returns the previous prop/declaration pair of the list,
333 *or NULL if we reached end of list (or if an error occurs)
334 */
335 CRPropList *
cr_prop_list_get_prev(CRPropList * a_this)336 cr_prop_list_get_prev (CRPropList * a_this)
337 {
338 g_return_val_if_fail (a_this && PRIVATE (a_this), NULL);
339
340 return PRIVATE (a_this)->prev;
341 }
342
343 /**
344 * cr_prop_list_unlink:
345 *@a_this: the current list of prop/decl pairs
346 *@a_pair: the prop/decl pair to unlink.
347 *
348 *Unlinks a prop/decl pair from the list
349 *
350 *Returns the new list or NULL in case of an error.
351 */
352 CRPropList *
cr_prop_list_unlink(CRPropList * a_this,CRPropList * a_pair)353 cr_prop_list_unlink (CRPropList * a_this, CRPropList * a_pair)
354 {
355 CRPropList *prev = NULL,
356 *next = NULL;
357
358 g_return_val_if_fail (a_this && PRIVATE (a_this) && a_pair, NULL);
359
360 /*some sanity checks */
361 if (PRIVATE (a_pair)->next) {
362 next = PRIVATE (a_pair)->next;
363 g_return_val_if_fail (PRIVATE (next), NULL);
364 g_return_val_if_fail (PRIVATE (next)->prev == a_pair, NULL);
365 }
366 if (PRIVATE (a_pair)->prev) {
367 prev = PRIVATE (a_pair)->prev;
368 g_return_val_if_fail (PRIVATE (prev), NULL);
369 g_return_val_if_fail (PRIVATE (prev)->next == a_pair, NULL);
370 }
371 if (prev) {
372 PRIVATE (prev)->next = next;
373 }
374 if (next) {
375 PRIVATE (next)->prev = prev;
376 }
377 PRIVATE (a_pair)->prev = PRIVATE (a_pair)->next = NULL;
378 if (a_this == a_pair) {
379 if (next)
380 return next;
381 return NULL;
382 }
383 return a_this;
384 }
385
386 /**
387 * cr_prop_list_destroy:
388 * @a_this: the current instance of #CRPropList
389 */
390 void
cr_prop_list_destroy(CRPropList * a_this)391 cr_prop_list_destroy (CRPropList * a_this)
392 {
393 CRPropList *tail = NULL,
394 *cur = NULL;
395
396 g_return_if_fail (a_this && PRIVATE (a_this));
397
398 for (tail = a_this;
399 tail && PRIVATE (tail) && PRIVATE (tail)->next;
400 tail = cr_prop_list_get_next (tail)) ;
401 g_return_if_fail (tail);
402
403 cur = tail;
404
405 while (cur) {
406 tail = PRIVATE (cur)->prev;
407 if (tail && PRIVATE (tail))
408 PRIVATE (tail)->next = NULL;
409 PRIVATE (cur)->prev = NULL;
410 g_free (PRIVATE (cur));
411 PRIVATE (cur) = NULL;
412 g_free (cur);
413 cur = tail;
414 }
415 }
416