Code

Extensions. Check element now search in the extension directory (see Bug #668895...
[inkscape.git] / src / libcroco / cr-term.c
1 /* -*- Mode: C; indent-tabs-mode:nil; c-basic-offset: 8-*- */
3 /*
4  * This file is part of The Croco Library
5  *
6  * This program is free software; you can redistribute it and/or
7  * modify it under the terms of version 2.1 of the GNU Lesser General Public
8  * License as published by the Free Software Foundation.
9  *
10  * This program is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13  * GNU General Public License for more details.
14  *
15  * You should have received a copy of the GNU Lesser General Public License
16  * along with this program; if not, write to the Free Software
17  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
18  * USA
19  *
20  * Author: Dodji Seketeli
21  * See COPYRIGHTS file for copyright information.
22  */
24 #include <stdio.h>
25 #include <string.h>
26 #include "cr-term.h"
27 #include "cr-num.h"
28 #include "cr-parser.h"
30 /**
31  *@file
32  *Definition of the #CRTem class.
33  */
35 static void
36 cr_term_clear (CRTerm * a_this)
37 {
38         g_return_if_fail (a_this);
40         switch (a_this->type) {
41         case TERM_NUMBER:
42                 if (a_this->content.num) {
43                         cr_num_destroy (a_this->content.num);
44                         a_this->content.num = NULL;
45                 }
46                 break;
48         case TERM_FUNCTION:
49                 if (a_this->ext_content.func_param) {
50                         cr_term_destroy (a_this->ext_content.func_param);
51                         a_this->ext_content.func_param = NULL;
52                 }
53         case TERM_STRING:
54         case TERM_IDENT:
55         case TERM_URI:
56         case TERM_HASH:
57                 if (a_this->content.str) {
58                         cr_string_destroy (a_this->content.str);
59                         a_this->content.str = NULL;
60                 }
61                 break;
63         case TERM_RGB:
64                 if (a_this->content.rgb) {
65                         cr_rgb_destroy (a_this->content.rgb);
66                         a_this->content.rgb = NULL;
67                 }
68                 break;
70         case TERM_UNICODERANGE:
71         case TERM_NO_TYPE:
72         default:
73                 break;
74         }
76         a_this->type = TERM_NO_TYPE;
77 }
79 /**
80  *Instanciate a #CRTerm.
81  *@return the newly build instance
82  *of #CRTerm.
83  */
84 CRTerm *
85 cr_term_new (void)
86 {
87         CRTerm *result = (CRTerm *)g_try_malloc (sizeof (CRTerm));
88         if (!result) {
89                 cr_utils_trace_info ("Out of memory");
90                 return NULL;
91         }
92         memset (result, 0, sizeof (CRTerm));
93         return result;
94 }
96 /**
97  *Parses an expresion as defined by the css2 spec
98  *and builds the expression as a list of terms.
99  *@param a_buf the buffer to parse.
100  *@return a pointer to the first term of the expression or
101  *NULL if parsing failed.
102  */
103 CRTerm *
104 cr_term_parse_expression_from_buf (const guchar * a_buf,
105                                    enum CREncoding a_encoding)
107         CRTerm *result = NULL;
108         enum CRStatus status = CR_OK;
110         g_return_val_if_fail (a_buf, NULL);
112         CRParser *parser = cr_parser_new_from_buf (
113                                                  (guchar*)a_buf,
114                                                                                   strlen ((char *)a_buf),
115                                           a_encoding, FALSE);
116         g_return_val_if_fail (parser, NULL);
118         status = cr_parser_try_to_skip_spaces_and_comments (parser);
119         if (status != CR_OK) {
120                 goto cleanup;
121         }
122         status = cr_parser_parse_expr (parser, &result);
123         if (status != CR_OK) {
124                 if (result) {
125                         cr_term_destroy (result);
126                         result = NULL;
127                 }
128         }
130       cleanup:
131         if (parser) {
132                 cr_parser_destroy (parser);
133                 parser = NULL;
134         }
136         return result;
139 enum CRStatus
140 cr_term_set_number (CRTerm * a_this, CRNum * a_num)
142         g_return_val_if_fail (a_this, CR_BAD_PARAM_ERROR);
144         cr_term_clear (a_this);
146         a_this->type = TERM_NUMBER;
147         a_this->content.num = a_num;
148         return CR_OK;
151 enum CRStatus
152 cr_term_set_function (CRTerm * a_this, CRString * a_func_name,
153                       CRTerm * a_func_param)
155         g_return_val_if_fail (a_this, CR_BAD_PARAM_ERROR);
157         cr_term_clear (a_this);
159         a_this->type = TERM_FUNCTION;
160         a_this->content.str = a_func_name;
161         a_this->ext_content.func_param = a_func_param;
162         return CR_OK;
165 enum CRStatus
166 cr_term_set_string (CRTerm * a_this, CRString * a_str)
168         g_return_val_if_fail (a_this, CR_BAD_PARAM_ERROR);
170         cr_term_clear (a_this);
172         a_this->type = TERM_STRING;
173         a_this->content.str = a_str;
174         return CR_OK;
177 enum CRStatus
178 cr_term_set_ident (CRTerm * a_this, CRString * a_str)
180         g_return_val_if_fail (a_this, CR_BAD_PARAM_ERROR);
182         cr_term_clear (a_this);
184         a_this->type = TERM_IDENT;
185         a_this->content.str = a_str;
186         return CR_OK;
189 enum CRStatus
190 cr_term_set_uri (CRTerm * a_this, CRString * a_str)
192         g_return_val_if_fail (a_this, CR_BAD_PARAM_ERROR);
194         cr_term_clear (a_this);
196         a_this->type = TERM_URI;
197         a_this->content.str = a_str;
198         return CR_OK;
201 enum CRStatus
202 cr_term_set_rgb (CRTerm * a_this, CRRgb * a_rgb)
204         g_return_val_if_fail (a_this, CR_BAD_PARAM_ERROR);
206         cr_term_clear (a_this);
208         a_this->type = TERM_RGB;
209         a_this->content.rgb = a_rgb;
210         return CR_OK;
213 enum CRStatus
214 cr_term_set_hash (CRTerm * a_this, CRString * a_str)
216         g_return_val_if_fail (a_this, CR_BAD_PARAM_ERROR);
218         cr_term_clear (a_this);
220         a_this->type = TERM_HASH;
221         a_this->content.str = a_str;
222         return CR_OK;
225 /**
226  *Appends a new term to the current list of #CRTerm.
227  *
228  *@param a_this the "this pointer" of the current instance
229  *of #CRTerm .
230  *@param a_new_term the term to append.
231  *@return the list of terms with the a_new_term appended to it.
232  */
233 CRTerm *
234 cr_term_append_term (CRTerm * a_this, CRTerm * a_new_term)
236         CRTerm *cur = NULL;
238         g_return_val_if_fail (a_new_term, NULL);
240         if (a_this == NULL)
241                 return a_new_term;
243         for (cur = a_this; cur->next; cur = cur->next) ;
245         cur->next = a_new_term;
246         a_new_term->prev = cur;
248         return a_this;
251 /**
252  *Prepends a term to the list of terms represented by a_this.
253  *
254  *@param a_this the "this pointer" of the current instance of
255  *#CRTerm .
256  *@param a_new_term the term to prepend.
257  *@return the head of the new list.
258  */
259 CRTerm *
260 cr_term_prepend_term (CRTerm * a_this, CRTerm * a_new_term)
262         g_return_val_if_fail (a_this && a_new_term, NULL);
264         a_new_term->next = a_this;
265         a_this->prev = a_new_term;
267         return a_new_term;
270 /**
271  *Serializes the expression represented by
272  *the chained instances of #CRterm.
273  *@param a_this the current instance of #CRTerm
274  *@return the zero terminated string containing the serialized
275  *form of #CRTerm. MUST BE FREED BY THE CALLER using g_free().
276  */
277 guchar *
278 cr_term_to_string (CRTerm * a_this)
280         GString *str_buf = NULL;
281         CRTerm *cur = NULL;
282         guchar *result = NULL;
283         gchar *content = NULL;
285         g_return_val_if_fail (a_this, NULL);
287         str_buf = g_string_new (NULL);
288         g_return_val_if_fail (str_buf, NULL);
290         for (cur = a_this; cur; cur = cur->next) {
291                 if ((cur->content.str == NULL)
292                     && (cur->content.num == NULL)
293                     && (cur->content.str == NULL)
294                     && (cur->content.rgb == NULL))
295                         continue;
297                 switch (cur->the_operator) {
298                 case DIVIDE:
299                         g_string_append (str_buf, " / ");
300                         break;
302                 case COMMA:
303                         g_string_append (str_buf, ", ");
304                         break;
306                 case NO_OP:
307                         if (cur->prev) {
308                                 g_string_append (str_buf, " ");
309                         }
310                         break;
311                 default:
313                         break;
314                 }
316                 switch (cur->unary_op) {
317                 case PLUS_UOP:
318                         g_string_append (str_buf, "+");
319                         break;
321                 case MINUS_UOP:
322                         g_string_append (str_buf, "-");
323                         break;
325                 default:
326                         break;
327                 }
329                 switch (cur->type) {
330                 case TERM_NUMBER:
331                         if (cur->content.num) {
332                                 content = (gchar *)cr_num_to_string (cur->content.num);
333                         }
335                         if (content) {
336                                 g_string_append (str_buf, content);
337                                 g_free (content);
338                                 content = NULL;
339                         }
341                         break;
343                 case TERM_FUNCTION:
344                         if (cur->content.str) {
345                                 content = g_strndup
346                                         (cur->content.str->stryng->str,
347                                          cur->content.str->stryng->len);
348                         }
350                         if (content) {
351                                 g_string_append_printf (str_buf, "%s(",
352                                                         content);
354                                 if (cur->ext_content.func_param) {
355                                         guchar *tmp_str = NULL;
357                                         tmp_str = cr_term_to_string
358                                                 (cur->
359                                                  ext_content.func_param);
361                                         if (tmp_str) {
362                                                 g_string_append (str_buf, 
363                                                                                     (gchar *)tmp_str);
364                                                 g_free (tmp_str);
365                                                 tmp_str = NULL;
366                                         }
368                                         g_free (content);
369                                         content = NULL;
370                                 }
371                                 g_string_append (str_buf, ")");
372                         }
374                         break;
376                 case TERM_STRING:
377                         if (cur->content.str) {
378                                 content = g_strndup
379                                         (cur->content.str->stryng->str,
380                                          cur->content.str->stryng->len);
381                         }
383                         if (content) {
384                                 g_string_append_printf (str_buf,
385                                                         "\"%s\"", content);
386                                 g_free (content);
387                                 content = NULL;
388                         }
389                         break;
391                 case TERM_IDENT:
392                         if (cur->content.str) {
393                                 content = g_strndup
394                                         (cur->content.str->stryng->str,
395                                          cur->content.str->stryng->len);
396                         }
398                         if (content) {
399                                 g_string_append (str_buf, content);
400                                 g_free (content);
401                                 content = NULL;
402                         }
403                         break;
405                 case TERM_URI:
406                         if (cur->content.str) {
407                                 content = g_strndup
408                                           (cur->content.str->stryng->str,
409                                            cur->content.str->stryng->len);
410                         }
412                         if (content) {
413                                 g_string_append_printf
414                                         (str_buf, "url(%s)", content);
415                                 g_free (content);
416                                 content = NULL;
417                         }
418                         break;
420                 case TERM_RGB:
421                         if (cur->content.rgb) {
422                                 guchar *tmp_str = NULL;
424                                 g_string_append (str_buf, "rgb(");
425                                 tmp_str = cr_rgb_to_string (cur->content.rgb);
427                                 if (tmp_str) {
428                                         g_string_append (str_buf, (gchar *)tmp_str);
429                                         g_free (tmp_str);
430                                         tmp_str = NULL;
431                                 }
432                                 g_string_append (str_buf, ")");
433                         }
435                         break;
437                 case TERM_UNICODERANGE:
438                         g_string_append
439                                 (str_buf,
440                                  "?found unicoderange: dump not supported yet?");
441                         break;
443                 case TERM_HASH:
444                         if (cur->content.str) {
445                                 content = g_strndup
446                                         (cur->content.str->stryng->str,
447                                          cur->content.str->stryng->len);
448                         }
450                         if (content) {
451                                 g_string_append_printf (str_buf,
452                                                         "#%s", content);
453                                 g_free (content);
454                                 content = NULL;
455                         }
456                         break;
458                 default:
459                         g_string_append (str_buf,
460                                          "Unrecognized Term type");
461                         break;
462                 }
463         }
465         if (str_buf) {
466                 result = (guchar *)str_buf->str;
467                 g_string_free (str_buf, FALSE);
468                 str_buf = NULL;
469         }
471         return result;
474 guchar *
475 cr_term_one_to_string (CRTerm * a_this)
477         GString *str_buf = NULL;
478         guchar *result = NULL;
479         gchar *content = NULL;
481         g_return_val_if_fail (a_this, NULL);
483         str_buf = g_string_new (NULL);
484         g_return_val_if_fail (str_buf, NULL);
486         if ((a_this->content.str == NULL)
487             && (a_this->content.num == NULL)
488             && (a_this->content.str == NULL)
489             && (a_this->content.rgb == NULL))
490                 return NULL ;
492         switch (a_this->the_operator) {
493         case DIVIDE:
494                 g_string_append_printf (str_buf, " / ");
495                 break;
497         case COMMA:
498                 g_string_append_printf (str_buf, ", ");
499                 break;
501         case NO_OP:
502                 if (a_this->prev) {
503                         g_string_append_printf (str_buf, " ");
504                 }
505                 break;
506         default:
508                 break;
509         }
511         switch (a_this->unary_op) {
512         case PLUS_UOP:
513                 g_string_append_printf (str_buf, "+");
514                 break;
516         case MINUS_UOP:
517                 g_string_append_printf (str_buf, "-");
518                 break;
520         default:
521                 break;
522         }
524         switch (a_this->type) {
525         case TERM_NUMBER:
526                 if (a_this->content.num) {
527                         content = (gchar *)cr_num_to_string (a_this->content.num);
528                 }
530                 if (content) {
531                         g_string_append (str_buf, content);
532                         g_free (content);
533                         content = NULL;
534                 }
536                 break;
538         case TERM_FUNCTION:
539                 if (a_this->content.str) {
540                         content = g_strndup
541                                 (a_this->content.str->stryng->str,
542                                  a_this->content.str->stryng->len);
543                 }
545                 if (content) {
546                         g_string_append_printf (str_buf, "%s(",
547                                                 content);
549                         if (a_this->ext_content.func_param) {
550                                 guchar *tmp_str = NULL;
552                                 tmp_str = cr_term_to_string
553                                         (a_this->
554                                          ext_content.func_param);
556                                 if (tmp_str) {
557                                         g_string_append_printf
558                                                 (str_buf,
559                                                  "%s", tmp_str);
560                                         g_free (tmp_str);
561                                         tmp_str = NULL;
562                                 }
564                                 g_string_append_printf (str_buf, ")");
565                                 g_free (content);
566                                 content = NULL;
567                         }
568                 }
570                 break;
572         case TERM_STRING:
573                 if (a_this->content.str) {
574                         content = g_strndup
575                                 (a_this->content.str->stryng->str,
576                                  a_this->content.str->stryng->len);
577                 }
579                 if (content) {
580                         g_string_append_printf (str_buf,
581                                                 "\"%s\"", content);
582                         g_free (content);
583                         content = NULL;
584                 }
585                 break;
587         case TERM_IDENT:
588                 if (a_this->content.str) {
589                         content = g_strndup
590                                 (a_this->content.str->stryng->str,
591                                  a_this->content.str->stryng->len);
592                 }
594                 if (content) {
595                         g_string_append (str_buf, content);
596                         g_free (content);
597                         content = NULL;
598                 }
599                 break;
601         case TERM_URI:
602                 if (a_this->content.str) {
603                         content = g_strndup
604                                 (a_this->content.str->stryng->str,
605                                  a_this->content.str->stryng->len);
606                 }
608                 if (content) {
609                         g_string_append_printf
610                                 (str_buf, "url(%s)", content);
611                         g_free (content);
612                         content = NULL;
613                 }
614                 break;
616         case TERM_RGB:
617                 if (a_this->content.rgb) {
619                         g_string_append_printf (str_buf, "rgb(");
620                         gchar *tmp_str = (gchar *)cr_rgb_to_string (a_this->content.rgb);
622                         if (tmp_str) {
623                                 g_string_append (str_buf, tmp_str);
624                                 g_free (tmp_str);
625                                 tmp_str = NULL;
626                         }
627                         g_string_append_printf (str_buf, ")");
628                 }
630                 break;
632         case TERM_UNICODERANGE:
633                 g_string_append_printf
634                         (str_buf,
635                          "?found unicoderange: dump not supported yet?");
636                 break;
638         case TERM_HASH:
639                 if (a_this->content.str) {
640                         content = g_strndup
641                                 (a_this->content.str->stryng->str,
642                                  a_this->content.str->stryng->len);
643                 }
645                 if (content) {
646                         g_string_append_printf (str_buf,
647                                                 "#%s", content);
648                         g_free (content);
649                         content = NULL;
650                 }
651                 break;
653         default:
654                 g_string_append_printf (str_buf,
655                                         "%s",
656                                         "Unrecognized Term type");
657                 break;
658         }
660         if (str_buf) {
661                 result = (guchar *)str_buf->str;
662                 g_string_free (str_buf, FALSE);
663                 str_buf = NULL;
664         }
666         return result;
669 /**
670  *Dumps the expression (a list of terms connected by operators)
671  *to a file.
672  *TODO: finish the dump. The dump of some type of terms have not yet been
673  *implemented.
674  *@param a_this the current instance of #CRTerm.
675  *@param a_fp the destination file pointer.
676  */
677 void
678 cr_term_dump (CRTerm * a_this, FILE * a_fp)
680         guchar *content = NULL;
682         g_return_if_fail (a_this);
684         content = cr_term_to_string (a_this);
686         if (content) {
687                 fprintf (a_fp, "%s", content);
688                 g_free (content);
689         }
692 /**
693  *Return the number of terms in the expression.
694  *@param a_this the current instance of #CRTerm.
695  *@return number of terms in the expression.
696  */
697 int
698 cr_term_nr_values (CRTerm *a_this)
700         CRTerm *cur = NULL ;
701         int nr = 0;
703         g_return_val_if_fail (a_this, -1) ;
705         for (cur = a_this ; cur ; cur = cur->next)
706                 nr ++;
707         return nr;
710 /**
711  *Use an index to get a CRTerm from the expression.
712  *@param a_this the current instance of #CRTerm.
713  *@param itemnr the index into the expression.
714  *@return CRTerm at position itemnr, if itemnr > number of terms - 1,
715  *it will return NULL.
716  */
717 CRTerm *
718 cr_term_get_from_list (CRTerm *a_this, int itemnr)
720         CRTerm *cur = NULL ;
721         int nr = 0;
723         g_return_val_if_fail (a_this, NULL) ;
725         for (cur = a_this ; cur ; cur = cur->next)
726                 if (nr++ == itemnr)
727                         return cur;
728         return NULL;
731 /**
732  *Increments the reference counter of the current instance
733  *of #CRTerm.*
734  *@param a_this the current instance of #CRTerm.
735  */
736 void
737 cr_term_ref (CRTerm * a_this)
739         g_return_if_fail (a_this);
741         a_this->ref_count++;
744 /**
745  *Decrements the ref count of the current instance of
746  *#CRTerm. If the ref count reaches zero, the instance is
747  *destroyed.
748  *@param a_this the current instance of #CRTerm.
749  *@return TRUE if the current instance has been destroyed, FALSE otherwise.
750  */
751 gboolean
752 cr_term_unref (CRTerm * a_this)
754         g_return_val_if_fail (a_this, FALSE);
756         if (a_this->ref_count) {
757                 a_this->ref_count--;
758         }
760         if (a_this->ref_count == 0) {
761                 cr_term_destroy (a_this);
762                 return TRUE;
763         }
765         return FALSE;
768 /**
769  *The destructor of the the #CRTerm class.
770  *@param a_this the "this pointer" of the current instance
771  *of #CRTerm.
772  */
773 void
774 cr_term_destroy (CRTerm * a_this)
776         g_return_if_fail (a_this);
778         cr_term_clear (a_this);
780         if (a_this->next) {
781                 cr_term_destroy (a_this->next);
782                 a_this->next = NULL;
783         }
785         if (a_this) {
786                 g_free (a_this);
787         }