/*
   File: abase_dstring.c
   Handles dynamic strings needed in the runtime system

   Copyright 2005 Radboud University of Nijmegen
 
   This program is free software; you can redistribute it and/or modify
   it under the terms of the GNU General Public License as published by
   the Free Software Foundation; either version 2 of the License, or
   (at your option) any later version.
 
   This program is distributed in the hope that it will be useful,
   but WITHOUT ANY WARRANTY; without even the implied warranty of
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   GNU Library General Public License for more details.
 
   You should have received a copy of the GNU General Public License
   along with this program; if not, write to the Free Software
   Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.

   CVS ID: "$Id: "
*/

#ifdef HAVE_CONFIG_H
#include <config.h>
#endif /* HAVE_CONFIG_H */

/* standard includes */
#include <stdio.h>
#include <stdlib.h>
#include <stdarg.h>
#include <string.h>

/* local includes */
#include "abase_porting.h"
#include "abase_error.h"
#include "abase_memalloc.h"
#include "abase_dstring.h"

/*
   Initialize and free a dynamic string
*/
dstring abs_init_dstring (int room)
	{ dstring ds = (dstring) abs_malloc (sizeof (struct dstring_rec),
					     "abs_init_dyn_string:ds");
	  char *buf;
	  if (room < 2) room = 2;
	  ds -> room = room;
	  ds -> len = 0;
	  buf = abs_malloc ((size_t) room, "abs_init_dstring:s");
	  *buf = '\0';
	  ds -> s = buf;
	  return (ds);
	};

void abs_free_dstring (dstring ds)
	{ if (ds == NULL) return;
	  abs_free (ds -> s, "abs_free_dstring:ds -> s");
	  abs_free (ds, "abs_free_dstring:ds");
	};

/*
   Character append
*/
void abs_append_dstring_c (dstring ds, char v)
	{ /* Check validity of dynamic string */
	  if (ds == NULL)
	     abs_abort ("abs_append_dstring_c", "called with NULL arg");

	  /* Check if the character would fit */
	  if (ds -> len + 1 == ds -> room)
	     { /* Double the amount of space for every realloc */
	       size_t new_room = ds -> room * 2;
	       char *s = abs_realloc ((void *) ds -> s, new_room, "abs_append_dstring_c:s");
	       ds -> s = s;
	       ds -> room = new_room;
	     };

	  /* Add the character */
	  ds -> s[ds -> len++] = v;
	  ds -> s[ds -> len] = '\0';
	};

/*
   String concatenation
*/
void abs_append_dstring (dstring ds, const char *s)
	{ size_t len, len2;
	  if ((ds == NULL) || (s == NULL))
	       abs_abort ("abs_append_dstring", "called with NULL args");

	  /* Check if the space would fit */
	  len = ds -> len;
	  len2 = strlen (s);
	  if (len + len2 + 1 >= ds -> room)
	     { size_t new_room = 2 * (len + len2 + 1);
	       char *s = abs_realloc ((void *) ds -> s, new_room, "abs_append_dstring:s");
	       ds -> s = s;
	       ds -> room = new_room;
	     };

	  /* Copy the string at the end */
	  strcpy (ds -> s + len, s);
	  ds -> len = len + len2;
	};

/*
   String concatenation with a var args
*/
void abs_sprintfa_dstring (dstring ds, char *format, ...)
	{ char buf[MAX_FMT_LEN];
	  va_list arg_ptr;
	  va_start (arg_ptr, format);
	  vsprintf (buf, format, arg_ptr);
	  va_end (arg_ptr);
	  abs_append_dstring (ds, buf);
	};

/*
   Deallocate the dynamic string and return its contents
*/
char *abs_finish_dstring (dstring ds)
	{ size_t len = strlen (ds -> s);
	  char *s = (char *) abs_malloc (len + 1, "abs_finish_dyn_string:s");
	  strcpy (s, ds -> s);
	  abs_free_dstring (ds);
	  return (s);
	};

