Main Page | Alphabetical List | Data Structures | Directories | File List | Data Fields | Globals | Related Pages

cr-declaration.c

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

Generated on Fri Oct 29 08:29:11 2004 for Libcroco by  doxygen 1.3.9.1