/* cStringBuffer: a file-like string buffer.
   Copyright (C) 2004 Mooneer Salem <mooneer@translator.cx>

   This library is free software; you can redistribute it and/or
   modify it under the terms of the GNU Lesser General Public
   License as published by the Free Software Foundation; either
   version 2.1 of the License, or (at your option) any later version.

   This library 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
   Lesser General Public License for more details.

   You should have received a copy of the GNU Lesser General Public
   License along with this library; if not, write to the Free Software
   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
*/

/* Include necessary includes. */
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdarg.h>
#include <assert.h>
#include <unistd.h>

#include "config.h"

#ifdef HAVE_PTHREAD_H
#include <pthread.h>
#endif

#include "csb_private.h"
#include "csb.h"

/* csb_new(): Allocates a new string buffer.
   Parameters: none
   Returns: Memory pointing to the new string buffer, or NULL
     on failure.
*/
/*@only@*/ /*@partial@*/ /*@null@*/ csb_buf *csb_new (void) {
	/* Allocate new memory for the buffer.*/
	csb_buf *retval = (csb_buf*)malloc(sizeof(csb_buf));

	/* Check if malloc() returned NULL. */
	if (retval != NULL) {
		/* It didn't return NULL, so allocate space for the string itself. */
		retval->string = (char*)malloc(BUFFER_INCREMENT);
		if (retval->string == NULL) {
			/* Unfortunately, this second malloc() failed, so abort and
			   return NULL. */
			free(retval);
			return(NULL);
		}

		/* Perform some initialization. Set the length to BUFFER_INCREMENT and the
		   file pointer to the beginning of the string. */
		retval->string[0] = '\0';
		retval->fileptr = retval->string;
		retval->length = BUFFER_INCREMENT;
		retval->stringsize = 0;
#ifdef CSB_OPTIMIZE_AND_EAT_RAM
		retval->multipletwo = 0;
#endif
#ifdef HAVE_PTHREAD_H
		/* Initialize the mutex. */
		retval->buf_mtx = NULL;
		(void)pthread_mutex_init(&retval->buf_mtx, NULL);
#endif

		/* Initialize ungetc buffer. */
		retval->ungetc_buffer = malloc((size_t)1);
		if (retval->ungetc_buffer == NULL) {
			/* Must free everything, we failed. */
#ifdef HAVE_PTHREAD_H
			(void)pthread_mutex_destroy(&retval->buf_mtx);
#endif
			free(retval->string);
			free(retval);
			return(NULL);
		}
		retval->ungetc_buffer[0] = '\0';

		/* Return new string buffer. */
		return (retval);
	} else {
		return (NULL);
	}
}

/* csb_new_withstring(): Allocates a new string buffer and initialize it.
   Parameters:
     string: the string to initialize the buffer with.
   Returns: Memory pointing to the new string buffer, or NULL
     on failure.
*/
/*@only@*/ /*@null@*/ csb_buf *csb_new_withstring (const char *str) {
	/* Call csb_new() for common initialization. */
	csb_buf *retval = csb_new();

	/* If successful, print the string to the buffer. */
	if (retval != NULL) {
		if (csb_puts(retval, str) == FALSE) {
			/* We couldn't print to the buffer; return NULL. */
			csb_destroy(retval);
			return(NULL);
		}
	}

	/* Return new string buffer. */
	return (retval);
}

/* csb_destroy(): Destroy string buffer.
   Parameters:
     buf: The buffer to operate on.
   Returns: nothing.
*/
void csb_destroy(/*@only@*/ /*@in@*/ /*@notnull@*/ csb_buf *buf) {
	/* Perform sanity checks to make sure we have a valid buffer. */
	assert(buf != NULL && buf->string != NULL);

	/* Destroy mutex. */
#ifdef HAVE_PTHREAD_H
	(void)pthread_mutex_destroy(&buf->buf_mtx);
	/*buf->buf_mtx = NULL;*/
#endif

	/* Free both the string and the buffer itself. */
	free(buf->string);
	buf->string = NULL;

	if (buf->ungetc_buffer != NULL) {
		free(buf->ungetc_buffer);
	}
	buf->ungetc_buffer = NULL;
	free(buf);
}


syntax highlighted by Code2HTML, v. 0.9.1