Logo AND Algorithmique Numérique Distribuée

Public GIT Repository
Make sure all the source files have an reference of the copyright and of the licence
[simgrid.git] / src / xbt / xbt_str.c
index dfe4f28..16a45ce 100644 (file)
@@ -1,3 +1,4 @@
+/* $Id$ */
 
 /* xbt_str.c - various helping functions to deal with strings               */
 
 #include "portable.h"
 #include "xbt/matrix.h" /* for the diff */
 
-static void free_string(void *d){
-  free(*(void**)d);
-}
-
 /**  @brief Strip whitespace (or other characters) from the end of a string.
  *
  * Strips the whitespaces from the end of s. 
@@ -191,7 +188,7 @@ xbt_str_strip_spaces(char *s) {
  */
 
 xbt_dynar_t xbt_str_split(const char *s, const char *sep) {
-  xbt_dynar_t res = xbt_dynar_new(sizeof(char*), free_string);
+  xbt_dynar_t res = xbt_dynar_new(sizeof(char*), xbt_free_ref);
   const char *p, *q;
   int done;
   const char* sep_dflt = " \t\n\r\x0B";
@@ -233,6 +230,54 @@ xbt_dynar_t xbt_str_split(const char *s, const char *sep) {
   return res;
 }
 
+/**
+ * \brief This functions splits a string after using another string as separator
+ * For example A!!B!!C splitted after !! will return the dynar {A,B,C}
+ * \return An array of dynars containing the string tokens
+*/
+xbt_dynar_t xbt_str_split_str(const char *s, const char *sep) {
+  xbt_dynar_t res = xbt_dynar_new(sizeof(char*), xbt_free_ref);
+  int done;
+  const char *p, *q;
+  p = q = s;
+  done = 0;
+  if (s[0] == '\0') 
+    return res;
+  if (sep[0] == '\0') {
+    s = xbt_strdup(s);
+    xbt_dynar_push(res, &s);
+    return res;
+  }
+
+  while (!done) {
+    char *to_push;
+    int v = 0;
+    //get the start of the first occurence of the substring
+    q = strstr(p, sep);
+    //if substring was not found add the entire string
+    if (NULL == q) {
+      v = strlen(p);
+      to_push = malloc(v + 1);
+      memcpy(to_push, p, v);
+      to_push[v] = '\0';
+      xbt_dynar_push(res, &to_push);
+      done = 1;
+    }
+    else {
+      //get the appearance
+      to_push = malloc(q - p + 1);
+      memcpy(to_push, p, q - p);
+      //add string terminator
+      to_push[q - p] = '\0';
+          xbt_dynar_push(res, &to_push);
+      p = q +strlen(sep);
+    }
+  }
+  return res;
+}
+
 /** @brief Splits a string into a dynar of strings, taking quotes into account
  * 
  * It basically does the same argument separation than the shell, where white 
@@ -243,7 +288,7 @@ xbt_dynar_t xbt_str_split(const char *s, const char *sep) {
  */
 
 xbt_dynar_t xbt_str_split_quoted(const char *s) {
-  xbt_dynar_t res = xbt_dynar_new(sizeof(char*), free_string);
+  xbt_dynar_t res = xbt_dynar_new(sizeof(char*), xbt_free_ref);
   char *str; /* we have to copy the string before, to handle backslashes */
   char *beg, *end; /* pointers around the parsed chunk */
   int in_simple_quote=0, in_double_quote=0;
@@ -335,6 +380,8 @@ xbt_dynar_t xbt_str_split_quoted(const char *s) {
 }
 
 #ifdef SIMGRID_TEST
+#include "xbt/str.h"
+
 #define mytest(name, input, expected) \
   xbt_test_add0(name); \
   d=xbt_str_split_quoted(input); \
@@ -350,6 +397,7 @@ XBT_TEST_UNIT("xbt_str_split_quoted",test_split_quoted, "test the function xbt_s
   xbt_dynar_t d;
   char *s;
 
+  mytest("Empty", "", "");
   mytest("Basic test", "toto tutu", "totoXXXtutu");
   mytest("Useless backslashes", "\\t\\o\\t\\o \\t\\u\\t\\u", "totoXXXtutu");
   mytest("Protected space", "toto\\ tutu", "toto tutu");
@@ -363,15 +411,40 @@ XBT_TEST_UNIT("xbt_str_split_quoted",test_split_quoted, "test the function xbt_s
   mytest("Backslashed quotes + quotes", "'toto \\'tutu' tata", "toto 'tutuXXXtata");
 
 }
+
+#define mytest_str(name, input, separator, expected) \
+  xbt_test_add0(name); \
+  d=xbt_str_split_str(input, separator); \
+  s=xbt_str_join(d,"XXX"); \
+  xbt_test_assert3(!strcmp(s,expected),\
+                  "Input (%s) leads to (%s) instead of (%s)", \
+                  input,s,expected);\
+  free(s); \
+  xbt_dynar_free(&d);
+
+XBT_TEST_UNIT("xbt_str_split_str",test_split_str, "test the function xbt_str_split_str") {
+  xbt_dynar_t d;
+  char *s;
+
+  mytest_str("Empty string and separator", "", "", "");
+  mytest_str("Empty string", "", "##", "");
+  mytest_str("Empty separator", "toto", "", "toto");
+  mytest_str("String with no separator in it", "toto", "##", "toto");
+  mytest_str("Basic test", "toto##tutu",  "##", "totoXXXtutu");
+}
 #endif /* SIMGRID_TEST */
    
 /** @brief Join a set of strings as a single string */
 
 char *xbt_str_join(xbt_dynar_t dyn, const char*sep) {
   int len=1,dyn_len=xbt_dynar_length(dyn);
-  int cpt;
+  unsigned int cpt;
   char *cursor;
   char *res,*p;
+  
+  if (!dyn_len)
+    return xbt_strdup("");
+
   /* compute the length */
   xbt_dynar_foreach(dyn,cpt,cursor) {
     len+=strlen(cursor);
@@ -381,7 +454,7 @@ char *xbt_str_join(xbt_dynar_t dyn, const char*sep) {
   res = xbt_malloc(len);
   p=res;
   xbt_dynar_foreach(dyn,cpt,cursor) {
-    if (cpt<dyn_len-1)
+    if ((int)cpt<dyn_len-1)
       p+=sprintf(p,"%s%s",cursor,sep);    
     else
       p+=sprintf(p,"%s",cursor);    
@@ -390,6 +463,9 @@ char *xbt_str_join(xbt_dynar_t dyn, const char*sep) {
 }
    
 #if !defined(HAVE_GETLINE) || defined(DOXYGEN)
+/* prototype here, just in case */
+long getline(char **buf, size_t *n, FILE *stream);
+
 /** @brief Get a single line from the stream (reimplementation of the GNU getline)
  * 
  * This is a redefinition of the GNU getline function, used on platforms where it does not exists.
@@ -407,7 +483,8 @@ char *xbt_str_join(xbt_dynar_t dyn, const char*sep) {
  */
 long getline(char **buf, size_t *n, FILE *stream) {
    
-   int i, ch;
+   size_t i;
+   int ch;
    
    if (!*buf) {
      *buf = xbt_malloc(512);
@@ -447,7 +524,8 @@ long getline(char **buf, size_t *n, FILE *stream) {
 static xbt_matrix_t diff_build_LCS(xbt_dynar_t da, xbt_dynar_t db) {
   xbt_matrix_t C = xbt_matrix_new(xbt_dynar_length(da),xbt_dynar_length(db),
                                  sizeof(int),NULL); 
-  int i,j;
+  unsigned long i,j;
+
   /* Compute the LCS */
   /*
     C = array(0..m, 0..n)
@@ -463,11 +541,13 @@ static xbt_matrix_t diff_build_LCS(xbt_dynar_t da, xbt_dynar_t db) {
                 C[i,j] := max(C[i,j-1], C[i-1,j])
     return C[m,n]
          */
-  for (i=0; i<xbt_dynar_length(da); i++) 
-    *((int*) xbt_matrix_get_ptr(C,i,0) ) = 0;
+  if (xbt_dynar_length(db) != 0)
+    for (i=0; i<xbt_dynar_length(da); i++) 
+      *((int*) xbt_matrix_get_ptr(C,i,0) ) = 0;
 
-  for (j=0; j<xbt_dynar_length(db); j++) 
-    *((int*) xbt_matrix_get_ptr(C,0,j) ) = 0;
+  if (xbt_dynar_length(da) != 0)
+    for (j=0; j<xbt_dynar_length(db); j++) 
+      *((int*) xbt_matrix_get_ptr(C,0,j) ) = 0;
 
   for (i=1; i<xbt_dynar_length(da); i++) 
     for (j=1; j<xbt_dynar_length(db); j++) {
@@ -506,7 +586,7 @@ static void diff_build_diff(xbt_dynar_t res,
     topush = bprintf("  %s",xbt_dynar_get_as(da,i,char*));
     xbt_dynar_push(res, &topush);
   } else if (j>=0 && 
-            (i<=0 || xbt_matrix_get_as(C,i,j-1,int) >= xbt_matrix_get_as(C,i-1,j,int))) {
+            (i<=0 ||j==0|| xbt_matrix_get_as(C,i,j-1,int) >= xbt_matrix_get_as(C,i-1,j,int))) {
     diff_build_diff(res,C,da,db,i,j-1);
     topush = bprintf("+ %s",xbt_dynar_get_as(db,j,char*));
     xbt_dynar_push(res,&topush);
@@ -529,7 +609,7 @@ char *xbt_str_diff(char *a, char *b) {
   xbt_dynar_t db = xbt_str_split(b, "\n");
 
   xbt_matrix_t C = diff_build_LCS(da,db);
-  xbt_dynar_t diff = xbt_dynar_new(sizeof(char*),free_string);
+  xbt_dynar_t diff = xbt_dynar_new(sizeof(char*),xbt_free_ref);
   char *res=NULL;
   
   diff_build_diff(diff, C, da,db, xbt_dynar_length(da)-1, xbt_dynar_length(db)-1);