Main Page   Alphabetical List   Data Structures   File List   Data Fields   Globals   Examples  

replacer.c

Go to the documentation of this file.
00001 /*! \file replacer.c
00002     This file contains the implementation of the Search / Replace API.
00003  */
00004 
00005 #include <stdio.h>
00006 #include <stdlib.h>
00007 #include <string.h>
00008 #include "replacer.h"
00009 #include "dstring.h"
00010 #include "chtbl.h"
00011 
00012 /*! \brief Array of strings. This variable is defined in the parser's module (see file 'replacer.lex').
00013            It will contain all the tokens extracted by the parser.
00014  */
00015 
00016 extern char** txt_tokens;
00017 
00018 /*! \brief Number of tokens in the array 'txt_tokens'. This variable is defined in the parser's module
00019            (see file 'replacer.lex').
00020  */
00021 
00022 extern size_t nb_tokens;
00023 
00024 /*! \brief Initial size for a dynamic string.
00025  */
00026 
00027 #define INIT_DYNAMIC_STRING 100
00028 
00029 /* ----------------------------------------------------- */
00030 /* Hash table management                                 */
00031 /* ----------------------------------------------------- */
00032 
00033 /*! \brief Type of the elements strored into the hash table.
00034  */
00035 
00036 struct couple {
00037 
00038                 /*! \brief This point points to a zero terminated string of characters that represent a
00039                            tag. */
00040 
00041                 char *key;
00042 
00043                 /*! \brief This point points to a zero terminated string of characters that represent the
00044                            value of a tag. */
00045 
00046                 char *value;
00047               };
00048 
00049 /*! \brief Number of linked lists for the hash tables used to store the couples (tags, values).
00050  */
00051 
00052 #define HASH_TABLE_ENTRIES   150
00053 
00054 /*! \brief Hash function used by the hash table to hash the tags.
00055     \param key Pointer to a structure <i>couple</i> that contains the couple (tag, value).
00056     \return The function returns an integer.
00057     \warning Make sure that the structure pointed by <i>key</i> has been initialized!
00058  */
00059 
00060 static int hash_function (const void *key)
00061 {
00062   struct couple  *data;
00063   int            total, i;
00064 
00065   data = (struct couple*)key;
00066   total = 1;
00067 
00068   for (i=0; i<strlen(data->key); i++) { total *= (int)((data->key)[i]) ; }
00069 
00070   if (total < 0) { total *= -1; } 
00071 
00072   return total;
00073 }
00074 
00075 /*! \brief Function used to free memory allocated for the elements of the hash table.
00076     \param d Pointer to a structure <i>couple</i> to be freed.
00077  */
00078 
00079 static void free_user_data (void *d)
00080 {
00081   struct couple  *data;
00082 
00083   data = (struct couple*)d;
00084   free (data);
00085   return;
00086 }
00087 
00088 /*! \brief Function used to compare two elements of the hash table (two tags).
00089     \param d1 First element to compare.
00090     \param d2 Second element to compare.
00091     \return The function return 1 if d1 == d2, 0 otherwise.
00092  */
00093 
00094 static int compare_user_data (const void *d1, const void *d2)
00095 {
00096   struct couple *data1, *data2;
00097 
00098   data1 = (struct couple*)d1;
00099   data2 = (struct couple*)d2;
00100 
00101   return !strcmp(data1->key, data2->key);
00102 }
00103 
00104 /* ----------------------------------------------------- */
00105 /* End of hash table management                          */
00106 /* ----------------------------------------------------- */
00107 
00108 /*! \brief Replace tags by their values in a text.
00109     \param text Pointer to a zero terminated string of characters. This string contains the original text. 
00110     \param tags Pointer to an array of tags (that will be searched in 'text').
00111     \param values Pointer to an array of values (a tag is replaced by a value). Please note that:
00112            'tags[i]' will be replaced by 'values[i]'.
00113     \param nb_tags Number of elements in the arrays 'text' and 'tags'.
00114     \return The function returns a pointer to a zero terminated string of characters that represents the
00115             final text. If the function could not allocate memory, then the returned value is NULL.
00116     \warning <ul>
00117                 <li>The returned string of characters has been allocated within the function. Therefore you must
00118                     free it yourself (using free()).
00119                 <li>This function is <b>NOT REENTRANT</b>, DO NOT use it with threads!
00120                 <li>This function works in memory, so if the input text is too large, the function may fail
00121                     because the process is running out of memory. In this case the function returns the value
00122                     NULL. If you get NULL, you should abort the process execution, because the function does
00123                     not clean the memory allocated...
00124              </ul>
00125  */
00126 
00127 char* replace_tags (char *text, char **tags, char **values, int nb_tags)
00128 {
00129   int           res, i;
00130   char          *final, *pt, *aux;
00131   dstring       ds;
00132   size_t        s;
00133   CHTbl         htab;
00134   struct couple *elem, selem;
00135  
00136   /* --------------------------------------------------- */
00137   /* Initialize the hash table                           */
00138   /* --------------------------------------------------- */
00139 
00140   if (
00141        chtbl_init (
00142                     &htab,
00143                     HASH_TABLE_ENTRIES,
00144                     hash_function,
00145                     compare_user_data,
00146                     free_user_data
00147                   ) == -1
00148      )
00149      { return NULL; }
00150 
00151   /* --------------------------------------------------- */
00152   /* Load hash table with couples (tags => values)       */
00153   /* --------------------------------------------------- */
00154 
00155   for (i=0; i<nb_tags; i++)
00156   {
00157     elem = (struct couple*)malloc(sizeof(struct couple));
00158     if (elem == NULL)
00159     {
00160       chtbl_destroy (&htab);
00161       return NULL;
00162     }
00163 
00164     elem->key   = tags[i];
00165     elem->value = values[i];
00166 
00167     res = chtbl_insert (&htab, (void*)elem);
00168 
00169     switch (res)
00170     {
00171       case -1: {
00172                   chtbl_destroy (&htab);
00173                   return NULL;
00174                }; break;
00175 
00176       case 1: /* tag already in hash table */ break;
00177     }
00178   }
00179 
00180   /* --------------------------------------------------- */
00181   /* Parse the original text.                            */
00182   /* This operation will fill the array 'txt_tokens'     */
00183   /* all the tokens.                                     */
00184   /*                                                     */
00185   /* o Tags begins with a character '+'.                 */
00186   /* o Other values begins with a character '-'.         */
00187   /* --------------------------------------------------- */
00188 
00189   res = yylex_memory(text);
00190 
00191   if (res == RELACER_MEM_ERROR)
00192   {
00193     chtbl_destroy (&htab);
00194     return NULL;
00195   }
00196 
00197   /* --------------------------------------------------- */
00198   /* Initialize the dynamic string                       */
00199   /* --------------------------------------------------- */
00200 
00201   if (dstring_init (&ds, INIT_DYNAMIC_STRING) == 1)
00202   {
00203     chtbl_destroy (&htab);
00204     return NULL;
00205   }
00206 
00207   /* --------------------------------------------------- */
00208   /* Look at each token and replace it if necessary.     */
00209   /* --------------------------------------------------- */
00210 
00211   for (i=0; i<nb_tokens; i++)
00212   {
00213     pt = txt_tokens[i]+1;
00214 
00215     if ( *(txt_tokens[i]) == '-')
00216     {
00217        /* ---------------------------------------------- */
00218        /* '-' means that this is NOT a tag, we copy it   */
00219        /* "as is".                                       */
00220        /* ---------------------------------------------- */
00221 
00222        if (dstring_add (&ds, pt, strlen(pt)) == 1)
00223        {
00224          chtbl_destroy (&htab);
00225          return NULL;
00226        }
00227     }
00228     else
00229     {
00230        /* ---------------------------------------------- */
00231        /* This is a tag, lets replace it                 */
00232        /* ---------------------------------------------- */
00233 
00234        selem.key   = pt;
00235        selem.value = NULL;
00236        elem        = &selem;
00237 
00238        res = chtbl_lookup (&htab, (void**)&elem);
00239 
00240        switch (res)
00241        {
00242          case 0: {
00243                    /* element found */
00244 
00245                    if (dstring_add (&ds, elem->value, strlen(elem->value)) == 1)
00246                    {
00247                      chtbl_destroy (&htab);
00248                      return NULL;
00249                    }
00250 
00251                  }; break;
00252 
00253          default: {
00254                    /* element not found */
00255 
00256                    /* ######################################################## */
00257                    /* ###                                                  ### */
00258                    /* ### WARNING !!!!                                     ### */
00259                    /* ###                                                  ### */
00260                    /* ### The following code depends on the tag's defini-  ### */
00261                    /* ### -tion (see file 'replacer.lex'.                  ### */
00262                    /* ###                                                  ### */
00263                    /* ######################################################## */
00264 
00265                    aux = (char*)malloc(strlen(pt)+4);
00266                    if (aux == NULL)
00267                    {
00268                      dstring_free(&ds);
00269                      chtbl_destroy (&htab);
00270                      return NULL;
00271                    }
00272 
00273                    sprintf (aux, "${%s}", pt);
00274 
00275                    if (dstring_add (&ds, aux, strlen(aux)) == 1)
00276                    {
00277                      free (aux);
00278                      chtbl_destroy (&htab);
00279                      return NULL;
00280                    }
00281 
00282                    free (aux);
00283 
00284                  }; break;
00285        }
00286     }
00287   }
00288 
00289   /* --------------------------------------------------- */
00290   /* Free hash table                                     */
00291   /* --------------------------------------------------- */
00292 
00293   chtbl_destroy (&htab);
00294 
00295   /* --------------------------------------------------- */
00296   /* Free all allocated tokens.                          */
00297   /* --------------------------------------------------- */
00298 
00299   free_tokens();
00300 
00301   /* --------------------------------------------------- */
00302   /* Copy the content of the dynamic string              */
00303   /* --------------------------------------------------- */
00304 
00305   final = dstring_get_data (&ds, &s);
00306   if (final == NULL) { return NULL; }
00307 
00308   /* --------------------------------------------------- */
00309   /* Free the dynamic string                             */
00310   /* --------------------------------------------------- */
00311 
00312   dstring_free(&ds);
00313 
00314   return final;
00315 }
00316 
00317 /*! \example test_replacer_final.c
00318     This file shows how to use the function replace_tags().
00319  */

Generated on Thu Apr 3 16:23:43 2003 for Common_C_libraries by doxygen1.3-rc1