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

/* allocates at least n bytes.
   Should not be called directly.
   Returns 0 or various errors from alloc_procs */
t_status		dyn_str_alloc(ds,n)
t_dyn_str		*ds;
size_t			n;		/* Numbers of bytes wanted	*/
{
  t_status		status;
  size_t		real_size;
  VOID_PTR		ptr;

  if (n < ds->base)
    n = ds->base;
  if ((status = 
       ds->alloc_algorithm_proc(ds->allocated,
				n,
				&real_size)) != 0)
    return (status);
  if (ds->str == NULL)
    {
      if ((ptr = ds->alloc_proc(real_size,
				ds->comment,
				"dyn_str_alloc:str",
				&status)) == NULL)
	return (status);
    }
  else
    {
      if ((ptr = ds->realloc_proc(ds->str,
				  real_size,
				  ds->comment,
				  "dyn_str_alloc:str",
				  &status)) == NULL)
	return (status);
    }
  ds->str = ptr;
  ds->allocated = real_size;
  return (0);
}

/* instantiates a new dyn_str.
   A replacement for str stuff. It might increase speed when working on
   big strings. It allows working on theorically "infinite" strings.
   I'm not sure we should consider "dynamic" string as an "arr" of chars 
   because it may not lead to the same optimizations.
   Returns a new dyn_str structure, if NULL status is filled */
t_dyn_str			*dyn_str_new(base,
					     now,
					     alloc_algorithm_proc,
					     alloc_proc,
					     realloc_proc,
					     free_proc,
					     comment,
					     status)	
size_t			base;			/* Base allocation	*/
t_boolean		now;			/* Alloc elts now	*/
t_alloc_algorithm_proc	alloc_algorithm_proc;	/* Alloc. strategy	*/
t_alloc_proc		alloc_proc;		/* E.g. alloc_malloc(3)	*/
t_realloc_proc		realloc_proc;		/* E.g. realloc_realloc(3)*/
t_free_proc		free_proc;		/* E.g. free_free(3)	*/
char			*comment;		/* Major comment	*/
t_status		*status;		/* Various		*/
{
  t_dyn_str		*ds;

  if ((ds = alloc_proc(sizeof (t_dyn_str),
		       comment,
		       "dyn_str_new:ds",
		       status)) == NULL)
    return (NULL);
  ds->base = base;
  ds->str = NULL;
  ds->len = 0;
  ds->allocated = 0;
  ds->alloc_algorithm_proc = alloc_algorithm_proc;
  ds->alloc_proc = alloc_proc; 
  ds->realloc_proc = realloc_proc;
  ds->free_proc = free_proc;
  ds->comment = comment;
  if (now)
    if (((*status) = dyn_str_alloc(ds,base)) != 0)
      {
	ds->free_proc(ds,
		      comment,
		      "dyn_str_new:ds");
	return (NULL);
      }
  return (ds);
}

t_status		dyn_str_cat_char(ds,c)
t_dyn_str		*ds;
int			c;
{
  t_status		status;

  if (ds->allocated < (ds->len + 2))
    if ((status = dyn_str_alloc(ds,
				ds->len + 2)) != 0)
      return (status);
  ds->str[ds->len] = c;
  ds->str[ds->len + 1] = 0;
  ds->len++;
  return (0);
}

t_status		dyn_str_cat_str(ds,str)
t_dyn_str		*ds;
char			*str;
{
  t_status		status;
  int			len;

  len = strlen(str);
  if (ds->allocated < (ds->len + len + 1))
    if ((status = dyn_str_alloc(ds,
				ds->len + len + 1)) != 0)
      return (status);
  bcopy(str,ds->str + ds->len,len);
  ds->str[ds->len + len + 1] = 0;
  ds->len += len;
  return (0);
}

t_status		dyn_str_cat_fmt_va_printf(ds,buf,len)
t_dyn_str		*ds;
char			*buf;
int			len;
{
  int			i;
  t_status		status;

  i = 0;
  while (i < len)
    {
      if ((status = dyn_str_cat_char(ds,
				     buf[i])) != 0)
	return (status);
      i++;
    }
  return (0);
}

t_status		dyn_str_cat_fmt_va_list(ds,fmt,args)
t_dyn_str		*ds;
char			*fmt;
va_list			args;
{
  return (my_vprintf((t_printf_proc)dyn_str_cat_fmt_va_printf,
		     ds,
		     fmt,
		     args));
}

#ifdef HAVE_STDARG_H
t_status		dyn_str_cat_fmt_va(t_dyn_str *ds,
					   char *fmt,...)
#else
t_status		dyn_str_cat_fmt_va(ds,fmt,va_alist)
t_dyn_str		*ds;
char			*fmt;
va_dcl
#endif
{
  va_list		args;
  t_status		status;
  
#ifdef HAVE_STDARG_H
  va_start(args,fmt);
#else
  va_start(args);
#endif
  status = my_vprintf((t_printf_proc)dyn_str_cat_fmt_va_printf,
		      ds,
		      fmt,
		      args);
  va_end(args);
  return (0);
}
