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 3 of the GNU 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 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