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

cr-term.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  * Copyright (C) 2002-2003 Dodji Seketeli <dodji@seketeli.org>
00007  *
00008  * This program is free software; you can redistribute it and/or
00009  * modify it under the terms of version 2.1 of the GNU Lesser General Public
00010  * License as published by the Free Software Foundation.
00011  *
00012  * This program is distributed in the hope that it will be useful,
00013  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00014  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00015  * GNU General Public License for more details.
00016  *
00017  * You should have received a copy of the GNU Lesser General Public License
00018  * along with this program; if not, write to the Free Software
00019  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
00020  * USA
00021  */
00022 
00023 /*
00024  *$Id: cr-term.c,v 1.9.2.1 2004/04/18 13:07:22 dodji Exp $
00025  */
00026 #include <stdio.h>
00027 #include <string.h>
00028 #include "cr-term.h"
00029 #include "cr-num.h"
00030 #include "cr-parser.h"
00031 
00032 /**
00033  *@file
00034  *Definition of the #CRTem class.
00035  */
00036 
00037 static void
00038 cr_term_clear (CRTerm * a_this)
00039 {
00040         g_return_if_fail (a_this);
00041 
00042         switch (a_this->type) {
00043         case TERM_NUMBER:
00044                 if (a_this->content.num) {
00045                         cr_num_destroy (a_this->content.num);
00046                         a_this->content.num = NULL;
00047                 }
00048                 break;
00049 
00050         case TERM_FUNCTION:
00051                 if (a_this->ext_content.func_param) {
00052                         cr_term_destroy (a_this->ext_content.func_param);
00053                         a_this->ext_content.func_param = NULL;
00054                 }
00055         case TERM_STRING:
00056         case TERM_IDENT:
00057         case TERM_URI:
00058         case TERM_HASH:
00059                 if (a_this->content.str) {
00060                         g_string_free (a_this->content.str, TRUE);
00061                         a_this->content.str = NULL;
00062                 }
00063                 break;
00064 
00065         case TERM_RGB:
00066                 if (a_this->content.rgb) {
00067                         cr_rgb_destroy (a_this->content.rgb);
00068                         a_this->content.rgb = NULL;
00069                 }
00070                 break;
00071 
00072         case TERM_UNICODERANGE:
00073         case TERM_NO_TYPE:
00074         default:
00075                 break;
00076         }
00077 
00078         a_this->type = TERM_NO_TYPE;
00079 }
00080 
00081 /**
00082  *Instanciate a #CRTerm.
00083  *@return the newly build instance
00084  *of #CRTerm.
00085  */
00086 CRTerm *
00087 cr_term_new (void)
00088 {
00089         CRTerm *result = NULL;
00090 
00091         result = g_try_malloc (sizeof (CRTerm));
00092         if (!result) {
00093                 cr_utils_trace_info ("Out of memory");
00094                 return NULL;
00095         }
00096         memset (result, 0, sizeof (CRTerm));
00097         return result;
00098 }
00099 
00100 /**
00101  *Parses an expresion as defined by the css2 spec
00102  *and builds the expression as a list of terms.
00103  *@param a_buf the buffer to parse.
00104  *@return a pointer to the first term of the expression or
00105  *NULL if parsing failed.
00106  */
00107 CRTerm *
00108 cr_term_parse_expression_from_buf (const guchar * a_buf,
00109                                    enum CREncoding a_encoding)
00110 {
00111         CRParser *parser = NULL;
00112         CRTerm *result = NULL;
00113         enum CRStatus status = CR_OK;
00114 
00115         g_return_val_if_fail (a_buf, NULL);
00116 
00117         parser = cr_parser_new_from_buf ((guchar*)a_buf, strlen (a_buf),
00118                                          a_encoding, FALSE);
00119         g_return_val_if_fail (parser, NULL);
00120 
00121         status = cr_parser_try_to_skip_spaces_and_comments (parser);
00122         if (status != CR_OK) {
00123                 goto cleanup;
00124         }
00125         status = cr_parser_parse_expr (parser, &result);
00126         if (status != CR_OK) {
00127                 if (result) {
00128                         cr_term_destroy (result);
00129                         result = NULL;
00130                 }
00131         }
00132 
00133       cleanup:
00134         if (parser) {
00135                 cr_parser_destroy (parser);
00136                 parser = NULL;
00137         }
00138 
00139         return result;
00140 }
00141 
00142 enum CRStatus
00143 cr_term_set_number (CRTerm * a_this, CRNum * a_num)
00144 {
00145         g_return_val_if_fail (a_this, CR_BAD_PARAM_ERROR);
00146 
00147         cr_term_clear (a_this);
00148 
00149         a_this->type = TERM_NUMBER;
00150         a_this->content.num = a_num;
00151         return CR_OK;
00152 }
00153 
00154 enum CRStatus
00155 cr_term_set_function (CRTerm * a_this, GString * a_func_name,
00156                       CRTerm * a_func_param)
00157 {
00158         g_return_val_if_fail (a_this, CR_BAD_PARAM_ERROR);
00159 
00160         cr_term_clear (a_this);
00161 
00162         a_this->type = TERM_FUNCTION;
00163         a_this->content.str = a_func_name;
00164         a_this->ext_content.func_param = a_func_param;
00165         return CR_OK;
00166 }
00167 
00168 enum CRStatus
00169 cr_term_set_string (CRTerm * a_this, GString * a_str)
00170 {
00171         g_return_val_if_fail (a_this, CR_BAD_PARAM_ERROR);
00172 
00173         cr_term_clear (a_this);
00174 
00175         a_this->type = TERM_STRING;
00176         a_this->content.str = a_str;
00177         return CR_OK;
00178 }
00179 
00180 enum CRStatus
00181 cr_term_set_ident (CRTerm * a_this, GString * a_str)
00182 {
00183         g_return_val_if_fail (a_this, CR_BAD_PARAM_ERROR);
00184 
00185         cr_term_clear (a_this);
00186 
00187         a_this->type = TERM_IDENT;
00188         a_this->content.str = a_str;
00189         return CR_OK;
00190 }
00191 
00192 enum CRStatus
00193 cr_term_set_uri (CRTerm * a_this, GString * a_str)
00194 {
00195         g_return_val_if_fail (a_this, CR_BAD_PARAM_ERROR);
00196 
00197         cr_term_clear (a_this);
00198 
00199         a_this->type = TERM_URI;
00200         a_this->content.str = a_str;
00201         return CR_OK;
00202 }
00203 
00204 enum CRStatus
00205 cr_term_set_rgb (CRTerm * a_this, CRRgb * a_rgb)
00206 {
00207         g_return_val_if_fail (a_this, CR_BAD_PARAM_ERROR);
00208 
00209         cr_term_clear (a_this);
00210 
00211         a_this->type = TERM_RGB;
00212         a_this->content.rgb = a_rgb;
00213         return CR_OK;
00214 }
00215 
00216 enum CRStatus
00217 cr_term_set_hash (CRTerm * a_this, GString * a_str)
00218 {
00219         g_return_val_if_fail (a_this, CR_BAD_PARAM_ERROR);
00220 
00221         cr_term_clear (a_this);
00222 
00223         a_this->type = TERM_HASH;
00224         a_this->content.str = a_str;
00225         return CR_OK;
00226 }
00227 
00228 /**
00229  *Appends a new term to the current list of #CRTerm.
00230  *
00231  *@param a_this the "this pointer" of the current instance
00232  *of #CRTerm .
00233  *@param a_new_term the term to append.
00234  *@return the list of terms with the a_new_term appended to it.
00235  */
00236 CRTerm *
00237 cr_term_append_term (CRTerm * a_this, CRTerm * a_new_term)
00238 {
00239         CRTerm *cur = NULL;
00240 
00241         g_return_val_if_fail (a_new_term, NULL);
00242 
00243         if (a_this == NULL)
00244                 return a_new_term;
00245 
00246         for (cur = a_this; cur->next; cur = cur->next) ;
00247 
00248         cur->next = a_new_term;
00249         a_new_term->prev = cur;
00250 
00251         return a_this;
00252 }
00253 
00254 /**
00255  *Prepends a term to the list of terms represented by a_this.
00256  *
00257  *@param a_this the "this pointer" of the current instance of
00258  *#CRTerm .
00259  *@param a_new_term the term to prepend.
00260  *@return the head of the new list.
00261  */
00262 CRTerm *
00263 cr_term_prepend_term (CRTerm * a_this, CRTerm * a_new_term)
00264 {
00265         g_return_val_if_fail (a_this && a_new_term, NULL);
00266 
00267         a_new_term->next = a_this;
00268         a_this->prev = a_new_term;
00269 
00270         return a_new_term;
00271 }
00272 
00273 /**
00274  *Serializes the expression represented by
00275  *the chained instances of #CRterm.
00276  *@param a_this the current instance of #CRTerm
00277  *@return the zero terminated string containing the serialized
00278  *form of #CRTerm. MUST BE FREED BY THE CALLER using g_free().
00279  */
00280 guchar *
00281 cr_term_to_string (CRTerm * a_this)
00282 {
00283         GString *str_buf = NULL;
00284         CRTerm *cur = NULL;
00285         guchar *result = NULL,
00286                 *content = NULL;
00287 
00288         g_return_val_if_fail (a_this, NULL);
00289 
00290         str_buf = g_string_new (NULL);
00291         g_return_val_if_fail (str_buf, NULL);
00292 
00293         for (cur = a_this; cur; cur = cur->next) {
00294                 if ((cur->content.str == NULL)
00295                     && (cur->content.num == NULL)
00296                     && (cur->content.str == NULL)
00297                     && (cur->content.rgb == NULL))
00298                         continue;
00299 
00300                 switch (cur->the_operator) {
00301                 case DIVIDE:
00302                         g_string_append_printf (str_buf, " / ");
00303                         break;
00304 
00305                 case COMMA:
00306                         g_string_append_printf (str_buf, ", ");
00307                         break;
00308 
00309                 case NO_OP:
00310                         if (cur->prev) {
00311                                 g_string_append_printf (str_buf, " ");
00312                         }
00313                         break;
00314                 default:
00315 
00316                         break;
00317                 }
00318 
00319                 switch (cur->unary_op) {
00320                 case PLUS_UOP:
00321                         g_string_append_printf (str_buf, "+");
00322                         break;
00323 
00324                 case MINUS_UOP:
00325                         g_string_append_printf (str_buf, "-");
00326                         break;
00327 
00328                 default:
00329                         break;
00330                 }
00331 
00332                 switch (cur->type) {
00333                 case TERM_NUMBER:
00334                         if (cur->content.num) {
00335                                 content = cr_num_to_string (cur->content.num);
00336                         }
00337 
00338                         if (content) {
00339                                 g_string_append (str_buf, content);
00340                                 g_free (content);
00341                                 content = NULL;
00342                         }
00343 
00344                         break;
00345 
00346                 case TERM_FUNCTION:
00347                         if (cur->content.str) {
00348                                 content = g_strndup
00349                                         (cur->content.str->str,
00350                                          cur->content.str->len);
00351                         }
00352 
00353                         if (content) {
00354                                 g_string_append_printf (str_buf, "%s(",
00355                                                         content);
00356 
00357                                 if (a_this->ext_content.func_param) {
00358                                         guchar *tmp_str = NULL;
00359 
00360                                         tmp_str = cr_term_to_string
00361                                                 (a_this->
00362                                                  ext_content.func_param);
00363 
00364                                         if (tmp_str) {
00365                                                 g_string_append_printf
00366                                                         (str_buf,
00367                                                          "%s", tmp_str);
00368                                                 g_free (tmp_str);
00369                                                 tmp_str = NULL;
00370                                         }
00371 
00372                                         g_string_append_printf (str_buf, ")");
00373                                         g_free (content);
00374                                         content = NULL;
00375                                 }
00376                         }
00377 
00378                         break;
00379 
00380                 case TERM_STRING:
00381                         if (cur->content.str) {
00382                                 content = g_strndup
00383                                         (cur->content.str->str,
00384                                          cur->content.str->len);
00385                         }
00386 
00387                         if (content) {
00388                                 g_string_append_printf (str_buf,
00389                                                         "\"%s\"", content);
00390                                 g_free (content);
00391                                 content = NULL;
00392                         }
00393                         break;
00394 
00395                 case TERM_IDENT:
00396                         if (cur->content.str) {
00397                                 content = g_strndup
00398                                         (cur->content.str->str,
00399                                          cur->content.str->len);
00400                         }
00401 
00402                         if (content) {
00403                                 g_string_append (str_buf, content);
00404                                 g_free (content);
00405                                 content = NULL;
00406                         }
00407                         break;
00408 
00409                 case TERM_URI:
00410                         if (cur->content.str) {
00411                                 content = g_strndup
00412                                         (cur->content.str->str,
00413                                          cur->content.str->len);
00414                         }
00415 
00416                         if (content) {
00417                                 g_string_append_printf
00418                                         (str_buf, "url(%s)", content);
00419                                 g_free (content);
00420                                 content = NULL;
00421                         }
00422                         break;
00423 
00424                 case TERM_RGB:
00425                         if (cur->content.rgb) {
00426                                 guchar *tmp_str = NULL;
00427 
00428                                 g_string_append_printf (str_buf, "rgb(");
00429                                 tmp_str = cr_rgb_to_string (cur->content.rgb);
00430 
00431                                 if (tmp_str) {
00432                                         g_string_append (str_buf, tmp_str);
00433                                         g_free (tmp_str);
00434                                         tmp_str = NULL;
00435                                 }
00436                                 g_string_append_printf (str_buf, ")");
00437                         }
00438 
00439                         break;
00440 
00441                 case TERM_UNICODERANGE:
00442                         g_string_append_printf
00443                                 (str_buf,
00444                                  "?found unicoderange: dump not supported yet?");
00445                         break;
00446 
00447                 case TERM_HASH:
00448                         if (cur->content.str) {
00449                                 content = g_strndup
00450                                         (cur->content.str->str,
00451                                          cur->content.str->len);
00452                         }
00453 
00454                         if (content) {
00455                                 g_string_append_printf (str_buf,
00456                                                         "#%s", content);
00457                                 g_free (content);
00458                                 content = NULL;
00459                         }
00460                         break;
00461 
00462                 default:
00463                         g_string_append_printf (str_buf,
00464                                                 "%s",
00465                                                 "Unrecognized Term type");
00466                         break;
00467                 }
00468         }
00469 
00470         if (str_buf) {
00471                 result = str_buf->str;
00472                 g_string_free (str_buf, FALSE);
00473                 str_buf = NULL;
00474         }
00475 
00476         return result;
00477 }
00478 
00479 /**
00480  *Dumps the expression (a list of terms connected by operators)
00481  *to a file.
00482  *TODO: finish the dump. The dump of some type of terms have not yet been
00483  *implemented.
00484  *@param a_this the current instance of #CRTerm.
00485  *@param a_fp the destination file pointer.
00486  */
00487 void
00488 cr_term_dump (CRTerm * a_this, FILE * a_fp)
00489 {
00490         guchar *content = NULL;
00491 
00492         g_return_if_fail (a_this);
00493 
00494         content = cr_term_to_string (a_this);
00495 
00496         if (content) {
00497                 fprintf (a_fp, "%s", content);
00498                 g_free (content);
00499         }
00500 }
00501 
00502 /**
00503  *Return the number of terms in the expression.
00504  *@param a_this the current instance of #CRTerm.
00505  *@return number of terms in the expression.
00506  */
00507 int
00508 cr_term_nr_values (CRTerm *a_this)
00509 {
00510         CRTerm *cur = NULL ;
00511         int nr = 0;
00512 
00513         g_return_val_if_fail (a_this, -1) ;
00514 
00515         for (cur = a_this ; cur ; cur = cur->next)
00516                 nr ++;
00517         return nr;
00518 }
00519 
00520 /**
00521  *Use an index to get a CRTerm from the expression.
00522  *@param a_this the current instance of #CRTerm.
00523  *@param itemnr the index into the expression.
00524  *@return CRTerm at position itemnr, if itemnr > number of terms - 1,
00525  *it will return NULL.
00526  */
00527 CRTerm *
00528 cr_term_get_from_list (CRTerm *a_this, int itemnr)
00529 {
00530         CRTerm *cur = NULL ;
00531         int nr = 0;
00532 
00533         g_return_val_if_fail (a_this, NULL) ;
00534 
00535         for (cur = a_this ; cur ; cur = cur->next)
00536                 if (nr++ == itemnr)
00537                         return cur;
00538         return NULL;
00539 }
00540 
00541 /**
00542  *Increments the reference counter of the current instance
00543  *of #CRTerm.*
00544  *@param a_this the current instance of #CRTerm.
00545  */
00546 void
00547 cr_term_ref (CRTerm * a_this)
00548 {
00549         g_return_if_fail (a_this);
00550 
00551         a_this->ref_count++;
00552 }
00553 
00554 /**
00555  *Decrements the ref count of the current instance of
00556  *#CRTerm. If the ref count reaches zero, the instance is
00557  *destroyed.
00558  *@param a_this the current instance of #CRTerm.
00559  *@return TRUE if the current instance has been destroyed, FALSE otherwise.
00560  */
00561 gboolean
00562 cr_term_unref (CRTerm * a_this)
00563 {
00564         g_return_val_if_fail (a_this, FALSE);
00565 
00566         if (a_this->ref_count) {
00567                 a_this->ref_count--;
00568         }
00569 
00570         if (a_this->ref_count == 0) {
00571                 cr_term_destroy (a_this);
00572                 return TRUE;
00573         }
00574 
00575         return FALSE;
00576 }
00577 
00578 /**
00579  *The destructor of the the #CRTerm class.
00580  *@param a_this the "this pointer" of the current instance
00581  *of #CRTerm.
00582  */
00583 void
00584 cr_term_destroy (CRTerm * a_this)
00585 {
00586         g_return_if_fail (a_this);
00587 
00588         cr_term_clear (a_this);
00589 
00590         if (a_this->next) {
00591                 cr_term_destroy (a_this->next);
00592                 a_this->next = NULL;
00593         }
00594 
00595         if (a_this) {
00596                 g_free (a_this);
00597         }
00598 
00599 }

Generated on Tue Apr 27 13:46:36 2004 for Libcroco by doxygen 1.3.6