/*
 * Copyright (C) 2005 iptelorg GmbH
 *
 * This file is part of ser, a free SIP server.
 *
 * ser 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
 *
 * For a license to use the ser software under conditions
 * other than those described here, or to purchase support for this
 * software, please contact iptel.org by e-mail at the following addresses:
 *    info@iptel.org
 *
 * ser 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 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., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
 */

#ifndef __DSTRING_H
#define __DSTRING_H

#include <cds/sstr.h>

#ifdef __cplusplus
extern "C"
{
#endif

	/**
 * \ingroup cds
 * \defgroup cds_dstring Dynamic strings
 *
 * Dynamic strings were introduced to satisfy needs of presence
 * modules when building presence documents.
 *
 * Dynamic string uses a list of buffers holding data.
 * Buffers are allocated when needed - when there is not enough
 * space in the last buffer. The whole result can be copied into one
 * destination buffer with \ref dstr_get_data, \ref dstr_get_str
 * or \ref dstr_get_str_pkg function.
 *
 * \todo Function with sprintf syntax which will help with
 * readibility of code using dynamic strings.
 * @{
 * */

	/** Buffer used by dynamic string.
 *
 * \todo 'len' and 'used' can be replaced by 'unused' member
 * but it doesn't save too much */
	typedef struct _dstr_buff_t
	{
		int len;				   /**< the buffer length */
		int used;				   /**< already used bytes from buffer */
		struct _dstr_buff_t *next; /**< pointer to next buffer in the list*/
		char data[1];			   /** buffer data */
	} dstr_buff_t;

	/** Dynamic string structure. It is used
 * for muliple appends of any strings.
 *
 * \note There was an attempt to add flags for SHM/PKG memory using, ...
 * but it shows that it slows down, thus they were removed and only the
 * "most quick" version is used (rather two functions than one with param) */
	typedef struct _dstring_t
	{
		/** pointer to the first buffer in the list */
		dstr_buff_t *first;
		/** pointer to the last buffer in the list */
		dstr_buff_t *last;
		/** the length of whole string */
		int len;
		/** predefined buffer size */
		int buff_size;

		/** a operation on this string was unsuccessful ->
	 * all other operations will produce error */
		int error;
	} dstring_t;

	/** Appends zero terminated string to dynamic string.
 * \retval 0 if successful
 * \retval negative on error */
	int dstr_append_zt(dstring_t *dstr, const char *s);

	/** Appends string with given length to dynamic string.
 * \retval 0 if successful
 * \retval negative on error */
	int dstr_append(dstring_t *dstr, const char *s, int len);

	/** Appends string to dynamic string.
 * \retval 0 if successful
 * \retval negative on error */
	int dstr_append_str(dstring_t *dstr, const str_t *s);

	/* int dstr_get_data_length(dstring_t *dstr); */

	/** Returns data stored in dynamic string. It does NOT allocate
 * space for them - it expects that the buffer is already allocated.
 * \retval 0 if successful
 * \retval negative on error */
	int dstr_get_data(dstring_t *dstr, char *dst);

	/** Returns data stored in dynamic string. It allocates space for
 * them with cds_malloc (SER's shared memory).
 * \retval 0 if successful
 * \retval negative on error */
	int dstr_get_str(dstring_t *dstr, str_t *dst);

	/** Returns data stored in dynamic string. It allocates space for
 * them with cds_malloc_pkg (SER's package memory).
 * \retval 0 if successful
 * \retval negative on error */
	int dstr_get_str_pkg(dstring_t *dstr, str_t *dst);
	/** Initializes dynamic string.
 * \param dstr dynamic string to be initialized
 * \param buff_size size of buffer used with this dynamic string
 * \retval 0 if successful
 * \retval negative on error */
	int dstr_init(dstring_t *dstr, int buff_size);

	/** Destroys dynamic string. It frees all allocated buffers. */
	int dstr_destroy(dstring_t *dstr);

/* returns nozero if error !!! */
/* int dstr_error(dstring_t *dstr);
void dstr_clear_error(dstring_t *dstr); */

/** Macro returning length of data stored in dynamic string. */
#define dstr_get_data_length(dstr) (dstr)->len

/** Macro pointing to error in dynamic string. If set
 * there was an error during a previous operation with
 * this dynamic string. */
#define dstr_error(dstr) (dstr)->error

/** Macro for cleaning error flag in dynamic string. */
#define dstr_clear_error(dstr) (dstr)->error = 0

	/** @} */

#ifdef __cplusplus
}
#endif

#endif
