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 (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, 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 const * 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 const * 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 const *a_this) 00701 { 00702 CRTerm const *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 }