Imported Upstream version 0.18.1.1
[platform/upstream/gettext.git] / gnulib-local / lib / libcroco / cr-simple-sel.c
1 /* -*- Mode: C; indent-tabs-mode:nil; c-basic-offset: 8-*- */
2
3 /*
4  * This file is part of The Croco Library
5  *
6  * This program is free software; you can redistribute it and/or
7  * modify it under the terms of version 2.1 of the GNU Lesser General Public
8  * License as published by the Free Software Foundation.
9  *
10  * This program is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13  * GNU General Public License for more details.
14  *
15  * You should have received a copy of the GNU Lesser General Public License
16  * along with this program; if not, write to the Free Software
17  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
18  * USA
19  *
20  * Author: Dodji Seketeli
21  * See COPYRIGHTS file for copyright information.
22  */
23
24 #include <config.h>
25 #include <string.h>
26 #include <glib.h>
27 #include "cr-simple-sel.h"
28
29 /**
30  * cr_simple_sel_new:
31  *
32  *The constructor of #CRSimpleSel.
33  *
34  *Returns the new instance of #CRSimpleSel.
35  */
36 CRSimpleSel *
37 cr_simple_sel_new (void)
38 {
39         CRSimpleSel *result = NULL;
40
41         result = g_try_malloc (sizeof (CRSimpleSel));
42         if (!result) {
43                 cr_utils_trace_info ("Out of memory");
44                 return NULL;
45         }
46         memset (result, 0, sizeof (CRSimpleSel));
47
48         return result;
49 }
50
51 /**
52  * cr_simple_sel_append_simple_sel:
53  *
54  *Appends a simpe selector to the current list of simple selector.
55  *
56  *@a_this: the this pointer of the current instance of #CRSimpleSel.
57  *@a_sel: the simple selector to append.
58  *Returns: the new list upon successfull completion, an error code otherwise.
59  */
60 CRSimpleSel *
61 cr_simple_sel_append_simple_sel (CRSimpleSel * a_this, CRSimpleSel * a_sel)
62 {
63         CRSimpleSel *cur = NULL;
64
65         g_return_val_if_fail (a_sel, NULL);
66
67         if (a_this == NULL)
68                 return a_sel;
69
70         for (cur = a_this; cur->next; cur = cur->next) ;
71
72         cur->next = a_sel;
73         a_sel->prev = cur;
74
75         return a_this;
76 }
77
78 /**
79  * cr_simple_sel_prepend_simple_sel:
80  *
81  *@a_this: the this pointer of the current instance of #CRSimpleSel.
82  *@a_sel: the simple selector to prepend.
83  *
84  *Prepends a simple selector to the current list of simple selectors.
85  *
86  *Returns the new list upon successfull completion, an error code otherwise.
87  */
88 CRSimpleSel *
89 cr_simple_sel_prepend_simple_sel (CRSimpleSel * a_this, CRSimpleSel * a_sel)
90 {
91         g_return_val_if_fail (a_sel, NULL);
92
93         if (a_this == NULL)
94                 return a_sel;
95
96         a_sel->next = a_this;
97         a_this->prev = a_sel;
98
99         return a_sel;
100 }
101
102 guchar *
103 cr_simple_sel_to_string (CRSimpleSel * a_this)
104 {
105         GString *str_buf = NULL;
106         guchar *result = NULL;
107
108         CRSimpleSel *cur = NULL;
109
110         g_return_val_if_fail (a_this, NULL);
111
112         str_buf = g_string_new (NULL);
113         for (cur = a_this; cur; cur = cur->next) {
114                 if (cur->name) {
115                         guchar *str = g_strndup (cur->name->stryng->str,
116                                                  cur->name->stryng->len);
117
118                         if (str) {
119                                 switch (cur->combinator) {
120                                 case COMB_WS:
121                                         g_string_append (str_buf, " ");
122                                         break;
123
124                                 case COMB_PLUS:
125                                         g_string_append (str_buf, "+");
126                                         break;
127
128                                 case COMB_GT:
129                                         g_string_append (str_buf, ">");
130                                         break;
131
132                                 default:
133                                         break;
134                                 }
135
136                                 g_string_append (str_buf, str);
137                                 g_free (str);
138                                 str = NULL;
139                         }
140                 }
141
142                 if (cur->add_sel) {
143                         guchar *tmp_str = NULL;
144
145                         tmp_str = cr_additional_sel_to_string (cur->add_sel);
146                         if (tmp_str) {
147                                 g_string_append (str_buf, tmp_str);
148                                 g_free (tmp_str);
149                                 tmp_str = NULL;
150                         }
151                 }
152         }
153
154         if (str_buf) {
155                 result = str_buf->str;
156                 g_string_free (str_buf, FALSE);
157                 str_buf = NULL;
158         }
159
160         return result;
161 }
162
163
164 guchar *
165 cr_simple_sel_one_to_string (CRSimpleSel * a_this)
166 {
167         GString *str_buf = NULL;
168         guchar *result = NULL;
169
170         g_return_val_if_fail (a_this, NULL);
171
172         str_buf = g_string_new (NULL);
173         if (a_this->name) {
174                 guchar *str = g_strndup (a_this->name->stryng->str,
175                                          a_this->name->stryng->len);
176
177                 if (str) {
178                         g_string_append_printf (str_buf, "%s", str);
179                         g_free (str);
180                         str = NULL;
181                 }
182         }
183
184         if (a_this->add_sel) {
185                 guchar *tmp_str = NULL;
186
187                 tmp_str = cr_additional_sel_to_string (a_this->add_sel);
188                 if (tmp_str) {
189                         g_string_append_printf
190                                 (str_buf, "%s", tmp_str);
191                         g_free (tmp_str);
192                         tmp_str = NULL;
193                 }
194         }
195
196         if (str_buf) {
197                 result = str_buf->str;
198                 g_string_free (str_buf, FALSE);
199                 str_buf = NULL;
200         }
201
202         return result;
203 }
204
205 /**
206  * cr_simple_sel_dump:
207  *@a_this: the current instance of #CRSimpleSel.
208  *@a_fp: the destination file pointer.
209  *
210  *Dumps the selector to a file.
211  *TODO: add the support of unicode in the dump.
212  *
213  *Returns CR_OK upon successfull completion, an error code
214  *otherwise.
215  */
216 enum CRStatus
217 cr_simple_sel_dump (CRSimpleSel * a_this, FILE * a_fp)
218 {
219         guchar *tmp_str = NULL;
220
221         g_return_val_if_fail (a_fp, CR_BAD_PARAM_ERROR);
222
223         if (a_this) {
224                 tmp_str = cr_simple_sel_to_string (a_this);
225                 if (tmp_str) {
226                         fprintf (a_fp, "%s", tmp_str);
227                         g_free (tmp_str);
228                         tmp_str = NULL;
229                 }
230         }
231
232         return CR_OK;
233 }
234
235 /**
236  * cr_simple_sel_compute_specificity:
237  *
238  *@a_this: the current instance of #CRSimpleSel
239  *
240  *Computes the selector (combinator separated list of simple selectors)
241  *as defined in the css2 spec in chapter 6.4.3
242  *
243  *Returns CR_OK upon successfull completion, an error code otherwise.
244  */
245 enum CRStatus
246 cr_simple_sel_compute_specificity (CRSimpleSel * a_this)
247 {
248         CRAdditionalSel *cur_add_sel = NULL;
249         CRSimpleSel *cur_sel = NULL;
250         gulong a = 0,
251                 b = 0,
252                 c = 0;
253
254         g_return_val_if_fail (a_this, CR_BAD_PARAM_ERROR);
255
256         for (cur_sel = a_this; cur_sel; cur_sel = cur_sel->next) {
257                 if (cur_sel->type_mask | TYPE_SELECTOR) {
258                         c++;    /*hmmh, is this a new language ? */
259                 } else if (!cur_sel->name 
260                            || !cur_sel->name->stryng
261                            || !cur_sel->name->stryng->str) {
262                         if (cur_sel->add_sel->type ==
263                             PSEUDO_CLASS_ADD_SELECTOR) {
264                                 /*
265                                  *this is a pseudo element, and
266                                  *the spec says, "ignore pseudo elements".
267                                  */
268                                 continue;
269                         }
270                 }
271
272                 for (cur_add_sel = cur_sel->add_sel;
273                      cur_add_sel; cur_add_sel = cur_add_sel->next) {
274                         switch (cur_add_sel->type) {
275                         case ID_ADD_SELECTOR:
276                                 a++;
277                                 break;
278
279                         case NO_ADD_SELECTOR:
280                                 continue;
281
282                         default:
283                                 b++;
284                                 break;
285                         }
286                 }
287         }
288
289         /*we suppose a, b and c have 1 to 3 digits */
290         a_this->specificity = a * 1000000 + b * 1000 + c;
291
292         return CR_OK;
293 }
294
295 /**
296  * cr_simple_sel_destroy:
297  *
298  *@a_this: the this pointer of the current instance of #CRSimpleSel.
299  *
300  *The destructor of the current instance of
301  *#CRSimpleSel.
302  */
303 void
304 cr_simple_sel_destroy (CRSimpleSel * a_this)
305 {
306         g_return_if_fail (a_this);
307
308         if (a_this->name) {
309                 cr_string_destroy (a_this->name);
310                 a_this->name = NULL;
311         }
312
313         if (a_this->add_sel) {
314                 cr_additional_sel_destroy (a_this->add_sel);
315                 a_this->add_sel = NULL;
316         }
317
318         if (a_this->next) {
319                 cr_simple_sel_destroy (a_this->next);
320         }
321
322         if (a_this) {
323                 g_free (a_this);
324         }
325 }