Libcroco
cr-simple-sel.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 <string.h>
00025 #include <glib.h>
00026 #include "cr-simple-sel.h"
00027 
00028 /**
00029  * cr_simple_sel_new:
00030  *
00031  *The constructor of #CRSimpleSel.
00032  *
00033  *Returns the new instance of #CRSimpleSel.
00034  */
00035 CRSimpleSel *
00036 cr_simple_sel_new (void)
00037 {
00038         CRSimpleSel *result = NULL;
00039 
00040         result = g_try_malloc (sizeof (CRSimpleSel));
00041         if (!result) {
00042                 cr_utils_trace_info ("Out of memory");
00043                 return NULL;
00044         }
00045         memset (result, 0, sizeof (CRSimpleSel));
00046 
00047         return result;
00048 }
00049 
00050 /**
00051  * cr_simple_sel_append_simple_sel:
00052  *
00053  *Appends a simpe selector to the current list of simple selector.
00054  *
00055  *@a_this: the this pointer of the current instance of #CRSimpleSel.
00056  *@a_sel: the simple selector to append.
00057  *
00058  *Returns: the new list upon successfull completion, an error code otherwise.
00059  */
00060 CRSimpleSel *
00061 cr_simple_sel_append_simple_sel (CRSimpleSel * a_this, CRSimpleSel * a_sel)
00062 {
00063         CRSimpleSel *cur = NULL;
00064 
00065         g_return_val_if_fail (a_sel, NULL);
00066 
00067         if (a_this == NULL)
00068                 return a_sel;
00069 
00070         for (cur = a_this; cur->next; cur = cur->next) ;
00071 
00072         cur->next = a_sel;
00073         a_sel->prev = cur;
00074 
00075         return a_this;
00076 }
00077 
00078 /**
00079  * cr_simple_sel_prepend_simple_sel:
00080  *
00081  *@a_this: the this pointer of the current instance of #CRSimpleSel.
00082  *@a_sel: the simple selector to prepend.
00083  *
00084  *Prepends a simple selector to the current list of simple selectors.
00085  *
00086  *Returns the new list upon successfull completion, an error code otherwise.
00087  */
00088 CRSimpleSel *
00089 cr_simple_sel_prepend_simple_sel (CRSimpleSel * a_this, CRSimpleSel * a_sel)
00090 {
00091         g_return_val_if_fail (a_sel, NULL);
00092 
00093         if (a_this == NULL)
00094                 return a_sel;
00095 
00096         a_sel->next = a_this;
00097         a_this->prev = a_sel;
00098 
00099         return a_sel;
00100 }
00101 
00102 guchar *
00103 cr_simple_sel_to_string (CRSimpleSel const * a_this)
00104 {
00105         GString *str_buf = NULL;
00106         guchar *result = NULL;
00107 
00108         CRSimpleSel const *cur = NULL;
00109 
00110         g_return_val_if_fail (a_this, NULL);
00111 
00112         str_buf = g_string_new (NULL);
00113         for (cur = a_this; cur; cur = cur->next) {
00114                 if (cur->name) {
00115                         guchar *str = g_strndup (cur->name->stryng->str,
00116                                                  cur->name->stryng->len);
00117 
00118                         if (str) {
00119                                 switch (cur->combinator) {
00120                                 case COMB_WS:
00121                                         g_string_append (str_buf, " ");
00122                                         break;
00123 
00124                                 case COMB_PLUS:
00125                                         g_string_append (str_buf, "+");
00126                                         break;
00127 
00128                                 case COMB_GT:
00129                                         g_string_append (str_buf, ">");
00130                                         break;
00131 
00132                                 default:
00133                                         break;
00134                                 }
00135 
00136                                 g_string_append (str_buf, str);
00137                                 g_free (str);
00138                                 str = NULL;
00139                         }
00140                 }
00141 
00142                 if (cur->add_sel) {
00143                         guchar *tmp_str = NULL;
00144 
00145                         tmp_str = cr_additional_sel_to_string (cur->add_sel);
00146                         if (tmp_str) {
00147                                 g_string_append (str_buf, tmp_str);
00148                                 g_free (tmp_str);
00149                                 tmp_str = NULL;
00150                         }
00151                 }
00152         }
00153 
00154         if (str_buf) {
00155                 result = str_buf->str;
00156                 g_string_free (str_buf, FALSE);
00157                 str_buf = NULL;
00158         }
00159 
00160         return result;
00161 }
00162 
00163 
00164 guchar *
00165 cr_simple_sel_one_to_string (CRSimpleSel const * a_this)
00166 {
00167         GString *str_buf = NULL;
00168         guchar *result = NULL;
00169 
00170         g_return_val_if_fail (a_this, NULL);
00171 
00172         str_buf = g_string_new (NULL);
00173         if (a_this->name) {
00174                 guchar *str = g_strndup (a_this->name->stryng->str,
00175                                          a_this->name->stryng->len);
00176 
00177                 if (str) {
00178                         g_string_append_printf (str_buf, "%s", str);
00179                         g_free (str);
00180                         str = NULL;
00181                 }
00182         }
00183 
00184         if (a_this->add_sel) {
00185                 guchar *tmp_str = NULL;
00186 
00187                 tmp_str = cr_additional_sel_to_string (a_this->add_sel);
00188                 if (tmp_str) {
00189                         g_string_append_printf
00190                                 (str_buf, "%s", tmp_str);
00191                         g_free (tmp_str);
00192                         tmp_str = NULL;
00193                 }
00194         }
00195 
00196         if (str_buf) {
00197                 result = str_buf->str;
00198                 g_string_free (str_buf, FALSE);
00199                 str_buf = NULL;
00200         }
00201 
00202         return result;
00203 }
00204 
00205 /**
00206  * cr_simple_sel_dump:
00207  *@a_this: the current instance of #CRSimpleSel.
00208  *@a_fp: the destination file pointer.
00209  *
00210  *Dumps the selector to a file.
00211  *TODO: add the support of unicode in the dump.
00212  *
00213  *Returns CR_OK upon successfull completion, an error code
00214  *otherwise.
00215  */
00216 enum CRStatus
00217 cr_simple_sel_dump (CRSimpleSel const * a_this, FILE * a_fp)
00218 {
00219         guchar *tmp_str = NULL;
00220 
00221         g_return_val_if_fail (a_fp, CR_BAD_PARAM_ERROR);
00222 
00223         if (a_this) {
00224                 tmp_str = cr_simple_sel_to_string (a_this);
00225                 if (tmp_str) {
00226                         fprintf (a_fp, "%s", tmp_str);
00227                         g_free (tmp_str);
00228                         tmp_str = NULL;
00229                 }
00230         }
00231 
00232         return CR_OK;
00233 }
00234 
00235 /**
00236  * cr_simple_sel_compute_specificity:
00237  *
00238  *@a_this: the current instance of #CRSimpleSel
00239  *
00240  *Computes the selector (combinator separated list of simple selectors)
00241  *as defined in the css2 spec in chapter 6.4.3
00242  *
00243  *Returns CR_OK upon successfull completion, an error code otherwise.
00244  */
00245 enum CRStatus
00246 cr_simple_sel_compute_specificity (CRSimpleSel * a_this)
00247 {
00248         CRAdditionalSel const *cur_add_sel = NULL;
00249         CRSimpleSel const *cur_sel = NULL;
00250         gulong a = 0,
00251                 b = 0,
00252                 c = 0;
00253 
00254         g_return_val_if_fail (a_this, CR_BAD_PARAM_ERROR);
00255 
00256         for (cur_sel = a_this; cur_sel; cur_sel = cur_sel->next) {
00257                 if (cur_sel->type_mask | TYPE_SELECTOR) {
00258                         c++;    /*hmmh, is this a new language ? */
00259                 } else if (!cur_sel->name 
00260                            || !cur_sel->name->stryng
00261                            || !cur_sel->name->stryng->str) {
00262                         if (cur_sel->add_sel->type ==
00263                             PSEUDO_CLASS_ADD_SELECTOR) {
00264                                 /*
00265                                  *this is a pseudo element, and
00266                                  *the spec says, "ignore pseudo elements".
00267                                  */
00268                                 continue;
00269                         }
00270                 }
00271 
00272                 for (cur_add_sel = cur_sel->add_sel;
00273                      cur_add_sel; cur_add_sel = cur_add_sel->next) {
00274                         switch (cur_add_sel->type) {
00275                         case ID_ADD_SELECTOR:
00276                                 a++;
00277                                 break;
00278 
00279                         case NO_ADD_SELECTOR:
00280                                 continue;
00281 
00282                         default:
00283                                 b++;
00284                                 break;
00285                         }
00286                 }
00287         }
00288 
00289         /*we suppose a, b and c have 1 to 3 digits */
00290         a_this->specificity = a * 1000000 + b * 1000 + c;
00291 
00292         return CR_OK;
00293 }
00294 
00295 /**
00296  * cr_simple_sel_destroy:
00297  *
00298  *@a_this: the this pointer of the current instance of #CRSimpleSel.
00299  *
00300  *The destructor of the current instance of
00301  *#CRSimpleSel.
00302  */
00303 void
00304 cr_simple_sel_destroy (CRSimpleSel * a_this)
00305 {
00306         g_return_if_fail (a_this);
00307 
00308         if (a_this->name) {
00309                 cr_string_destroy (a_this->name);
00310                 a_this->name = NULL;
00311         }
00312 
00313         if (a_this->add_sel) {
00314                 cr_additional_sel_destroy (a_this->add_sel);
00315                 a_this->add_sel = NULL;
00316         }
00317 
00318         if (a_this->next) {
00319                 cr_simple_sel_destroy (a_this->next);
00320         }
00321 
00322         if (a_this) {
00323                 g_free (a_this);
00324         }
00325 }