/* 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_puts(): Print string to file buffer.
   Parameters:
     buf: The buffer to print to.
     string: The string to print.
   Returns: true on success, false otherwise.
*/
int csb_puts(csb_buf *buf, /*@unique@*/ const char *str) /*@modifies buf->fileptr, buf->string, buf->stringsize, buf->length, buf->ungetc_buffer@*/ {
	const size_t str_size = strlen(str); 

	/* Do some sanity checks to make sure we're getting a valid buffer. */
	assert(buf != NULL && buf->string != NULL);

	/* Dynamically make the buffer bigger until we're sure the string fits. */
	CSB_RESIZE_TO_FIT(buf, str);

	/* "Print" the string to the buffer at its current position. When done,
	   reset the size of the string and seek to the end of the combined 
	   string. */
	strncpy (buf->fileptr, str, str_size);
	buf->fileptr += str_size;
	if (buf->fileptr >= buf->string + buf->stringsize) {
		buf->stringsize = (size_t)((unsigned long)(buf->fileptr) - (unsigned long)(buf->string));
		*buf->fileptr = '\0';
	}

	/* Return TRUE; it was successful. */
	return (TRUE);
}

/* csb_putc(): Print a character to file buffer.
   Parameters:
     buf: The buffer to print to.
     ch: The character to print.
   Returns: true on success, false otherwise.
*/
int csb_putc(csb_buf *buf, char ch) /*@modifies buf->fileptr, buf->string, buf->stringsize, buf->length, buf->ungetc_buffer, buf->ungetc_length@*/ {
	/* Declare variables. */
	char str[2];

	/* Initialize the string to be the character passed in followed by '\0'. */
	str[0] = ch;
	str[1] = '\0';

	/* Send the string to csb_puts() since there's common code in there. */
	return (csb_puts(buf, str));
}

/* csb_write(): write binary data to buffer.
   Parameters:
     buf: Buffer to operate on.
     data: Data to write.
     length: The size of the data to write.
   Returns: true on success, false otherwise.
*/
int csb_write(csb_buf *buf, /*@unique@*/ const void *data, size_t length) /*@modifies buf->fileptr, buf->string, buf->stringsize, buf->length, buf->ungetc_buffer@*/ {
	/* Perform sanity checks to make sure we have a valid buffer. */
	assert(buf != NULL && buf->string != NULL);

	/* Grow the buffer to the needed size. */
	/*while (buf->stringsize + length > buf->length) {
		csb_addchunk(buf);
	}*/
	if (buf->stringsize + length > buf->length) {
		(void)csb_prealloc(buf, buf->stringsize + length);
	}

	/* Copy the data to the position of the file pointer. */
	memcpy(buf->fileptr, data, length);
	buf->fileptr += length;

	/* Adjust the size of the string and move the file pointer
	   to the end of the string. */
	if (buf->stringsize < (size_t)((unsigned long)(buf->fileptr) - (unsigned long)(buf->string))) {
		buf->stringsize = (size_t)((unsigned long)(buf->fileptr) - (unsigned long)(buf->string));
		*buf->fileptr = '\0';
	} 

	/* Return true, it was a success. */
	return(TRUE);
}

/* csb_printf(): write formatted output to the buffer.
   Parameters:
     buf: Buffer to print to.
     fmt: The format of the output (see the man page for printf)
     ...: each parameter specified in fmt.
   Returns: true on success, false otherwise.
*/
int csb_printf(csb_buf *buf, const char *fmt, ...) /*@modifies buf->fileptr, buf->string, buf->stringsize, buf->length, buf->ungetc_buffer@*/ {
	/* Declare variables. */
	va_list ap;
	int retval;
	
	/* Perform sanity checks to make sure we have a valid buffer. */
	assert(buf != NULL && buf->string != NULL);

	/* Pass the parameters to the system prinf. */
	va_start(ap, fmt);
	retval = vsnprintf (buf->fileptr, buf->length - buf->stringsize - 1, fmt, ap);
	if (retval >= 0) {
		if (retval > (int)(buf->length - buf->stringsize - 1)) {
			/* Grow the buffer to the needed size. */
			/*while (buf->stringsize + retval + 1 > buf->length)
				csb_addchunk (buf);*/
			if (buf->stringsize + retval + 1 > buf->length) {
				(void)csb_prealloc(buf, buf->stringsize + retval + 1);
			}

			retval = vsnprintf (buf->fileptr, buf->length - buf->stringsize - 1, fmt, ap);
		}
		buf->fileptr += retval;

		/* Adjust the size of the string and move the file pointer
		   to the end of the string. */
		buf->stringsize = (size_t)((unsigned long)(buf->fileptr) - (unsigned long)(buf->string));
	} 
	va_end(ap);

	/* Return the return value of csb_puts(). */
	return (retval);
}


syntax highlighted by Code2HTML, v. 0.9.1