1 /* -*- Mode: C; indent-tabs-mode: ni; c-basic-offset: 8 -*- */
4 * This file is part of The Croco Library
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.
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.
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
20 * Author: Dodji Seketeli.
21 * See COPYRIGHTS file for copyright information.
26 #include "cr-declaration.h"
27 #include "cr-statement.h"
28 #include "cr-parser.h"
33 *The definition of the #CRDeclaration class.
38 *@a_this: the current instance of #CRDeclaration.
39 *@a_fp: the destination file pointer.
40 *@a_indent: the number of indentation white char.
42 *Dumps (serializes) one css declaration to a file.
45 dump (CRDeclaration * a_this, FILE * a_fp, glong a_indent)
49 g_return_if_fail (a_this);
51 str = cr_declaration_to_string (a_this, a_indent);
53 fprintf (a_fp, "%s", str);
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.
66 *Returns the newly built instance of #CRDeclaration, or NULL in
70 cr_declaration_new (CRStatement * a_statement,
71 CRString * a_property, CRTerm * a_value)
73 CRDeclaration *result = NULL;
75 g_return_val_if_fail (a_property, NULL);
78 g_return_val_if_fail (a_statement
79 && ((a_statement->type == RULESET_STMT)
81 == AT_FONT_FACE_RULE_STMT)
83 == AT_PAGE_RULE_STMT)), NULL);
85 result = g_try_malloc (sizeof (CRDeclaration));
87 cr_utils_trace_info ("Out of memory");
90 memset (result, 0, sizeof (CRDeclaration));
91 result->property = a_property;
92 result->value = a_value;
95 cr_term_ref (a_value);
97 result->parent_statement = a_statement;
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.
109 *Parses a text buffer that contains
111 *Returns the parsed declaration, or NULL in case of error.
114 cr_declaration_parse_from_buf (CRStatement * a_statement,
115 const guchar * a_str, enum CREncoding a_enc)
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;
124 g_return_val_if_fail (a_str, NULL);
126 g_return_val_if_fail (a_statement->type == RULESET_STMT,
129 parser = cr_parser_new_from_buf ((guchar*)a_str, strlen (a_str), a_enc, FALSE);
130 g_return_val_if_fail (parser, NULL);
132 status = cr_parser_try_to_skip_spaces_and_comments (parser);
136 status = cr_parser_parse_declaration (parser, &property,
138 if (status != CR_OK || !property)
141 result = cr_declaration_new (a_statement, property, value);
145 result->important = important;
151 cr_parser_destroy (parser);
156 cr_string_destroy (property);
161 cr_term_destroy (value);
169 * cr_declaration_parse_list_from_buf:
170 *@a_str: the input buffer that contains the list of declaration to
172 *@a_enc: the encoding of a_str
174 *Parses a ';' separated list of properties declaration.
175 *Returns the parsed list of declaration, NULL if parsing failed.
178 cr_declaration_parse_list_from_buf (const guchar * a_str,
179 enum CREncoding a_enc)
182 enum CRStatus status = CR_OK;
183 CRTerm *value = NULL;
184 CRString *property = NULL;
185 CRDeclaration *result = NULL,
187 CRParser *parser = NULL;
188 CRTknzr *tokenizer = NULL;
189 gboolean important = FALSE;
191 g_return_val_if_fail (a_str, NULL);
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) {
201 status = cr_parser_try_to_skip_spaces_and_comments (parser);
205 status = cr_parser_parse_declaration (parser, &property,
207 if (status != CR_OK || !property) {
212 result = cr_declaration_new (NULL, property, value);
216 result->important = important;
218 /*now, go parse the other declarations */
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)
230 status = cr_tknzr_read_char (tokenizer, &c);
235 cr_parser_try_to_skip_spaces_and_comments (parser);
236 status = cr_parser_parse_declaration (parser, &property,
238 if (status != CR_OK || !property) {
239 if (status == CR_END_OF_INPUT_ERROR) {
244 cur_decl = cr_declaration_new (NULL, property, value);
246 cur_decl->important = important;
247 result = cr_declaration_append (result, cur_decl);
259 cr_parser_destroy (parser);
264 cr_string_destroy (property);
269 cr_term_destroy (value);
273 if (status != CR_OK && result) {
274 cr_declaration_destroy (result);
281 * cr_declaration_append:
282 *@a_this: the current declaration list.
283 *@a_new: the declaration to append.
285 *Appends a new declaration to the current declarations list.
286 *Returns the declaration list with a_new appended to it, or NULL
290 cr_declaration_append (CRDeclaration * a_this, CRDeclaration * a_new)
292 CRDeclaration *cur = NULL;
294 g_return_val_if_fail (a_new, NULL);
299 for (cur = a_this; cur && cur->next; cur = cur->next) ;
308 * cr_declaration_unlink:
309 *@a_decls: the declaration to unlink.
311 *Unlinks the declaration from the declaration list.
312 *case of a successfull completion, NULL otherwise.
314 *Returns a pointer to the unlinked declaration in
317 cr_declaration_unlink (CRDeclaration * a_decl)
319 CRDeclaration *result = a_decl;
321 g_return_val_if_fail (result, NULL);
324 *some sanity checks first
327 g_return_val_if_fail (a_decl->prev->next == a_decl, NULL);
331 g_return_val_if_fail (a_decl->next->prev == a_decl, NULL);
335 *now, the real unlinking job.
338 a_decl->prev->next = a_decl->next;
341 a_decl->next->prev = a_decl->prev;
343 if (a_decl->parent_statement) {
344 CRDeclaration **children_decl_ptr = NULL;
346 switch (a_decl->parent_statement->type) {
348 if (a_decl->parent_statement->kind.ruleset) {
350 &a_decl->parent_statement->
351 kind.ruleset->decl_list;
356 case AT_FONT_FACE_RULE_STMT:
357 if (a_decl->parent_statement->kind.font_face_rule) {
359 &a_decl->parent_statement->
360 kind.font_face_rule->decl_list;
363 case AT_PAGE_RULE_STMT:
364 if (a_decl->parent_statement->kind.page_rule) {
366 &a_decl->parent_statement->
367 kind.page_rule->decl_list;
373 if (children_decl_ptr
374 && *children_decl_ptr && *children_decl_ptr == a_decl)
375 *children_decl_ptr = (*children_decl_ptr)->next;
380 a_decl->parent_statement = NULL;
386 * cr_declaration_prepend:
387 * @a_this: the current declaration list.
388 * @a_new: the declaration to prepend.
390 * prepends a declaration to the current declaration list.
392 * Returns the list with a_new prepended or NULL in case of error.
395 cr_declaration_prepend (CRDeclaration * a_this, CRDeclaration * a_new)
397 CRDeclaration *cur = NULL;
399 g_return_val_if_fail (a_new, NULL);
404 a_this->prev = a_new;
405 a_new->next = a_this;
407 for (cur = a_new; cur && cur->prev; cur = cur->prev) ;
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.
418 *Appends a declaration to the current declaration list.
419 *Returns the list with the new property appended to it, or NULL in
423 cr_declaration_append2 (CRDeclaration * a_this,
424 CRString * a_prop, CRTerm * a_value)
426 CRDeclaration *new_elem = NULL;
429 new_elem = cr_declaration_new (a_this->parent_statement,
432 new_elem = cr_declaration_new (NULL, a_prop, a_value);
435 g_return_val_if_fail (new_elem, NULL);
437 return cr_declaration_append (a_this, new_elem);
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 .
448 *Dumps a declaration list to a file.
451 cr_declaration_dump (CRDeclaration * a_this, FILE * a_fp, glong a_indent,
452 gboolean a_one_per_line)
454 CRDeclaration *cur = NULL;
456 g_return_if_fail (a_this);
458 for (cur = a_this; cur; cur = cur->next) {
460 if (a_one_per_line == TRUE)
461 fprintf (a_fp, ";\n");
463 fprintf (a_fp, "; ");
465 dump (cur, a_fp, a_indent);
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.
475 *Dumps the first declaration of the declaration list to a file.
478 cr_declaration_dump_one (CRDeclaration * a_this, FILE * a_fp, glong a_indent)
480 g_return_if_fail (a_this);
482 dump (a_this, a_fp, a_indent);
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.
491 *Serializes the declaration into a string
492 *Returns the serialized form the declaration. The caller must
493 *free the string using g_free().
496 cr_declaration_to_string (CRDeclaration * a_this, gulong a_indent)
498 GString *stringue = NULL;
503 g_return_val_if_fail (a_this, NULL);
505 stringue = g_string_new (NULL);
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);
513 cr_utils_dump_n_chars2 (' ', stringue,
515 g_string_append (stringue, str);
522 guchar *value_str = NULL;
524 value_str = cr_term_to_string (a_this->value);
526 g_string_append_printf (stringue, " : %s",
532 if (a_this->important == TRUE) {
533 g_string_append_printf (stringue, " %s",
537 if (stringue && stringue->str) {
538 result = stringue->str;
539 g_string_free (stringue, FALSE);
545 g_string_free (stringue, TRUE);
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.
562 *Serializes the declaration list into a string
565 cr_declaration_list_to_string (CRDeclaration * a_this, gulong a_indent)
567 CRDeclaration *cur = NULL;
568 GString *stringue = NULL;
572 g_return_val_if_fail (a_this, NULL);
574 stringue = g_string_new (NULL);
576 for (cur = a_this; cur; cur = cur->next) {
577 str = cr_declaration_to_string (cur, a_indent);
579 g_string_append_printf (stringue, "%s;", str);
584 if (stringue && stringue->str) {
585 result = stringue->str;
586 g_string_free (stringue, FALSE);
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.
599 *Serializes the declaration list into a string
600 *Returns the serialized form the declararation.
603 cr_declaration_list_to_string2 (CRDeclaration * a_this,
604 gulong a_indent, gboolean a_one_decl_per_line)
606 CRDeclaration *cur = NULL;
607 GString *stringue = NULL;
611 g_return_val_if_fail (a_this, NULL);
613 stringue = g_string_new (NULL);
615 for (cur = a_this; cur; cur = cur->next) {
616 str = cr_declaration_to_string (cur, a_indent);
618 if (a_one_decl_per_line == TRUE) {
620 g_string_append_printf (stringue,
623 g_string_append (stringue,
627 g_string_append_printf (stringue,
630 g_string_append (stringue,
637 if (stringue && stringue->str) {
638 result = stringue->str;
639 g_string_free (stringue, FALSE);
646 * cr_declaration_nr_props:
647 *@a_this: the current instance of #CRDeclaration.
648 *Return the number of properties in the declaration
651 cr_declaration_nr_props (CRDeclaration * a_this)
653 CRDeclaration *cur = NULL;
656 g_return_val_if_fail (a_this, -1);
658 for (cur = a_this; cur; cur = cur->next)
664 * cr_declaration_get_from_list:
665 *@a_this: the current instance of #CRDeclaration.
666 *@itemnr: the index into the declaration list.
668 *Use an index to get a CRDeclaration from the declaration list.
670 *Returns #CRDeclaration at position itemnr,
671 *if itemnr > number of declarations - 1,
672 *it will return NULL.
675 cr_declaration_get_from_list (CRDeclaration * a_this, int itemnr)
677 CRDeclaration *cur = NULL;
680 g_return_val_if_fail (a_this, NULL);
682 for (cur = a_this; cur; cur = cur->next)
689 * cr_declaration_get_by_prop_name:
690 *@a_this: the current instance of #CRDeclaration.
691 *@a_prop: the property name to search for.
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.
697 cr_declaration_get_by_prop_name (CRDeclaration * a_this,
698 const guchar * a_prop)
700 CRDeclaration *cur = NULL;
702 g_return_val_if_fail (a_this, NULL);
703 g_return_val_if_fail (a_prop, NULL);
705 for (cur = a_this; cur; cur = cur->next) {
707 && cur->property->stryng
708 && cur->property->stryng->str) {
709 if (!strcmp (cur->property->stryng->str,
719 * cr_declaration_ref:
720 *@a_this: the current instance of #CRDeclaration.
722 *Increases the ref count of the current instance of #CRDeclaration.
725 cr_declaration_ref (CRDeclaration * a_this)
727 g_return_if_fail (a_this);
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.
738 *Decrements the ref count of the current instance of #CRDeclaration.
739 *If the ref count reaches zero, the current instance of #CRDeclaration
741 *Returns TRUE if the object got destroyed, FALSE otherwise.
744 cr_declaration_unref (CRDeclaration * a_this)
746 g_return_val_if_fail (a_this, FALSE);
748 if (a_this->ref_count) {
752 if (a_this->ref_count == 0) {
753 cr_declaration_destroy (a_this);
760 * cr_declaration_destroy:
761 *@a_this: the current instance of #CRDeclaration.
763 *Destructor of the declaration list.
766 cr_declaration_destroy (CRDeclaration * a_this)
768 CRDeclaration *cur = NULL;
770 g_return_if_fail (a_this);
773 *Go get the tail of the list.
774 *Meanwhile, free each property/value pair contained in the list.
776 for (cur = a_this; cur && cur->next; cur = cur->next) {
778 cr_string_destroy (cur->property);
779 cur->property = NULL;
783 cr_term_destroy (cur->value);
790 cr_string_destroy (cur->property);
791 cur->property = NULL;
795 cr_term_destroy (cur->value);
800 /*in case the list contains only one element */
801 if (cur && !cur->prev) {
806 /*walk backward the list and free each "next" element */
807 for (cur = cur->prev; cur && cur->prev; cur = cur->prev) {