• Home
  • History
  • Annotate
  • Line#
  • Navigate
  • Raw
  • Download
  • only in /netgear-WNDR4500v2-V1.0.0.60_1.0.38/ap/gpl/timemachine/gettext-0.17/gettext-tools/gnulib-lib/libcroco/
1/* -*- Mode: C; indent-tabs-mode: ni; 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 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 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 "cr-declaration.h"
27#include "cr-statement.h"
28#include "cr-parser.h"
29
30/**
31 *@CRDeclaration:
32 *
33 *The definition of the #CRDeclaration class.
34 */
35
36/**
37 * dump:
38 *@a_this: the current instance of #CRDeclaration.
39 *@a_fp: the destination file pointer.
40 *@a_indent: the number of indentation white char.
41 *
42 *Dumps (serializes) one css declaration to a file.
43 */
44static void
45dump (CRDeclaration * a_this, FILE * a_fp, glong a_indent)
46{
47        guchar *str = NULL;
48
49        g_return_if_fail (a_this);
50
51        str = cr_declaration_to_string (a_this, a_indent);
52        if (str) {
53                fprintf (a_fp, "%s", str);
54                g_free (str);
55                str = NULL;
56        }
57}
58
59/**
60 * cr_declaration_new:
61 * @a_statement: the statement this declaration belongs to. can be NULL.
62 *@a_property: the property string of the declaration
63 *@a_value: the value expression of the declaration.
64 *Constructor of #CRDeclaration.
65 *
66 *Returns the newly built instance of #CRDeclaration, or NULL in
67 *case of error.
68 */
69CRDeclaration *
70cr_declaration_new (CRStatement * a_statement,
71                    CRString * a_property, CRTerm * a_value)
72{
73        CRDeclaration *result = NULL;
74
75        g_return_val_if_fail (a_property, NULL);
76
77        if (a_statement)
78                g_return_val_if_fail (a_statement
79                                      && ((a_statement->type == RULESET_STMT)
80                                          || (a_statement->type
81                                              == AT_FONT_FACE_RULE_STMT)
82                                          || (a_statement->type
83                                              == AT_PAGE_RULE_STMT)), NULL);
84
85        result = g_try_malloc (sizeof (CRDeclaration));
86        if (!result) {
87                cr_utils_trace_info ("Out of memory");
88                return NULL;
89        }
90        memset (result, 0, sizeof (CRDeclaration));
91        result->property = a_property;
92        result->value = a_value;
93
94        if (a_value) {
95                cr_term_ref (a_value);
96        }
97        result->parent_statement = a_statement;
98        return result;
99}
100
101/**
102 * cr_declaration_parse_from_buf:
103 *@a_statement: the parent css2 statement of this
104 *this declaration. Must be non NULL and of type
105 *RULESET_STMT (must be a ruleset).
106 *@a_str: the string that contains the statement.
107 *@a_enc: the encoding of a_str.
108 *
109 *Parses a text buffer that contains
110 *a css declaration.
111 *Returns the parsed declaration, or NULL in case of error.
112 */
113CRDeclaration *
114cr_declaration_parse_from_buf (CRStatement * a_statement,
115                               const guchar * a_str, enum CREncoding a_enc)
116{
117        enum CRStatus status = CR_OK;
118        CRTerm *value = NULL;
119        CRString *property = NULL;
120        CRDeclaration *result = NULL;
121        CRParser *parser = NULL;
122        gboolean important = FALSE;
123
124        g_return_val_if_fail (a_str, NULL);
125        if (a_statement)
126                g_return_val_if_fail (a_statement->type == RULESET_STMT,
127                                      NULL);
128
129        parser = cr_parser_new_from_buf ((guchar*)a_str, strlen (a_str), a_enc, FALSE);
130        g_return_val_if_fail (parser, NULL);
131
132        status = cr_parser_try_to_skip_spaces_and_comments (parser);
133        if (status != CR_OK)
134                goto cleanup;
135
136        status = cr_parser_parse_declaration (parser, &property,
137                                              &value, &important);
138        if (status != CR_OK || !property)
139                goto cleanup;
140
141        result = cr_declaration_new (a_statement, property, value);
142        if (result) {
143                property = NULL;
144                value = NULL;
145                result->important = important;
146        }
147
148      cleanup:
149
150        if (parser) {
151                cr_parser_destroy (parser);
152                parser = NULL;
153        }
154
155        if (property) {
156                cr_string_destroy (property);
157                property = NULL;
158        }
159
160        if (value) {
161                cr_term_destroy (value);
162                value = NULL;
163        }
164
165        return result;
166}
167
168/**
169 * cr_declaration_parse_list_from_buf:
170 *@a_str: the input buffer that contains the list of declaration to
171 *parse.
172 *@a_enc: the encoding of a_str
173 *
174 *Parses a ';' separated list of properties declaration.
175 *Returns the parsed list of declaration, NULL if parsing failed.
176 */
177CRDeclaration *
178cr_declaration_parse_list_from_buf (const guchar * a_str,
179                                    enum CREncoding a_enc)
180{
181
182        enum CRStatus status = CR_OK;
183        CRTerm *value = NULL;
184        CRString *property = NULL;
185        CRDeclaration *result = NULL,
186                *cur_decl = NULL;
187        CRParser *parser = NULL;
188        CRTknzr *tokenizer = NULL;
189        gboolean important = FALSE;
190
191        g_return_val_if_fail (a_str, NULL);
192
193        parser = cr_parser_new_from_buf ((guchar*)a_str, strlen (a_str), a_enc, FALSE);
194        g_return_val_if_fail (parser, NULL);
195        status = cr_parser_get_tknzr (parser, &tokenizer);
196        if (status != CR_OK || !tokenizer) {
197                if (status == CR_OK)
198                        status = CR_ERROR;
199                goto cleanup;
200        }
201        status = cr_parser_try_to_skip_spaces_and_comments (parser);
202        if (status != CR_OK)
203                goto cleanup;
204
205        status = cr_parser_parse_declaration (parser, &property,
206                                              &value, &important);
207        if (status != CR_OK || !property) {
208                if (status != CR_OK)
209                        status = CR_ERROR;
210                goto cleanup;
211        }
212        result = cr_declaration_new (NULL, property, value);
213        if (result) {
214                property = NULL;
215                value = NULL;
216                result->important = important;
217        }
218        /*now, go parse the other declarations */
219        for (;;) {
220                guint32 c = 0;
221
222                cr_parser_try_to_skip_spaces_and_comments (parser);
223                status = cr_tknzr_peek_char (tokenizer, &c);
224                if (status != CR_OK) {
225                        if (status == CR_END_OF_INPUT_ERROR)
226                                status = CR_OK;
227                        goto cleanup;
228                }
229                if (c == ';') {
230                        status = cr_tknzr_read_char (tokenizer, &c);
231                } else {
232                        break;
233                }
234                important = FALSE;
235                cr_parser_try_to_skip_spaces_and_comments (parser);
236                status = cr_parser_parse_declaration (parser, &property,
237                                                      &value, &important);
238                if (status != CR_OK || !property) {
239                        if (status == CR_END_OF_INPUT_ERROR) {
240                                status = CR_OK;
241                        }
242                        break;
243                }
244                cur_decl = cr_declaration_new (NULL, property, value);
245                if (cur_decl) {
246                        cur_decl->important = important;
247                        result = cr_declaration_append (result, cur_decl);
248                        property = NULL;
249                        value = NULL;
250                        cur_decl = NULL;
251                } else {
252                        break;
253                }
254        }
255
256      cleanup:
257
258        if (parser) {
259                cr_parser_destroy (parser);
260                parser = NULL;
261        }
262
263        if (property) {
264                cr_string_destroy (property);
265                property = NULL;
266        }
267
268        if (value) {
269                cr_term_destroy (value);
270                value = NULL;
271        }
272
273        if (status != CR_OK && result) {
274                cr_declaration_destroy (result);
275                result = NULL;
276        }
277        return result;
278}
279
280/**
281 * cr_declaration_append:
282 *@a_this: the current declaration list.
283 *@a_new: the declaration to append.
284 *
285 *Appends a new declaration to the current declarations list.
286 *Returns the declaration list with a_new appended to it, or NULL
287 *in case of error.
288 */
289CRDeclaration *
290cr_declaration_append (CRDeclaration * a_this, CRDeclaration * a_new)
291{
292        CRDeclaration *cur = NULL;
293
294        g_return_val_if_fail (a_new, NULL);
295
296        if (!a_this)
297                return a_new;
298
299        for (cur = a_this; cur && cur->next; cur = cur->next) ;
300
301        cur->next = a_new;
302        a_new->prev = cur;
303
304        return a_this;
305}
306
307/**
308 * cr_declaration_unlink:
309 *@a_decls: the declaration to unlink.
310 *
311 *Unlinks the declaration from the declaration list.
312 *case of a successfull completion, NULL otherwise.
313 *
314 *Returns a pointer to the unlinked declaration in
315 */
316CRDeclaration *
317cr_declaration_unlink (CRDeclaration * a_decl)
318{
319        CRDeclaration *result = a_decl;
320
321        g_return_val_if_fail (result, NULL);
322
323        /*
324         *some sanity checks first
325         */
326        if (a_decl->prev) {
327                g_return_val_if_fail (a_decl->prev->next == a_decl, NULL);
328
329        }
330        if (a_decl->next) {
331                g_return_val_if_fail (a_decl->next->prev == a_decl, NULL);
332        }
333
334        /*
335         *now, the real unlinking job.
336         */
337        if (a_decl->prev) {
338                a_decl->prev->next = a_decl->next;
339        }
340        if (a_decl->next) {
341                a_decl->next->prev = a_decl->prev;
342        }
343        if (a_decl->parent_statement) {
344                CRDeclaration **children_decl_ptr = NULL;
345
346                switch (a_decl->parent_statement->type) {
347                case RULESET_STMT:
348                        if (a_decl->parent_statement->kind.ruleset) {
349                                children_decl_ptr =
350                                        &a_decl->parent_statement->
351                                        kind.ruleset->decl_list;
352                        }
353
354                        break;
355
356                case AT_FONT_FACE_RULE_STMT:
357                        if (a_decl->parent_statement->kind.font_face_rule) {
358                                children_decl_ptr =
359                                        &a_decl->parent_statement->
360                                        kind.font_face_rule->decl_list;
361                        }
362                        break;
363                case AT_PAGE_RULE_STMT:
364                        if (a_decl->parent_statement->kind.page_rule) {
365                                children_decl_ptr =
366                                        &a_decl->parent_statement->
367                                        kind.page_rule->decl_list;
368                        }
369
370                default:
371                        break;
372                }
373                if (children_decl_ptr
374                    && *children_decl_ptr && *children_decl_ptr == a_decl)
375                        *children_decl_ptr = (*children_decl_ptr)->next;
376        }
377
378        a_decl->next = NULL;
379        a_decl->prev = NULL;
380        a_decl->parent_statement = NULL;
381
382        return result;
383}
384
385/**
386 * cr_declaration_prepend:
387 * @a_this: the current declaration list.
388 * @a_new: the declaration to prepend.
389 *
390 * prepends a declaration to the current declaration list.
391 *
392 * Returns the list with a_new prepended or NULL in case of error.
393 */
394CRDeclaration *
395cr_declaration_prepend (CRDeclaration * a_this, CRDeclaration * a_new)
396{
397        CRDeclaration *cur = NULL;
398
399        g_return_val_if_fail (a_new, NULL);
400
401        if (!a_this)
402                return a_new;
403
404        a_this->prev = a_new;
405        a_new->next = a_this;
406
407        for (cur = a_new; cur && cur->prev; cur = cur->prev) ;
408
409        return cur;
410}
411
412/**
413 * cr_declaration_append2:
414 *@a_this: the current declaration list.
415 *@a_prop: the property string of the declaration to append.
416 *@a_value: the value of the declaration to append.
417 *
418 *Appends a declaration to the current declaration list.
419 *Returns the list with the new property appended to it, or NULL in
420 *case of an error.
421 */
422CRDeclaration *
423cr_declaration_append2 (CRDeclaration * a_this,
424                        CRString * a_prop, CRTerm * a_value)
425{
426        CRDeclaration *new_elem = NULL;
427
428        if (a_this) {
429                new_elem = cr_declaration_new (a_this->parent_statement,
430                                               a_prop, a_value);
431        } else {
432                new_elem = cr_declaration_new (NULL, a_prop, a_value);
433        }
434
435        g_return_val_if_fail (new_elem, NULL);
436
437        return cr_declaration_append (a_this, new_elem);
438}
439
440/**
441 * cr_declaration_dump:
442 *@a_this: the current instance of #CRDeclaration.
443 *@a_fp: the destination file.
444 *@a_indent: the number of indentation white char.
445 *@a_one_per_line: whether to put one declaration per line of not .
446 *
447 *
448 *Dumps a declaration list to a file.
449 */
450void
451cr_declaration_dump (CRDeclaration * a_this, FILE * a_fp, glong a_indent,
452                     gboolean a_one_per_line)
453{
454        CRDeclaration *cur = NULL;
455
456        g_return_if_fail (a_this);
457
458        for (cur = a_this; cur; cur = cur->next) {
459                if (cur->prev) {
460                        if (a_one_per_line == TRUE)
461                                fprintf (a_fp, ";\n");
462                        else
463                                fprintf (a_fp, "; ");
464                }
465                dump (cur, a_fp, a_indent);
466        }
467}
468
469/**
470 * cr_declaration_dump_one:
471 *@a_this: the current instance of #CRDeclaration.
472 *@a_fp: the destination file.
473 *@a_indent: the number of indentation white char.
474 *
475 *Dumps the first declaration of the declaration list to a file.
476 */
477void
478cr_declaration_dump_one (CRDeclaration * a_this, FILE * a_fp, glong a_indent)
479{
480        g_return_if_fail (a_this);
481
482        dump (a_this, a_fp, a_indent);
483}
484
485/**
486 * cr_declaration_to_string:
487 *@a_this: the current instance of #CRDeclaration.
488 *@a_indent: the number of indentation white char
489 *to put before the actual serialisation.
490 *
491 *Serializes the declaration into a string
492 *Returns the serialized form the declaration. The caller must
493 *free the string using g_free().
494 */
495gchar *
496cr_declaration_to_string (CRDeclaration * a_this, gulong a_indent)
497{
498        GString *stringue = NULL;
499
500        guchar *str = NULL,
501                *result = NULL;
502
503        g_return_val_if_fail (a_this, NULL);
504
505	stringue = g_string_new (NULL);
506
507	if (a_this->property
508	    && a_this->property->stryng
509	    && a_this->property->stryng->str) {
510		str = g_strndup (a_this->property->stryng->str,
511				 a_this->property->stryng->len);
512		if (str) {
513			cr_utils_dump_n_chars2 (' ', stringue,
514						a_indent);
515			g_string_append (stringue, str);
516			g_free (str);
517			str = NULL;
518		} else
519                        goto error;
520
521                if (a_this->value) {
522                        guchar *value_str = NULL;
523
524                        value_str = cr_term_to_string (a_this->value);
525                        if (value_str) {
526                                g_string_append_printf (stringue, " : %s",
527                                                        value_str);
528                                g_free (value_str);
529                        } else
530                                goto error;
531                }
532                if (a_this->important == TRUE) {
533                        g_string_append_printf (stringue, " %s",
534                                                "!important");
535                }
536        }
537        if (stringue && stringue->str) {
538                result = stringue->str;
539                g_string_free (stringue, FALSE);
540        }
541        return result;
542
543      error:
544        if (stringue) {
545                g_string_free (stringue, TRUE);
546                stringue = NULL;
547        }
548        if (str) {
549                g_free (str);
550                str = NULL;
551        }
552
553        return result;
554}
555
556/**
557 * cr_declaration_list_to_string:
558 *@a_this: the current instance of #CRDeclaration.
559 *@a_indent: the number of indentation white char
560 *to put before the actual serialisation.
561 *
562 *Serializes the declaration list into a string
563 */
564guchar *
565cr_declaration_list_to_string (CRDeclaration * a_this, gulong a_indent)
566{
567        CRDeclaration *cur = NULL;
568        GString *stringue = NULL;
569        guchar *str = NULL,
570                *result = NULL;
571
572        g_return_val_if_fail (a_this, NULL);
573
574        stringue = g_string_new (NULL);
575
576        for (cur = a_this; cur; cur = cur->next) {
577                str = cr_declaration_to_string (cur, a_indent);
578                if (str) {
579                        g_string_append_printf (stringue, "%s;", str);
580                        g_free (str);
581                } else
582                        break;
583        }
584        if (stringue && stringue->str) {
585                result = stringue->str;
586                g_string_free (stringue, FALSE);
587        }
588
589        return result;
590}
591
592/**
593 * cr_declaration_list_to_string2:
594 *@a_this: the current instance of #CRDeclaration.
595 *@a_indent: the number of indentation white char
596 @a_one_decl_per_line: whether to output one doc per line or not.
597 *to put before the actual serialisation.
598 *
599 *Serializes the declaration list into a string
600 *Returns the serialized form the declararation.
601 */
602guchar *
603cr_declaration_list_to_string2 (CRDeclaration * a_this,
604                                gulong a_indent, gboolean a_one_decl_per_line)
605{
606        CRDeclaration *cur = NULL;
607        GString *stringue = NULL;
608        guchar *str = NULL,
609                *result = NULL;
610
611        g_return_val_if_fail (a_this, NULL);
612
613        stringue = g_string_new (NULL);
614
615        for (cur = a_this; cur; cur = cur->next) {
616                str = cr_declaration_to_string (cur, a_indent);
617                if (str) {
618                        if (a_one_decl_per_line == TRUE) {
619                                if (cur->next)
620                                        g_string_append_printf (stringue,
621                                                                "%s;\n", str);
622                                else
623                                        g_string_append (stringue,
624                                                         str);
625                        } else {
626                                if (cur->next)
627                                        g_string_append_printf (stringue,
628                                                                "%s;", str);
629                                else
630                                        g_string_append (stringue,
631                                                         str);
632                        }
633                        g_free (str);
634                } else
635                        break;
636        }
637        if (stringue && stringue->str) {
638                result = stringue->str;
639                g_string_free (stringue, FALSE);
640        }
641
642        return result;
643}
644
645/**
646 * cr_declaration_nr_props:
647 *@a_this: the current instance of #CRDeclaration.
648 *Return the number of properties in the declaration
649 */
650gint
651cr_declaration_nr_props (CRDeclaration * a_this)
652{
653        CRDeclaration *cur = NULL;
654        int nr = 0;
655
656        g_return_val_if_fail (a_this, -1);
657
658        for (cur = a_this; cur; cur = cur->next)
659                nr++;
660        return nr;
661}
662
663/**
664 * cr_declaration_get_from_list:
665 *@a_this: the current instance of #CRDeclaration.
666 *@itemnr: the index into the declaration list.
667 *
668 *Use an index to get a CRDeclaration from the declaration list.
669 *
670 *Returns #CRDeclaration at position itemnr,
671 *if itemnr > number of declarations - 1,
672 *it will return NULL.
673 */
674CRDeclaration *
675cr_declaration_get_from_list (CRDeclaration * a_this, int itemnr)
676{
677        CRDeclaration *cur = NULL;
678        int nr = 0;
679
680        g_return_val_if_fail (a_this, NULL);
681
682        for (cur = a_this; cur; cur = cur->next)
683                if (nr++ == itemnr)
684                        return cur;
685        return NULL;
686}
687
688/**
689 * cr_declaration_get_by_prop_name:
690 *@a_this: the current instance of #CRDeclaration.
691 *@a_prop: the property name to search for.
692 *
693 *Use property name to get a CRDeclaration from the declaration list.
694 *Returns #CRDeclaration with property name a_prop, or NULL if not found.
695 */
696CRDeclaration *
697cr_declaration_get_by_prop_name (CRDeclaration * a_this,
698                                 const guchar * a_prop)
699{
700        CRDeclaration *cur = NULL;
701
702        g_return_val_if_fail (a_this, NULL);
703        g_return_val_if_fail (a_prop, NULL);
704
705        for (cur = a_this; cur; cur = cur->next) {
706		if (cur->property
707		    && cur->property->stryng
708		    && cur->property->stryng->str) {
709			if (!strcmp (cur->property->stryng->str,
710				     a_prop)) {
711				return cur;
712			}
713		}
714	}
715        return NULL;
716}
717
718/**
719 * cr_declaration_ref:
720 *@a_this: the current instance of #CRDeclaration.
721 *
722 *Increases the ref count of the current instance of #CRDeclaration.
723 */
724void
725cr_declaration_ref (CRDeclaration * a_this)
726{
727        g_return_if_fail (a_this);
728
729        a_this->ref_count++;
730}
731
732/**
733 * cr_declaration_unref:
734 *@param a_this the current instance of #CRDeclaration.
735 *@return TRUE if the current instance of #CRDeclaration has been destroyed
736 *(ref count reached zero), FALSE otherwise.
737 *
738 *Decrements the ref count of the current instance of #CRDeclaration.
739 *If the ref count reaches zero, the current instance of #CRDeclaration
740 *if destroyed.
741 *Returns TRUE if the object got destroyed, FALSE otherwise.
742 */
743gboolean
744cr_declaration_unref (CRDeclaration * a_this)
745{
746        g_return_val_if_fail (a_this, FALSE);
747
748        if (a_this->ref_count) {
749                a_this->ref_count--;
750        }
751
752        if (a_this->ref_count == 0) {
753                cr_declaration_destroy (a_this);
754                return TRUE;
755        }
756        return FALSE;
757}
758
759/**
760 * cr_declaration_destroy:
761 *@a_this: the current instance of #CRDeclaration.
762 *
763 *Destructor of the declaration list.
764 */
765void
766cr_declaration_destroy (CRDeclaration * a_this)
767{
768        CRDeclaration *cur = NULL;
769
770        g_return_if_fail (a_this);
771
772        /*
773         *Go get the tail of the list.
774         *Meanwhile, free each property/value pair contained in the list.
775         */
776        for (cur = a_this; cur && cur->next; cur = cur->next) {
777                if (cur->property) {
778                        cr_string_destroy (cur->property);
779                        cur->property = NULL;
780                }
781
782                if (cur->value) {
783                        cr_term_destroy (cur->value);
784                        cur->value = NULL;
785                }
786        }
787
788        if (cur) {
789                if (cur->property) {
790                        cr_string_destroy (cur->property);
791                        cur->property = NULL;
792                }
793
794                if (cur->value) {
795                        cr_term_destroy (cur->value);
796                        cur->value = NULL;
797                }
798        }
799
800        /*in case the list contains only one element */
801        if (cur && !cur->prev) {
802                g_free (cur);
803                return;
804        }
805
806        /*walk backward the list and free each "next" element */
807        for (cur = cur->prev; cur && cur->prev; cur = cur->prev) {
808                if (cur->next) {
809                        g_free (cur->next);
810                        cur->next = NULL;
811                }
812        }
813
814        if (!cur)
815                return;
816
817        if (cur->next) {
818                g_free (cur->next);
819                cur->next = NULL;
820        }
821
822        g_free (cur);
823}
824