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  * 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 #include <stdio.h>
00025 #include <string.h>
00026 #include "cr-term.h"
00027 #include "cr-num.h"
00028 #include "cr-parser.h"
00029 
00030 /**
00031  *@file
00032  *Definition of the #CRTem class.
00033  */
00034 
00035 static void
00036 cr_term_clear (CRTerm * a_this)
00037 {
00038         g_return_if_fail (a_this);
00039 
00040         switch (a_this->type) {
00041         case TERM_NUMBER:
00042                 if (a_this->content.num) {
00043                         cr_num_destroy (a_this->content.num);
00044                         a_this->content.num = NULL;
00045                 }
00046                 break;
00047 
00048         case TERM_FUNCTION:
00049                 if (a_this->ext_content.func_param) {
00050                         cr_term_destroy (a_this->ext_content.func_param);
00051                         a_this->ext_content.func_param = NULL;
00052                 }
00053         case TERM_STRING:
00054         case TERM_IDENT:
00055         case TERM_URI:
00056         case TERM_HASH:
00057                 if (a_this->content.str) {
00058                         cr_string_destroy (a_this->content.str);
00059                         a_this->content.str = NULL;
00060                 }
00061                 break;
00062 
00063         case TERM_RGB:
00064                 if (a_this->content.rgb) {
00065                         cr_rgb_destroy (a_this->content.rgb);
00066                         a_this->content.rgb = NULL;
00067                 }
00068                 break;
00069 
00070         case TERM_UNICODERANGE:
00071         case TERM_NO_TYPE:
00072         default:
00073                 break;
00074         }
00075 
00076         a_this->type = TERM_NO_TYPE;
00077 }
00078 
00079 /**
00080  *Instanciate a #CRTerm.
00081  *@return the newly build instance
00082  *of #CRTerm.
00083  */
00084 CRTerm *
00085 cr_term_new (void)
00086 {
00087         CRTerm *result = NULL;
00088 
00089         result = g_try_malloc (sizeof (CRTerm));
00090         if (!result) {
00091                 cr_utils_trace_info ("Out of memory");
00092                 return NULL;
00093         }
00094         memset (result, 0, sizeof (CRTerm));
00095         return result;
00096 }
00097 
00098 /**
00099  *Parses an expresion as defined by the css2 spec
00100  *and builds the expression as a list of terms.
00101  *@param a_buf the buffer to parse.
00102  *@return a pointer to the first term of the expression or
00103  *NULL if parsing failed.
00104  */
00105 CRTerm *
00106 cr_term_parse_expression_from_buf (const guchar * a_buf,
00107                                    enum CREncoding a_encoding)
00108 {
00109         CRParser *parser = NULL;
00110         CRTerm *result = NULL;
00111         enum CRStatus status = CR_OK;
00112 
00113         g_return_val_if_fail (a_buf, NULL);
00114 
00115         parser = cr_parser_new_from_buf ((guchar*)a_buf, strlen (a_buf),
00116                                          a_encoding, FALSE);
00117         g_return_val_if_fail (parser, NULL);
00118 
00119         status = cr_parser_try_to_skip_spaces_and_comments (parser);
00120         if (status != CR_OK) {
00121                 goto cleanup;
00122         }
00123         status = cr_parser_parse_expr (parser, &result);
00124         if (status != CR_OK) {
00125                 if (result) {
00126                         cr_term_destroy (result);
00127                         result = NULL;
00128                 }
00129         }
00130 
00131       cleanup:
00132         if (parser) {
00133                 cr_parser_destroy (parser);
00134                 parser = NULL;
00135         }
00136 
00137         return result;
00138 }
00139 
00140 enum CRStatus
00141 cr_term_set_number (CRTerm * a_this, CRNum * a_num)
00142 {
00143         g_return_val_if_fail (a_this, CR_BAD_PARAM_ERROR);
00144 
00145         cr_term_clear (a_this);
00146 
00147         a_this->type = TERM_NUMBER;
00148         a_this->content.num = a_num;
00149         return CR_OK;
00150 }
00151 
00152 enum CRStatus
00153 cr_term_set_function (CRTerm * a_this, CRString * a_func_name,
00154                       CRTerm * a_func_param)
00155 {
00156         g_return_val_if_fail (a_this, CR_BAD_PARAM_ERROR);
00157 
00158         cr_term_clear (a_this);
00159 
00160         a_this->type = TERM_FUNCTION;
00161         a_this->content.str = a_func_name;
00162         a_this->ext_content.func_param = a_func_param;
00163         return CR_OK;
00164 }
00165 
00166 enum CRStatus
00167 cr_term_set_string (CRTerm * a_this, CRString * a_str)
00168 {
00169         g_return_val_if_fail (a_this, CR_BAD_PARAM_ERROR);
00170 
00171         cr_term_clear (a_this);
00172 
00173         a_this->type = TERM_STRING;
00174         a_this->content.str = a_str;
00175         return CR_OK;
00176 }
00177 
00178 enum CRStatus
00179 cr_term_set_ident (CRTerm * a_this, CRString * a_str)
00180 {
00181         g_return_val_if_fail (a_this, CR_BAD_PARAM_ERROR);
00182 
00183         cr_term_clear (a_this);
00184 
00185         a_this->type = TERM_IDENT;
00186         a_this->content.str = a_str;
00187         return CR_OK;
00188 }
00189 
00190 enum CRStatus
00191 cr_term_set_uri (CRTerm * a_this, CRString * a_str)
00192 {
00193         g_return_val_if_fail (a_this, CR_BAD_PARAM_ERROR);
00194 
00195         cr_term_clear (a_this);
00196 
00197         a_this->type = TERM_URI;
00198         a_this->content.str = a_str;
00199         return CR_OK;
00200 }
00201 
00202 enum CRStatus
00203 cr_term_set_rgb (CRTerm * a_this, CRRgb * a_rgb)
00204 {
00205         g_return_val_if_fail (a_this, CR_BAD_PARAM_ERROR);
00206 
00207         cr_term_clear (a_this);
00208 
00209         a_this->type = TERM_RGB;
00210         a_this->content.rgb = a_rgb;
00211         return CR_OK;
00212 }
00213 
00214 enum CRStatus
00215 cr_term_set_hash (CRTerm * a_this, CRString * a_str)
00216 {
00217         g_return_val_if_fail (a_this, CR_BAD_PARAM_ERROR);
00218 
00219         cr_term_clear (a_this);
00220 
00221         a_this->type = TERM_HASH;
00222         a_this->content.str = a_str;
00223         return CR_OK;
00224 }
00225 
00226 /**
00227  *Appends a new term to the current list of #CRTerm.
00228  *
00229  *@param a_this the "this pointer" of the current instance
00230  *of #CRTerm .
00231  *@param a_new_term the term to append.
00232  *@return the list of terms with the a_new_term appended to it.
00233  */
00234 CRTerm *
00235 cr_term_append_term (CRTerm * a_this, CRTerm * a_new_term)
00236 {
00237         CRTerm *cur = NULL;
00238 
00239         g_return_val_if_fail (a_new_term, NULL);
00240 
00241         if (a_this == NULL)
00242                 return a_new_term;
00243 
00244         for (cur = a_this; cur->next; cur = cur->next) ;
00245 
00246         cur->next = a_new_term;
00247         a_new_term->prev = cur;
00248 
00249         return a_this;
00250 }
00251 
00252 /**
00253  *Prepends a term to the list of terms represented by a_this.
00254  *
00255  *@param a_this the "this pointer" of the current instance of
00256  *#CRTerm .
00257  *@param a_new_term the term to prepend.
00258  *@return the head of the new list.
00259  */
00260 CRTerm *
00261 cr_term_prepend_term (CRTerm * a_this, CRTerm * a_new_term)
00262 {
00263         g_return_val_if_fail (a_this && a_new_term, NULL);
00264 
00265         a_new_term->next = a_this;
00266         a_this->prev = a_new_term;
00267 
00268         return a_new_term;
00269 }
00270 
00271 /**
00272  *Serializes the expression represented by
00273  *the chained instances of #CRterm.
00274  *@param a_this the current instance of #CRTerm
00275  *@return the zero terminated string containing the serialized
00276  *form of #CRTerm. MUST BE FREED BY THE CALLER using g_free().
00277  */
00278 guchar *
00279 cr_term_to_string (CRTerm * a_this)
00280 {
00281         GString *str_buf = NULL;
00282         CRTerm *cur = NULL;
00283         guchar *result = NULL,
00284                 *content = NULL;
00285 
00286         g_return_val_if_fail (a_this, NULL);
00287 
00288         str_buf = g_string_new (NULL);
00289         g_return_val_if_fail (str_buf, NULL);
00290 
00291         for (cur = a_this; cur; cur = cur->next) {
00292                 if ((cur->content.str == NULL)
00293                     && (cur->content.num == NULL)
00294                     && (cur->content.str == NULL)
00295                     && (cur->content.rgb == NULL))
00296                         continue;
00297 
00298                 switch (cur->the_operator) {
00299                 case DIVIDE:
00300                         g_string_append (str_buf, " / ");
00301                         break;
00302 
00303                 case COMMA:
00304                         g_string_append (str_buf, ", ");
00305                         break;
00306 
00307                 case NO_OP:
00308                         if (cur->prev) {
00309                                 g_string_append (str_buf, " ");
00310                         }
00311                         break;
00312                 default:
00313 
00314                         break;
00315                 }
00316 
00317                 switch (cur->unary_op) {
00318                 case PLUS_UOP:
00319                         g_string_append (str_buf, "+");
00320                         break;
00321 
00322                 case MINUS_UOP:
00323                         g_string_append (str_buf, "-");
00324                         break;
00325 
00326                 default:
00327                         break;
00328                 }
00329 
00330                 switch (cur->type) {
00331                 case TERM_NUMBER:
00332                         if (cur->content.num) {
00333                                 content = cr_num_to_string (cur->content.num);
00334                         }
00335 
00336                         if (content) {
00337                                 g_string_append (str_buf, content);
00338                                 g_free (content);
00339                                 content = NULL;
00340                         }
00341 
00342                         break;
00343 
00344                 case TERM_FUNCTION:
00345                         if (cur->content.str) {
00346                                 content = g_strndup
00347                                         (cur->content.str->stryng->str,
00348                                          cur->content.str->stryng->len);
00349                         }
00350 
00351                         if (content) {
00352                                 g_string_append_printf (str_buf, "%s(",
00353                                                         content);
00354 
00355                                 if (cur->ext_content.func_param) {
00356                                         guchar *tmp_str = NULL;
00357 
00358                                         tmp_str = cr_term_to_string
00359                                                 (cur->
00360                                                  ext_content.func_param);
00361 
00362                                         if (tmp_str) {
00363                                                 g_string_append (str_buf, 
00364                                                                  tmp_str);
00365                                                 g_free (tmp_str);
00366                                                 tmp_str = NULL;
00367                                         }
00368 
00369                                         g_free (content);
00370                                         content = NULL;
00371                                 }
00372                                 g_string_append (str_buf, ")");
00373                         }
00374 
00375                         break;
00376 
00377                 case TERM_STRING:
00378                         if (cur->content.str) {
00379                                 content = g_strndup
00380                                         (cur->content.str->stryng->str,
00381                                          cur->content.str->stryng->len);
00382                         }
00383 
00384                         if (content) {
00385                                 g_string_append_printf (str_buf,
00386                                                         "\"%s\"", content);
00387                                 g_free (content);
00388                                 content = NULL;
00389                         }
00390                         break;
00391 
00392                 case TERM_IDENT:
00393                         if (cur->content.str) {
00394                                 content = g_strndup
00395                                         (cur->content.str->stryng->str,
00396                                          cur->content.str->stryng->len);
00397                         }
00398 
00399                         if (content) {
00400                                 g_string_append (str_buf, content);
00401                                 g_free (content);
00402                                 content = NULL;
00403                         }
00404                         break;
00405 
00406                 case TERM_URI:
00407                         if (cur->content.str) {
00408                                 content = g_strndup
00409                                         (cur->content.str->stryng->str,
00410                                          cur->content.str->stryng->len);
00411                         }
00412 
00413                         if (content) {
00414                                 g_string_append_printf
00415                                         (str_buf, "url(%s)", content);
00416                                 g_free (content);
00417                                 content = NULL;
00418                         }
00419                         break;
00420 
00421                 case TERM_RGB:
00422                         if (cur->content.rgb) {
00423                                 guchar *tmp_str = NULL;
00424 
00425                                 g_string_append (str_buf, "rgb(");
00426                                 tmp_str = cr_rgb_to_string (cur->content.rgb);
00427 
00428                                 if (tmp_str) {
00429                                         g_string_append (str_buf, tmp_str);
00430                                         g_free (tmp_str);
00431                                         tmp_str = NULL;
00432                                 }
00433                                 g_string_append (str_buf, ")");
00434                         }
00435 
00436                         break;
00437 
00438                 case TERM_UNICODERANGE:
00439                         g_string_append
00440                                 (str_buf,
00441                                  "?found unicoderange: dump not supported yet?");
00442                         break;
00443 
00444                 case TERM_HASH:
00445                         if (cur->content.str) {
00446                                 content = g_strndup
00447                                         (cur->content.str->stryng->str,
00448                                          cur->content.str->stryng->len);
00449                         }
00450 
00451                         if (content) {
00452                                 g_string_append_printf (str_buf,
00453                                                         "#%s", content);
00454                                 g_free (content);
00455                                 content = NULL;
00456                         }
00457                         break;
00458 
00459                 default:
00460                         g_string_append (str_buf,
00461                                          "Unrecognized Term type");
00462                         break;
00463                 }
00464         }
00465 
00466         if (str_buf) {
00467                 result = str_buf->str;
00468                 g_string_free (str_buf, FALSE);
00469                 str_buf = NULL;
00470         }
00471 
00472         return result;
00473 }
00474 
00475 guchar *
00476 cr_term_one_to_string (CRTerm * a_this)
00477 {
00478         GString *str_buf = NULL;
00479         guchar *result = NULL,
00480                 *content = NULL;
00481 
00482         g_return_val_if_fail (a_this, NULL);
00483 
00484         str_buf = g_string_new (NULL);
00485         g_return_val_if_fail (str_buf, NULL);
00486 
00487         if ((a_this->content.str == NULL)
00488             && (a_this->content.num == NULL)
00489             && (a_this->content.str == NULL)
00490             && (a_this->content.rgb == NULL))
00491                 return NULL ;
00492 
00493         switch (a_this->the_operator) {
00494         case DIVIDE:
00495                 g_string_append_printf (str_buf, " / ");
00496                 break;
00497 
00498         case COMMA:
00499                 g_string_append_printf (str_buf, ", ");
00500                 break;
00501 
00502         case NO_OP:
00503                 if (a_this->prev) {
00504                         g_string_append_printf (str_buf, " ");
00505                 }
00506                 break;
00507         default:
00508 
00509                 break;
00510         }
00511 
00512         switch (a_this->unary_op) {
00513         case PLUS_UOP:
00514                 g_string_append_printf (str_buf, "+");
00515                 break;
00516 
00517         case MINUS_UOP:
00518                 g_string_append_printf (str_buf, "-");
00519                 break;
00520 
00521         default:
00522                 break;
00523         }
00524 
00525         switch (a_this->type) {
00526         case TERM_NUMBER:
00527                 if (a_this->content.num) {
00528                         content = cr_num_to_string (a_this->content.num);
00529                 }
00530 
00531                 if (content) {
00532                         g_string_append (str_buf, content);
00533                         g_free (content);
00534                         content = NULL;
00535                 }
00536 
00537                 break;
00538 
00539         case TERM_FUNCTION:
00540                 if (a_this->content.str) {
00541                         content = g_strndup
00542                                 (a_this->content.str->stryng->str,
00543                                  a_this->content.str->stryng->len);
00544                 }
00545 
00546                 if (content) {
00547                         g_string_append_printf (str_buf, "%s(",
00548                                                 content);
00549 
00550                         if (a_this->ext_content.func_param) {
00551                                 guchar *tmp_str = NULL;
00552 
00553                                 tmp_str = cr_term_to_string
00554                                         (a_this->
00555                                          ext_content.func_param);
00556 
00557                                 if (tmp_str) {
00558                                         g_string_append_printf
00559                                                 (str_buf,
00560                                                  "%s", tmp_str);
00561                                         g_free (tmp_str);
00562                                         tmp_str = NULL;
00563                                 }
00564 
00565                                 g_string_append_printf (str_buf, ")");
00566                                 g_free (content);
00567                                 content = NULL;
00568                         }
00569                 }
00570 
00571                 break;
00572 
00573         case TERM_STRING:
00574                 if (a_this->content.str) {
00575                         content = g_strndup
00576                                 (a_this->content.str->stryng->str,
00577                                  a_this->content.str->stryng->len);
00578                 }
00579 
00580                 if (content) {
00581                         g_string_append_printf (str_buf,
00582                                                 "\"%s\"", content);
00583                         g_free (content);
00584                         content = NULL;
00585                 }
00586                 break;
00587 
00588         case TERM_IDENT:
00589                 if (a_this->content.str) {
00590                         content = g_strndup
00591                                 (a_this->content.str->stryng->str,
00592                                  a_this->content.str->stryng->len);
00593                 }
00594 
00595                 if (content) {
00596                         g_string_append (str_buf, content);
00597                         g_free (content);
00598                         content = NULL;
00599                 }
00600                 break;
00601 
00602         case TERM_URI:
00603                 if (a_this->content.str) {
00604                         content = g_strndup
00605                                 (a_this->content.str->stryng->str,
00606                                  a_this->content.str->stryng->len);
00607                 }
00608 
00609                 if (content) {
00610                         g_string_append_printf
00611                                 (str_buf, "url(%s)", content);
00612                         g_free (content);
00613                         content = NULL;
00614                 }
00615                 break;
00616 
00617         case TERM_RGB:
00618                 if (a_this->content.rgb) {
00619                         guchar *tmp_str = NULL;
00620 
00621                         g_string_append_printf (str_buf, "rgb(");
00622                         tmp_str = cr_rgb_to_string (a_this->content.rgb);
00623 
00624                         if (tmp_str) {
00625                                 g_string_append (str_buf, tmp_str);
00626                                 g_free (tmp_str);
00627                                 tmp_str = NULL;
00628                         }
00629                         g_string_append_printf (str_buf, ")");
00630                 }
00631 
00632                 break;
00633 
00634         case TERM_UNICODERANGE:
00635                 g_string_append_printf
00636                         (str_buf,
00637                          "?found unicoderange: dump not supported yet?");
00638                 break;
00639 
00640         case TERM_HASH:
00641                 if (a_this->content.str) {
00642                         content = g_strndup
00643                                 (a_this->content.str->stryng->str,
00644                                  a_this->content.str->stryng->len);
00645                 }
00646 
00647                 if (content) {
00648                         g_string_append_printf (str_buf,
00649                                                 "#%s", content);
00650                         g_free (content);
00651                         content = NULL;
00652                 }
00653                 break;
00654 
00655         default:
00656                 g_string_append_printf (str_buf,
00657                                         "%s",
00658                                         "Unrecognized Term type");
00659                 break;
00660         }
00661 
00662         if (str_buf) {
00663                 result = str_buf->str;
00664                 g_string_free (str_buf, FALSE);
00665                 str_buf = NULL;
00666         }
00667 
00668         return result;
00669 }
00670 
00671 /**
00672  *Dumps the expression (a list of terms connected by operators)
00673  *to a file.
00674  *TODO: finish the dump. The dump of some type of terms have not yet been
00675  *implemented.
00676  *@param a_this the current instance of #CRTerm.
00677  *@param a_fp the destination file pointer.
00678  */
00679 void
00680 cr_term_dump (CRTerm * a_this, FILE * a_fp)
00681 {
00682         guchar *content = NULL;
00683 
00684         g_return_if_fail (a_this);
00685 
00686         content = cr_term_to_string (a_this);
00687 
00688         if (content) {
00689                 fprintf (a_fp, "%s", content);
00690                 g_free (content);
00691         }
00692 }
00693 
00694 /**
00695  *Return the number of terms in the expression.
00696  *@param a_this the current instance of #CRTerm.
00697  *@return number of terms in the expression.
00698  */
00699 int
00700 cr_term_nr_values (CRTerm *a_this)
00701 {
00702         CRTerm *cur = NULL ;
00703         int nr = 0;
00704 
00705         g_return_val_if_fail (a_this, -1) ;
00706 
00707         for (cur = a_this ; cur ; cur = cur->next)
00708                 nr ++;
00709         return nr;
00710 }
00711 
00712 /**
00713  *Use an index to get a CRTerm from the expression.
00714  *@param a_this the current instance of #CRTerm.
00715  *@param itemnr the index into the expression.
00716  *@return CRTerm at position itemnr, if itemnr > number of terms - 1,
00717  *it will return NULL.
00718  */
00719 CRTerm *
00720 cr_term_get_from_list (CRTerm *a_this, int itemnr)
00721 {
00722         CRTerm *cur = NULL ;
00723         int nr = 0;
00724 
00725         g_return_val_if_fail (a_this, NULL) ;
00726 
00727         for (cur = a_this ; cur ; cur = cur->next)
00728                 if (nr++ == itemnr)
00729                         return cur;
00730         return NULL;
00731 }
00732 
00733 /**
00734  *Increments the reference counter of the current instance
00735  *of #CRTerm.*
00736  *@param a_this the current instance of #CRTerm.
00737  */
00738 void
00739 cr_term_ref (CRTerm * a_this)
00740 {
00741         g_return_if_fail (a_this);
00742 
00743         a_this->ref_count++;
00744 }
00745 
00746 /**
00747  *Decrements the ref count of the current instance of
00748  *#CRTerm. If the ref count reaches zero, the instance is
00749  *destroyed.
00750  *@param a_this the current instance of #CRTerm.
00751  *@return TRUE if the current instance has been destroyed, FALSE otherwise.
00752  */
00753 gboolean
00754 cr_term_unref (CRTerm * a_this)
00755 {
00756         g_return_val_if_fail (a_this, FALSE);
00757 
00758         if (a_this->ref_count) {
00759                 a_this->ref_count--;
00760         }
00761 
00762         if (a_this->ref_count == 0) {
00763                 cr_term_destroy (a_this);
00764                 return TRUE;
00765         }
00766 
00767         return FALSE;
00768 }
00769 
00770 /**
00771  *The destructor of the the #CRTerm class.
00772  *@param a_this the "this pointer" of the current instance
00773  *of #CRTerm.
00774  */
00775 void
00776 cr_term_destroy (CRTerm * a_this)
00777 {
00778         g_return_if_fail (a_this);
00779 
00780         cr_term_clear (a_this);
00781 
00782         if (a_this->next) {
00783                 cr_term_destroy (a_this->next);
00784                 a_this->next = NULL;
00785         }
00786 
00787         if (a_this) {
00788                 g_free (a_this);
00789         }
00790 
00791 }

Generated on Thu Mar 9 19:18:50 2006 for Libcroco by  doxygen 1.4.6