Libcroco
cr-declaration.c
Go to the documentation of this file.
00001 /* -*- Mode: C; indent-tabs-mode: nil; c-basic-offset: 8 -*- */
00002 
00003 /*
00004  * This file is part of The Croco Library
00005  *
00006  * This program is free software; you can redistribute it and/or
00007  * modify it under the terms of version 2.1 of the GNU Lesser General Public
00008  * License as published by the Free Software Foundation.
00009  *
00010  * This program is distributed in the hope that it will be useful,
00011  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00012  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00013  * GNU General Public License for more details.
00014  *
00015  * You should have received a copy of the GNU Lesser General Public License
00016  * along with this program; if not, write to the Free Software
00017  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
00018  * USA
00019  *
00020  * Author: Dodji Seketeli.
00021  * See COPYRIGHTS file for copyright information.
00022  */
00023 
00024 
00025 #include <string.h>
00026 #include "cr-declaration.h"
00027 #include "cr-statement.h"
00028 #include "cr-parser.h"
00029 
00030 /**
00031  *@CRDeclaration:
00032  *
00033  *The definition of the #CRDeclaration class.
00034  */
00035 
00036 /**
00037  * dump:
00038  *@a_this: the current instance of #CRDeclaration.
00039  *@a_fp: the destination file pointer.
00040  *@a_indent: the number of indentation white char. 
00041  *
00042  *Dumps (serializes) one css declaration to a file.
00043  */
00044 static void
00045 dump (CRDeclaration const * a_this, FILE * a_fp, glong a_indent)
00046 {
00047         guchar *str = NULL;
00048 
00049         g_return_if_fail (a_this);
00050 
00051         str = (guchar *) cr_declaration_to_string (a_this, a_indent);
00052         if (str) {
00053                 fprintf (a_fp, "%s", str);
00054                 g_free (str);
00055                 str = NULL;
00056         }
00057 }
00058 
00059 /**
00060  * cr_declaration_new:
00061  * @a_statement: the statement this declaration belongs to. can be NULL.
00062  *@a_property: the property string of the declaration
00063  *@a_value: the value expression of the declaration.
00064  *Constructor of #CRDeclaration.
00065  *
00066  *Returns the newly built instance of #CRDeclaration, or NULL in
00067  *case of error.
00068  *
00069  *The returned CRDeclaration takes ownership of @a_property and @a_value.
00070  *(E.g. cr_declaration_destroy on this CRDeclaration will also free
00071  *@a_property and @a_value.)
00072  */
00073 CRDeclaration *
00074 cr_declaration_new (CRStatement * a_statement,
00075                     CRString * a_property, CRTerm * a_value)
00076 {
00077         CRDeclaration *result = NULL;
00078 
00079         g_return_val_if_fail (a_property, NULL);
00080 
00081         if (a_statement)
00082                 g_return_val_if_fail (a_statement
00083                                       && ((a_statement->type == RULESET_STMT)
00084                                           || (a_statement->type
00085                                               == AT_FONT_FACE_RULE_STMT)
00086                                           || (a_statement->type
00087                                               == AT_PAGE_RULE_STMT)), NULL);
00088 
00089         result = g_try_malloc (sizeof (CRDeclaration));
00090         if (!result) {
00091                 cr_utils_trace_info ("Out of memory");
00092                 return NULL;
00093         }
00094         memset (result, 0, sizeof (CRDeclaration));
00095         result->property = a_property;
00096         result->value = a_value;
00097 
00098         if (a_value) {
00099                 cr_term_ref (a_value);
00100         }
00101         result->parent_statement = a_statement;
00102         return result;
00103 }
00104 
00105 /**
00106  * cr_declaration_parse_from_buf:
00107  *@a_statement: the parent css2 statement of this
00108  *this declaration. Must be non NULL and of type
00109  *RULESET_STMT (must be a ruleset).
00110  *@a_str: the string that contains the statement.
00111  *@a_enc: the encoding of a_str.
00112  *
00113  *Parses a text buffer that contains
00114  *a css declaration.
00115  *Returns the parsed declaration, or NULL in case of error.
00116  */
00117 CRDeclaration *
00118 cr_declaration_parse_from_buf (CRStatement * a_statement,
00119                                const guchar * a_str, enum CREncoding a_enc)
00120 {
00121         enum CRStatus status = CR_OK;
00122         CRTerm *value = NULL;
00123         CRString *property = NULL;
00124         CRDeclaration *result = NULL;
00125         CRParser *parser = NULL;
00126         gboolean important = FALSE;
00127 
00128         g_return_val_if_fail (a_str, NULL);
00129         if (a_statement)
00130                 g_return_val_if_fail (a_statement->type == RULESET_STMT,
00131                                       NULL);
00132 
00133         parser = cr_parser_new_from_buf ((guchar*)a_str, strlen ((const char *) a_str), a_enc, FALSE);
00134         g_return_val_if_fail (parser, NULL);
00135 
00136         status = cr_parser_try_to_skip_spaces_and_comments (parser);
00137         if (status != CR_OK)
00138                 goto cleanup;
00139 
00140         status = cr_parser_parse_declaration (parser, &property,
00141                                               &value, &important);
00142         if (status != CR_OK || !property)
00143                 goto cleanup;
00144 
00145         result = cr_declaration_new (a_statement, property, value);
00146         if (result) {
00147                 property = NULL;
00148                 value = NULL;
00149                 result->important = important;
00150         }
00151 
00152       cleanup:
00153 
00154         if (parser) {
00155                 cr_parser_destroy (parser);
00156                 parser = NULL;
00157         }
00158 
00159         if (property) {
00160                 cr_string_destroy (property);
00161                 property = NULL;
00162         }
00163 
00164         if (value) {
00165                 cr_term_destroy (value);
00166                 value = NULL;
00167         }
00168 
00169         return result;
00170 }
00171 
00172 /**
00173  * cr_declaration_parse_list_from_buf:
00174  *@a_str: the input buffer that contains the list of declaration to
00175  *parse.
00176  *@a_enc: the encoding of a_str
00177  *
00178  *Parses a ';' separated list of properties declaration.
00179  *Returns the parsed list of declaration, NULL if parsing failed.
00180  */
00181 CRDeclaration *
00182 cr_declaration_parse_list_from_buf (const guchar * a_str,
00183                                     enum CREncoding a_enc)
00184 {
00185 
00186         enum CRStatus status = CR_OK;
00187         CRTerm *value = NULL;
00188         CRString *property = NULL;
00189         CRDeclaration *result = NULL,
00190                 *cur_decl = NULL;
00191         CRParser *parser = NULL;
00192         CRTknzr *tokenizer = NULL;
00193         gboolean important = FALSE;
00194 
00195         g_return_val_if_fail (a_str, NULL);
00196 
00197         parser = cr_parser_new_from_buf ((guchar*)a_str, strlen ((const char *) a_str), a_enc, FALSE);
00198         g_return_val_if_fail (parser, NULL);
00199         status = cr_parser_get_tknzr (parser, &tokenizer);
00200         if (status != CR_OK || !tokenizer) {
00201                 if (status == CR_OK)
00202                         status = CR_ERROR;
00203                 goto cleanup;
00204         }
00205         status = cr_parser_try_to_skip_spaces_and_comments (parser);
00206         if (status != CR_OK)
00207                 goto cleanup;
00208 
00209         status = cr_parser_parse_declaration (parser, &property,
00210                                               &value, &important);
00211         if (status != CR_OK || !property) {
00212                 if (status != CR_OK)
00213                         status = CR_ERROR;
00214                 goto cleanup;
00215         }
00216         result = cr_declaration_new (NULL, property, value);
00217         if (result) {
00218                 property = NULL;
00219                 value = NULL;
00220                 result->important = important;
00221         }
00222         /*now, go parse the other declarations */
00223         for (;;) {
00224                 guint32 c = 0;
00225 
00226                 cr_parser_try_to_skip_spaces_and_comments (parser);
00227                 status = cr_tknzr_peek_char (tokenizer, &c);
00228                 if (status != CR_OK) {
00229                         if (status == CR_END_OF_INPUT_ERROR)
00230                                 status = CR_OK;
00231                         goto cleanup;
00232                 }
00233                 if (c == ';') {
00234                         status = cr_tknzr_read_char (tokenizer, &c);
00235                 } else {
00236                         break;
00237                 }
00238                 important = FALSE;
00239                 cr_parser_try_to_skip_spaces_and_comments (parser);
00240                 status = cr_parser_parse_declaration (parser, &property,
00241                                                       &value, &important);
00242                 if (status != CR_OK || !property) {
00243                         if (status == CR_END_OF_INPUT_ERROR) {
00244                                 status = CR_OK;
00245                         }
00246                         break;
00247                 }
00248                 cur_decl = cr_declaration_new (NULL, property, value);
00249                 if (cur_decl) {
00250                         cur_decl->important = important;
00251                         result = cr_declaration_append (result, cur_decl);
00252                         property = NULL;
00253                         value = NULL;
00254                         cur_decl = NULL;
00255                 } else {
00256                         break;
00257                 }
00258         }
00259 
00260       cleanup:
00261 
00262         if (parser) {
00263                 cr_parser_destroy (parser);
00264                 parser = NULL;
00265         }
00266 
00267         if (property) {
00268                 cr_string_destroy (property);
00269                 property = NULL;
00270         }
00271 
00272         if (value) {
00273                 cr_term_destroy (value);
00274                 value = NULL;
00275         }
00276 
00277         if (status != CR_OK && result) {
00278                 cr_declaration_destroy (result);
00279                 result = NULL;
00280         }
00281         return result;
00282 }
00283 
00284 /**
00285  * cr_declaration_append:
00286  *@a_this: the current declaration list.
00287  *@a_new: the declaration to append.
00288  *
00289  *Appends a new declaration to the current declarations list.
00290  *Returns the declaration list with a_new appended to it, or NULL
00291  *in case of error.
00292  */
00293 CRDeclaration *
00294 cr_declaration_append (CRDeclaration * a_this, CRDeclaration * a_new)
00295 {
00296         CRDeclaration *cur = NULL;
00297 
00298         g_return_val_if_fail (a_new, NULL);
00299 
00300         if (!a_this)
00301                 return a_new;
00302 
00303         for (cur = a_this; cur && cur->next; cur = cur->next) ;
00304 
00305         cur->next = a_new;
00306         a_new->prev = cur;
00307 
00308         return a_this;
00309 }
00310 
00311 /**
00312  * cr_declaration_unlink:
00313  *@a_decls: the declaration to unlink.
00314  *
00315  *Unlinks the declaration from the declaration list.
00316  *case of a successfull completion, NULL otherwise.
00317  *
00318  *Returns a pointer to the unlinked declaration in
00319  */
00320 CRDeclaration *
00321 cr_declaration_unlink (CRDeclaration * a_decl)
00322 {
00323         CRDeclaration *result = a_decl;
00324 
00325         g_return_val_if_fail (result, NULL);
00326 
00327         /*
00328          *some sanity checks first
00329          */
00330         if (a_decl->prev) {
00331                 g_return_val_if_fail (a_decl->prev->next == a_decl, NULL);
00332 
00333         }
00334         if (a_decl->next) {
00335                 g_return_val_if_fail (a_decl->next->prev == a_decl, NULL);
00336         }
00337 
00338         /*
00339          *now, the real unlinking job.
00340          */
00341         if (a_decl->prev) {
00342                 a_decl->prev->next = a_decl->next;
00343         }
00344         if (a_decl->next) {
00345                 a_decl->next->prev = a_decl->prev;
00346         }
00347         if (a_decl->parent_statement) {
00348                 CRDeclaration **children_decl_ptr = NULL;
00349 
00350                 switch (a_decl->parent_statement->type) {
00351                 case RULESET_STMT:
00352                         if (a_decl->parent_statement->kind.ruleset) {
00353                                 children_decl_ptr =
00354                                         &a_decl->parent_statement->
00355                                         kind.ruleset->decl_list;
00356                         }
00357 
00358                         break;
00359 
00360                 case AT_FONT_FACE_RULE_STMT:
00361                         if (a_decl->parent_statement->kind.font_face_rule) {
00362                                 children_decl_ptr =
00363                                         &a_decl->parent_statement->
00364                                         kind.font_face_rule->decl_list;
00365                         }
00366                         break;
00367                 case AT_PAGE_RULE_STMT:
00368                         if (a_decl->parent_statement->kind.page_rule) {
00369                                 children_decl_ptr =
00370                                         &a_decl->parent_statement->
00371                                         kind.page_rule->decl_list;
00372                         }
00373 
00374                 default:
00375                         break;
00376                 }
00377                 if (children_decl_ptr
00378                     && *children_decl_ptr && *children_decl_ptr == a_decl)
00379                         *children_decl_ptr = (*children_decl_ptr)->next;
00380         }
00381 
00382         a_decl->next = NULL;
00383         a_decl->prev = NULL;
00384         a_decl->parent_statement = NULL;
00385 
00386         return result;
00387 }
00388 
00389 /**
00390  * cr_declaration_prepend:
00391  * @a_this: the current declaration list.
00392  * @a_new: the declaration to prepend.
00393  *
00394  * prepends a declaration to the current declaration list.
00395  *
00396  * Returns the list with a_new prepended or NULL in case of error.
00397  */
00398 CRDeclaration *
00399 cr_declaration_prepend (CRDeclaration * a_this, CRDeclaration * a_new)
00400 {
00401         CRDeclaration *cur = NULL;
00402 
00403         g_return_val_if_fail (a_new, NULL);
00404 
00405         if (!a_this)
00406                 return a_new;
00407 
00408         a_this->prev = a_new;
00409         a_new->next = a_this;
00410 
00411         for (cur = a_new; cur && cur->prev; cur = cur->prev) ;
00412 
00413         return cur;
00414 }
00415 
00416 /**
00417  * cr_declaration_append2:
00418  *@a_this: the current declaration list.
00419  *@a_prop: the property string of the declaration to append.
00420  *@a_value: the value of the declaration to append.
00421  *
00422  *Appends a declaration to the current declaration list.
00423  *Returns the list with the new property appended to it, or NULL in
00424  *case of an error.
00425  */
00426 CRDeclaration *
00427 cr_declaration_append2 (CRDeclaration * a_this,
00428                         CRString * a_prop, CRTerm * a_value)
00429 {
00430         CRDeclaration *new_elem = NULL;
00431 
00432         if (a_this) {
00433                 new_elem = cr_declaration_new (a_this->parent_statement,
00434                                                a_prop, a_value);
00435         } else {
00436                 new_elem = cr_declaration_new (NULL, a_prop, a_value);
00437         }
00438 
00439         g_return_val_if_fail (new_elem, NULL);
00440 
00441         return cr_declaration_append (a_this, new_elem);
00442 }
00443 
00444 /**
00445  * cr_declaration_dump:
00446  *@a_this: the current instance of #CRDeclaration.
00447  *@a_fp: the destination file.
00448  *@a_indent: the number of indentation white char.
00449  *@a_one_per_line: whether to put one declaration per line of not .
00450  *
00451  *
00452  *Dumps a declaration list to a file.
00453  */
00454 void
00455 cr_declaration_dump (CRDeclaration const * a_this, FILE * a_fp, glong a_indent,
00456                      gboolean a_one_per_line)
00457 {
00458         CRDeclaration const *cur = NULL;
00459 
00460         g_return_if_fail (a_this);
00461 
00462         for (cur = a_this; cur; cur = cur->next) {
00463                 if (cur->prev) {
00464                         if (a_one_per_line == TRUE)
00465                                 fprintf (a_fp, ";\n");
00466                         else
00467                                 fprintf (a_fp, "; ");
00468                 }
00469                 dump (cur, a_fp, a_indent);
00470         }
00471 }
00472 
00473 /**
00474  * cr_declaration_dump_one:
00475  *@a_this: the current instance of #CRDeclaration.
00476  *@a_fp: the destination file.
00477  *@a_indent: the number of indentation white char.
00478  *
00479  *Dumps the first declaration of the declaration list to a file.
00480  */
00481 void
00482 cr_declaration_dump_one (CRDeclaration const * a_this, FILE * a_fp, glong a_indent)
00483 {
00484         g_return_if_fail (a_this);
00485 
00486         dump (a_this, a_fp, a_indent);
00487 }
00488 
00489 /**
00490  * cr_declaration_to_string:
00491  *@a_this: the current instance of #CRDeclaration.
00492  *@a_indent: the number of indentation white char
00493  *to put before the actual serialisation.
00494  *
00495  *Serializes the declaration into a string
00496  *Returns the serialized form the declaration. The caller must
00497  *free the string using g_free().
00498  */
00499 gchar *
00500 cr_declaration_to_string (CRDeclaration const * a_this, gulong a_indent)
00501 {
00502         GString *stringue = NULL;
00503 
00504         gchar *str = NULL,
00505                 *result = NULL;
00506 
00507         g_return_val_if_fail (a_this, NULL);
00508 
00509         stringue = g_string_new (NULL);
00510 
00511         if (a_this->property 
00512             && a_this->property->stryng
00513             && a_this->property->stryng->str) {
00514                 str = g_strndup (a_this->property->stryng->str,
00515                                  a_this->property->stryng->len);
00516                 if (str) {
00517                         cr_utils_dump_n_chars2 (' ', stringue, 
00518                                                 a_indent);
00519                         g_string_append (stringue, str);
00520                         g_free (str);
00521                         str = NULL;
00522                 } else
00523                         goto error;
00524 
00525                 if (a_this->value) {
00526                         guchar *value_str = NULL;
00527 
00528                         value_str = cr_term_to_string (a_this->value);
00529                         if (value_str) {
00530                                 g_string_append_printf (stringue, " : %s",
00531                                                         value_str);
00532                                 g_free (value_str);
00533                         } else
00534                                 goto error;
00535                 }
00536                 if (a_this->important == TRUE) {
00537                         g_string_append_printf (stringue, " %s",
00538                                                 "!important");
00539                 }
00540         }
00541         if (stringue && stringue->str) {
00542                 result = stringue->str;
00543                 g_string_free (stringue, FALSE);
00544         }
00545         return result;
00546 
00547       error:
00548         if (stringue) {
00549                 g_string_free (stringue, TRUE);
00550                 stringue = NULL;
00551         }
00552         if (str) {
00553                 g_free (str);
00554                 str = NULL;
00555         }
00556 
00557         return result;
00558 }
00559 
00560 /**
00561  * cr_declaration_list_to_string:
00562  *@a_this: the current instance of #CRDeclaration.
00563  *@a_indent: the number of indentation white char
00564  *to put before the actual serialisation.
00565  *
00566  *Serializes the declaration list into a string
00567  */
00568 guchar *
00569 cr_declaration_list_to_string (CRDeclaration const * a_this, gulong a_indent)
00570 {
00571         CRDeclaration const *cur = NULL;
00572         GString *stringue = NULL;
00573         guchar *str = NULL,
00574                 *result = NULL;
00575 
00576         g_return_val_if_fail (a_this, NULL);
00577 
00578         stringue = g_string_new (NULL);
00579 
00580         for (cur = a_this; cur; cur = cur->next) {
00581                 str = (guchar *) cr_declaration_to_string (cur, a_indent);
00582                 if (str) {
00583                         g_string_append_printf (stringue, "%s;", str);
00584                         g_free (str);
00585                 } else
00586                         break;
00587         }
00588         if (stringue && stringue->str) {
00589                 result = (guchar *) stringue->str;
00590                 g_string_free (stringue, FALSE);
00591         }
00592 
00593         return result;
00594 }
00595 
00596 /**
00597  * cr_declaration_list_to_string2:
00598  *@a_this: the current instance of #CRDeclaration.
00599  *@a_indent: the number of indentation white char
00600  *@a_one_decl_per_line: whether to output one doc per line or not.
00601  *to put before the actual serialisation.
00602  *
00603  *Serializes the declaration list into a string
00604  *Returns the serialized form the declararation.
00605  */
00606 guchar *
00607 cr_declaration_list_to_string2 (CRDeclaration const * a_this,
00608                                 gulong a_indent, gboolean a_one_decl_per_line)
00609 {
00610         CRDeclaration const *cur = NULL;
00611         GString *stringue = NULL;
00612         guchar *str = NULL,
00613                 *result = NULL;
00614 
00615         g_return_val_if_fail (a_this, NULL);
00616 
00617         stringue = g_string_new (NULL);
00618 
00619         for (cur = a_this; cur; cur = cur->next) {
00620                 str = (guchar *) cr_declaration_to_string (cur, a_indent);
00621                 if (str) {
00622                         if (a_one_decl_per_line == TRUE) {
00623                                 if (cur->next)
00624                                         g_string_append_printf (stringue,
00625                                                                 "%s;\n", str);
00626                                 else
00627                                         g_string_append (stringue,
00628                                                          (const gchar *) str);
00629                         } else {
00630                                 if (cur->next)
00631                                         g_string_append_printf (stringue,
00632                                                                 "%s;", str);
00633                                 else
00634                                         g_string_append (stringue,
00635                                                          (const gchar *) str);
00636                         }
00637                         g_free (str);
00638                 } else
00639                         break;
00640         }
00641         if (stringue && stringue->str) {
00642                 result = (guchar *) stringue->str;
00643                 g_string_free (stringue, FALSE);
00644         }
00645 
00646         return result;
00647 }
00648 
00649 /**
00650  * cr_declaration_nr_props:
00651  *@a_this: the current instance of #CRDeclaration.
00652  *Return the number of properties in the declaration
00653  */
00654 gint
00655 cr_declaration_nr_props (CRDeclaration const * a_this)
00656 {
00657         CRDeclaration const *cur = NULL;
00658         int nr = 0;
00659 
00660         g_return_val_if_fail (a_this, -1);
00661 
00662         for (cur = a_this; cur; cur = cur->next)
00663                 nr++;
00664         return nr;
00665 }
00666 
00667 /**
00668  * cr_declaration_get_from_list:
00669  *@a_this: the current instance of #CRDeclaration.
00670  *@itemnr: the index into the declaration list.
00671  *
00672  *Use an index to get a CRDeclaration from the declaration list.
00673  *
00674  *Returns #CRDeclaration at position itemnr, 
00675  *if itemnr > number of declarations - 1,
00676  *it will return NULL.
00677  */
00678 CRDeclaration *
00679 cr_declaration_get_from_list (CRDeclaration * a_this, int itemnr)
00680 {
00681         CRDeclaration *cur = NULL;
00682         int nr = 0;
00683 
00684         g_return_val_if_fail (a_this, NULL);
00685 
00686         for (cur = a_this; cur; cur = cur->next)
00687                 if (nr++ == itemnr)
00688                         return cur;
00689         return NULL;
00690 }
00691 
00692 /**
00693  * cr_declaration_get_by_prop_name:
00694  *@a_this: the current instance of #CRDeclaration.
00695  *@a_prop: the property name to search for.
00696  *
00697  *Use property name to get a CRDeclaration from the declaration list.
00698  *Returns #CRDeclaration with property name a_prop, or NULL if not found.
00699  */
00700 CRDeclaration *
00701 cr_declaration_get_by_prop_name (CRDeclaration * a_this,
00702                                  const guchar * a_prop)
00703 {
00704         CRDeclaration *cur = NULL;
00705 
00706         g_return_val_if_fail (a_this, NULL);
00707         g_return_val_if_fail (a_prop, NULL);
00708 
00709         for (cur = a_this; cur; cur = cur->next) {
00710                 if (cur->property 
00711                     && cur->property->stryng
00712                     && cur->property->stryng->str) {
00713                         if (!strcmp (cur->property->stryng->str, 
00714                                      (const char *) a_prop)) {
00715                                 return cur;
00716                         }
00717                 }
00718         }
00719         return NULL;
00720 }
00721 
00722 /**
00723  * cr_declaration_ref:
00724  *@a_this: the current instance of #CRDeclaration.
00725  *
00726  *Increases the ref count of the current instance of #CRDeclaration.
00727  */
00728 void
00729 cr_declaration_ref (CRDeclaration * a_this)
00730 {
00731         g_return_if_fail (a_this);
00732 
00733         a_this->ref_count++;
00734 }
00735 
00736 /**
00737  * cr_declaration_unref:
00738  *@a_this: the current instance of #CRDeclaration.
00739  *
00740  *Decrements the ref count of the current instance of #CRDeclaration.
00741  *If the ref count reaches zero, the current instance of #CRDeclaration
00742  *if destroyed.
00743  *Returns TRUE if @a_this was destroyed (ref count reached zero),
00744  *FALSE otherwise.
00745  */
00746 gboolean
00747 cr_declaration_unref (CRDeclaration * a_this)
00748 {
00749         g_return_val_if_fail (a_this, FALSE);
00750 
00751         if (a_this->ref_count) {
00752                 a_this->ref_count--;
00753         }
00754 
00755         if (a_this->ref_count == 0) {
00756                 cr_declaration_destroy (a_this);
00757                 return TRUE;
00758         }
00759         return FALSE;
00760 }
00761 
00762 /**
00763  * cr_declaration_destroy:
00764  *@a_this: the current instance of #CRDeclaration.
00765  *
00766  *Destructor of the declaration list.
00767  */
00768 void
00769 cr_declaration_destroy (CRDeclaration * a_this)
00770 {
00771         CRDeclaration *cur = NULL;
00772 
00773         g_return_if_fail (a_this);
00774 
00775         /*
00776          * Go to the last element of the list.
00777          */
00778         for (cur = a_this; cur->next; cur = cur->next)
00779                 g_assert (cur->next->prev == cur);
00780 
00781         /*
00782          * Walk backward the list and free each "next" element.
00783          * Meanwhile, free each property/value pair contained in the list.
00784          */
00785         for (; cur; cur = cur->prev) {
00786                 g_free (cur->next);
00787                 cur->next = NULL;
00788 
00789                 if (cur->property) {
00790                         cr_string_destroy (cur->property);
00791                         cur->property = NULL;
00792                 }
00793 
00794                 if (cur->value) {
00795                         cr_term_destroy (cur->value);
00796                         cur->value = NULL;
00797                 }
00798         }
00799 
00800         g_free (a_this);
00801 }