Libcroco
|
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 ((const char *) 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 const * a_this) 00280 { 00281 GString *str_buf = NULL; 00282 CRTerm const *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, (const gchar *) content); 00338 g_free (content); 00339 content = NULL; 00340 } 00341 00342 break; 00343 00344 case TERM_FUNCTION: 00345 if (cur->content.str) { 00346 content = (guchar *) 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 (const gchar *) tmp_str); 00365 g_free (tmp_str); 00366 tmp_str = NULL; 00367 } 00368 } 00369 g_string_append (str_buf, ")"); 00370 g_free (content); 00371 content = NULL; 00372 } 00373 00374 break; 00375 00376 case TERM_STRING: 00377 if (cur->content.str) { 00378 content = (guchar *) g_strndup 00379 (cur->content.str->stryng->str, 00380 cur->content.str->stryng->len); 00381 } 00382 00383 if (content) { 00384 g_string_append_printf (str_buf, 00385 "\"%s\"", content); 00386 g_free (content); 00387 content = NULL; 00388 } 00389 break; 00390 00391 case TERM_IDENT: 00392 if (cur->content.str) { 00393 content = (guchar *) g_strndup 00394 (cur->content.str->stryng->str, 00395 cur->content.str->stryng->len); 00396 } 00397 00398 if (content) { 00399 g_string_append (str_buf, (const gchar *) content); 00400 g_free (content); 00401 content = NULL; 00402 } 00403 break; 00404 00405 case TERM_URI: 00406 if (cur->content.str) { 00407 content = (guchar *) g_strndup 00408 (cur->content.str->stryng->str, 00409 cur->content.str->stryng->len); 00410 } 00411 00412 if (content) { 00413 g_string_append_printf 00414 (str_buf, "url(%s)", content); 00415 g_free (content); 00416 content = NULL; 00417 } 00418 break; 00419 00420 case TERM_RGB: 00421 if (cur->content.rgb) { 00422 guchar *tmp_str = NULL; 00423 00424 g_string_append (str_buf, "rgb("); 00425 tmp_str = cr_rgb_to_string (cur->content.rgb); 00426 00427 if (tmp_str) { 00428 g_string_append (str_buf, (const gchar *) tmp_str); 00429 g_free (tmp_str); 00430 tmp_str = NULL; 00431 } 00432 g_string_append (str_buf, ")"); 00433 } 00434 00435 break; 00436 00437 case TERM_UNICODERANGE: 00438 g_string_append 00439 (str_buf, 00440 "?found unicoderange: dump not supported yet?"); 00441 break; 00442 00443 case TERM_HASH: 00444 if (cur->content.str) { 00445 content = (guchar *) g_strndup 00446 (cur->content.str->stryng->str, 00447 cur->content.str->stryng->len); 00448 } 00449 00450 if (content) { 00451 g_string_append_printf (str_buf, 00452 "#%s", content); 00453 g_free (content); 00454 content = NULL; 00455 } 00456 break; 00457 00458 default: 00459 g_string_append (str_buf, 00460 "Unrecognized Term type"); 00461 break; 00462 } 00463 } 00464 00465 if (str_buf) { 00466 result =(guchar *) str_buf->str; 00467 g_string_free (str_buf, FALSE); 00468 str_buf = NULL; 00469 } 00470 00471 return result; 00472 } 00473 00474 guchar * 00475 cr_term_one_to_string (CRTerm const * a_this) 00476 { 00477 GString *str_buf = NULL; 00478 guchar *result = NULL, 00479 *content = NULL; 00480 00481 g_return_val_if_fail (a_this, NULL); 00482 00483 str_buf = g_string_new (NULL); 00484 g_return_val_if_fail (str_buf, NULL); 00485 00486 if ((a_this->content.str == NULL) 00487 && (a_this->content.num == NULL) 00488 && (a_this->content.str == NULL) 00489 && (a_this->content.rgb == NULL)) 00490 return NULL ; 00491 00492 switch (a_this->the_operator) { 00493 case DIVIDE: 00494 g_string_append_printf (str_buf, " / "); 00495 break; 00496 00497 case COMMA: 00498 g_string_append_printf (str_buf, ", "); 00499 break; 00500 00501 case NO_OP: 00502 if (a_this->prev) { 00503 g_string_append_printf (str_buf, " "); 00504 } 00505 break; 00506 default: 00507 00508 break; 00509 } 00510 00511 switch (a_this->unary_op) { 00512 case PLUS_UOP: 00513 g_string_append_printf (str_buf, "+"); 00514 break; 00515 00516 case MINUS_UOP: 00517 g_string_append_printf (str_buf, "-"); 00518 break; 00519 00520 default: 00521 break; 00522 } 00523 00524 switch (a_this->type) { 00525 case TERM_NUMBER: 00526 if (a_this->content.num) { 00527 content = cr_num_to_string (a_this->content.num); 00528 } 00529 00530 if (content) { 00531 g_string_append (str_buf, (const gchar *) content); 00532 g_free (content); 00533 content = NULL; 00534 } 00535 00536 break; 00537 00538 case TERM_FUNCTION: 00539 if (a_this->content.str) { 00540 content = (guchar *) g_strndup 00541 (a_this->content.str->stryng->str, 00542 a_this->content.str->stryng->len); 00543 } 00544 00545 if (content) { 00546 g_string_append_printf (str_buf, "%s(", 00547 content); 00548 00549 if (a_this->ext_content.func_param) { 00550 guchar *tmp_str = NULL; 00551 00552 tmp_str = cr_term_to_string 00553 (a_this-> 00554 ext_content.func_param); 00555 00556 if (tmp_str) { 00557 g_string_append_printf 00558 (str_buf, 00559 "%s", tmp_str); 00560 g_free (tmp_str); 00561 tmp_str = NULL; 00562 } 00563 00564 g_string_append_printf (str_buf, ")"); 00565 g_free (content); 00566 content = NULL; 00567 } 00568 } 00569 00570 break; 00571 00572 case TERM_STRING: 00573 if (a_this->content.str) { 00574 content = (guchar *) g_strndup 00575 (a_this->content.str->stryng->str, 00576 a_this->content.str->stryng->len); 00577 } 00578 00579 if (content) { 00580 g_string_append_printf (str_buf, 00581 "\"%s\"", content); 00582 g_free (content); 00583 content = NULL; 00584 } 00585 break; 00586 00587 case TERM_IDENT: 00588 if (a_this->content.str) { 00589 content = (guchar *) g_strndup 00590 (a_this->content.str->stryng->str, 00591 a_this->content.str->stryng->len); 00592 } 00593 00594 if (content) { 00595 g_string_append (str_buf, (const gchar *) content); 00596 g_free (content); 00597 content = NULL; 00598 } 00599 break; 00600 00601 case TERM_URI: 00602 if (a_this->content.str) { 00603 content = (guchar *) g_strndup 00604 (a_this->content.str->stryng->str, 00605 a_this->content.str->stryng->len); 00606 } 00607 00608 if (content) { 00609 g_string_append_printf 00610 (str_buf, "url(%s)", content); 00611 g_free (content); 00612 content = NULL; 00613 } 00614 break; 00615 00616 case TERM_RGB: 00617 if (a_this->content.rgb) { 00618 guchar *tmp_str = NULL; 00619 00620 g_string_append_printf (str_buf, "rgb("); 00621 tmp_str = cr_rgb_to_string (a_this->content.rgb); 00622 00623 if (tmp_str) { 00624 g_string_append (str_buf, (const gchar *) tmp_str); 00625 g_free (tmp_str); 00626 tmp_str = NULL; 00627 } 00628 g_string_append_printf (str_buf, ")"); 00629 } 00630 00631 break; 00632 00633 case TERM_UNICODERANGE: 00634 g_string_append_printf 00635 (str_buf, 00636 "?found unicoderange: dump not supported yet?"); 00637 break; 00638 00639 case TERM_HASH: 00640 if (a_this->content.str) { 00641 content = (guchar *) g_strndup 00642 (a_this->content.str->stryng->str, 00643 a_this->content.str->stryng->len); 00644 } 00645 00646 if (content) { 00647 g_string_append_printf (str_buf, 00648 "#%s", content); 00649 g_free (content); 00650 content = NULL; 00651 } 00652 break; 00653 00654 default: 00655 g_string_append_printf (str_buf, 00656 "%s", 00657 "Unrecognized Term type"); 00658 break; 00659 } 00660 00661 if (str_buf) { 00662 result = (guchar *) str_buf->str; 00663 g_string_free (str_buf, FALSE); 00664 str_buf = NULL; 00665 } 00666 00667 return result; 00668 } 00669 00670 /** 00671 *Dumps the expression (a list of terms connected by operators) 00672 *to a file. 00673 *TODO: finish the dump. The dump of some type of terms have not yet been 00674 *implemented. 00675 *@param a_this the current instance of #CRTerm. 00676 *@param a_fp the destination file pointer. 00677 */ 00678 void 00679 cr_term_dump (CRTerm const * a_this, FILE * a_fp) 00680 { 00681 guchar *content = NULL; 00682 00683 g_return_if_fail (a_this); 00684 00685 content = cr_term_to_string (a_this); 00686 00687 if (content) { 00688 fprintf (a_fp, "%s", content); 00689 g_free (content); 00690 } 00691 } 00692 00693 /** 00694 *Return the number of terms in the expression. 00695 *@param a_this the current instance of #CRTerm. 00696 *@return number of terms in the expression. 00697 */ 00698 int 00699 cr_term_nr_values (CRTerm const *a_this) 00700 { 00701 CRTerm const *cur = NULL ; 00702 int nr = 0; 00703 00704 g_return_val_if_fail (a_this, -1) ; 00705 00706 for (cur = a_this ; cur ; cur = cur->next) 00707 nr ++; 00708 return nr; 00709 } 00710 00711 /** 00712 *Use an index to get a CRTerm from the expression. 00713 *@param a_this the current instance of #CRTerm. 00714 *@param itemnr the index into the expression. 00715 *@return CRTerm at position itemnr, if itemnr > number of terms - 1, 00716 *it will return NULL. 00717 */ 00718 CRTerm * 00719 cr_term_get_from_list (CRTerm *a_this, int itemnr) 00720 { 00721 CRTerm *cur = NULL ; 00722 int nr = 0; 00723 00724 g_return_val_if_fail (a_this, NULL) ; 00725 00726 for (cur = a_this ; cur ; cur = cur->next) 00727 if (nr++ == itemnr) 00728 return cur; 00729 return NULL; 00730 } 00731 00732 /** 00733 *Increments the reference counter of the current instance 00734 *of #CRTerm.* 00735 *@param a_this the current instance of #CRTerm. 00736 */ 00737 void 00738 cr_term_ref (CRTerm * a_this) 00739 { 00740 g_return_if_fail (a_this); 00741 00742 a_this->ref_count++; 00743 } 00744 00745 /** 00746 *Decrements the ref count of the current instance of 00747 *#CRTerm. If the ref count reaches zero, the instance is 00748 *destroyed. 00749 *@param a_this the current instance of #CRTerm. 00750 *@return TRUE if the current instance has been destroyed, FALSE otherwise. 00751 */ 00752 gboolean 00753 cr_term_unref (CRTerm * a_this) 00754 { 00755 g_return_val_if_fail (a_this, FALSE); 00756 00757 if (a_this->ref_count) { 00758 a_this->ref_count--; 00759 } 00760 00761 if (a_this->ref_count == 0) { 00762 cr_term_destroy (a_this); 00763 return TRUE; 00764 } 00765 00766 return FALSE; 00767 } 00768 00769 /** 00770 *The destructor of the the #CRTerm class. 00771 *@param a_this the "this pointer" of the current instance 00772 *of #CRTerm. 00773 */ 00774 void 00775 cr_term_destroy (CRTerm * a_this) 00776 { 00777 g_return_if_fail (a_this); 00778 00779 cr_term_clear (a_this); 00780 00781 if (a_this->next) { 00782 cr_term_destroy (a_this->next); 00783 a_this->next = NULL; 00784 } 00785 00786 if (a_this) { 00787 g_free (a_this); 00788 } 00789 00790 }