/*
** mg_vec_str.c for  in 
** 
** Made by vianney rancurel
** Login   <vianney@epita.fr>
** 
** Started on  Wed Aug 25 12:10:53 1999 vianney rancurel
** Last update Thu Oct 28 20:15:18 1999 
*/
#include "mg.h"

/* splits a string into a vector of strings.
   Returns 0 if OK. Might return various errors */
t_status	vec_str_split(vec,s,sep)
t_vec		*vec;
char		*s;		/* The string to be splited */
int		sep;		/* Separator e.g. comma */
{
  char		*p;
  char		*tmp;
  t_status	status;
  char		*s2;
  char		*s3;

  if ((s2 = strdup_alloc(s,
			 vec->alloc_proc,
			 vec->comment,
			 "vec_str_split:str",
			 &status)) == NULL)
    return (status);
  p = s3 = s2;
  while (*p)
    {
      if (*p == sep)
	{
	  *p = 0;
	  if (tmp = strdup_alloc(s3,
				 vec->alloc_proc,
				 vec->comment,
				 "vec_str_split:str",
				 &status))
	    vec_add(vec,tmp);
	  else
	    goto end;
	  s3 = p + 1;
	}
      p++;
    } 
  if ((p - s3) != 0)
    {
      if (tmp = strdup_alloc(s3,
			     vec->alloc_proc,
			     vec->comment,
			     "vec_str_split:str",
			     &status))
	{
	  if ((status = vec_add(vec,tmp)) != 0)
	    goto end;
	}
      else
	goto end;
    }
  status = 0;
 end:
  vec->free_proc(s2,
		 vec->comment,
		 "*:str");
  return (status);
}

/* Returns the index of the first elt matching str.
   It performs a strcmp(3).
   Return -1 if not found */
int		vec_str_index(vec,str)
t_vec		*vec;
char		*str;
{
  VEC_FOR(vec,char *s)
    {
      if (!strcmp(s,str))
	return (VEC_IDX);
    }
  VEC_ENDFOR;
  return (-1);
}

/* transforms a vector of strings to a string.
   Returns a new string or NULL if there was a problem (status is then filled)
   */
char		*vec_str_to_str(vec,status)
t_vec		*vec;
t_status	*status;
{
  int		total_len;
  char		*nstr;
  int		size;
  int		offset;

  total_len = 0;
  VEC_FOR(vec,char *str)
    {
      total_len += strlen(str);
    }
  VEC_ENDFOR;
  size = (total_len + 1) * sizeof (char);
  if ((nstr = vec->alloc_proc(size,
			      vec->comment,
			      "vec_str_to_str:str",
			      status)) == NULL)
    return (NULL);
  offset = 0;
  VEC_FOR(vec,char *str)
    {
      strcpy(nstr + offset,str);
      offset += strlen(str); 
    }
  VEC_ENDFOR;
  nstr[offset] = 0;
  return (nstr);
}

/* adds a new string to a vector of string.
   Returns 0 if OK. Might return various errors */
t_status	vec_str_add(vec,str)
t_vec		*vec;
char		*str;
{
  char		*nstr;
  t_status	status;

  if ((nstr = strdup_alloc(str,
			   vec->alloc_proc,
			   vec->comment,
			   "vec_str_add:str",
			   &status)) == NULL)
    return (status);
  if ((status = vec_add(vec,nstr)) != 0)
    vec->free_proc(nstr,
		   vec->comment,
		   "vec_str_add:str");
  return (status);
}

/* adds a new string to a vector of string.
   Note that str is bcopied so there is no check concerning a potential zero
   before len.
   Returns 0 if OK. Might return various errors */
t_status	vec_str_add_with_len(vec,str,len)
t_vec		*vec;
char		*str;
int		len;
{
  char		*nstr;
  t_status	status;
  
#ifdef NOTDEF
  printf("`%s' (%d)\n",str,len);
#endif
  if ((nstr = vec->alloc_proc(len + 1,
			      vec->comment,
			      "vec_str_add:str",
			      &status)) == NULL)
    return (status);
  bcopy(str,nstr,len);
  nstr[len] = 0;
#ifdef NOTDEF
  printf("nstr=`%s'\n",nstr);
#endif
  if ((status = vec_add(vec,nstr)) != 0)
    vec->free_proc(nstr,
		   vec->comment,
		   "vec_str_add:str");
  return (status);
}

/* overrides a slot with a new string.
   Note there is no check concerning idx.
   If keep_if_equal is true and old string and new string are identical
   it returns immediately avoiding the reallocation.
   Returns 0 if OK. Might return various errors */
t_status	vec_str_override(vec,idx,str,keep_if_equal)
t_vec		*vec;
int		idx;
char		*str;
t_boolean	keep_if_equal;
{
  char		*oldstr;
  char		*nstr;
  t_status	status;
  
  oldstr = VEC_AT(vec,idx);
  if (keep_if_equal)
    if (!strcmp(oldstr,str))
      return (0);
  if ((nstr = strdup_alloc(str,
			   vec->alloc_proc,
			   vec->comment,
			   "vec_str_override:str",
			   &status)) == NULL)
    return (status);
  vec->free_proc(oldstr,
		 vec->comment,
		 "*:str");
  VEC_OVERRIDE(vec,idx,nstr);
  return (status);
}

/* frees all strings contained by the vector but not the structure.
   The vector is then empty and reusable */
VOID_FUNC	vec_str_destroy(vec)
t_vec		*vec;
{
  VEC_FOR(vec,char *str)
    {
      vec->free_proc(str,
		     vec->comment,
		     "*:str");
    }
  VEC_ENDFOR;
  vec_destroy(vec);
}

/* frees all strings contained by the vector and the structure */
VOID_FUNC	vec_str_delete(vec)
t_vec		*vec;
{
  vec_str_destroy(vec);
  vec_delete(vec);
}

/* is a t_vec_cmp_proc.
   It is used internally by vec_str_sort(3) */
int		vec_str_sort_cmp(p1,p2)
VOID_PTR	*p1;
VOID_PTR	*p2;
{
  char		*str1;
  char		*str2;

  str1 = (char *)(*p1);
  str2 = (char *)(*p2);
  return (strcmp(str1,str2));
}

/* sorts the vector accoring the ASCII order.
   It uses strcmp(3). */
VOID_FUNC	vec_str_sort(vec)
t_vec		*vec;
{
  vec_sort(vec,(t_vec_cmp_proc)vec_str_sort_cmp);
}

#ifdef DEBUG
/* shows a vector of strings.
   This is a debug function. */
VOID_FUNC	vec_str_show(vec)
t_vec		*vec;
{
  VEC_FOR(vec,char *str)
    {
      if (str)
	fprintf(stderr,"`%s'",str);
      else
	fprintf(stderr,"(null)");
      fprintf(stderr," ");
    }
  VEC_ENDFOR;
  fprintf(stderr,"\n");
}
#endif
