/*
#ident	"@(#)smail/src:RELEASE-3_2_0_120:dys.h,v 1.24 2004/06/25 17:55:49 woods Exp"
 */

/*
 *    Copyright (C) 1987, 1988 Ronald S. Karr and Landon Curt Noll
 *    Copyright (C) 1992  Ronald S. Karr
 * 
 * See the file COPYING, distributed with smail, for restriction
 * and warranty information.
 */

/*
 * dys.h:
 *	macros for dynamic string region functions.
 *
 *	The macros in this file provide a simple method of building strings in
 *	an environment where the final length requirements are not known.
 *	Thus, these macros automatically support growing of strings with
 *	xrealloc() when the current allocation is deemed insufficient.
 *
 *	The 'str' structure has three values: a character pointer, an index,
 *	and an allocation size.  The index is an offset from the character
 *	pointer to the current location being copied into and the allocation
 *	size is the current limit for the index, beyond which a call to
 *	xrealloc() is required.
 */

/*
 * STR - access the string in question directly
 *
 * Note that 'struct str' arrays are not necessarily NUL-terminated unless
 * they've explicitly been made so.
 */
#define STR(sp)		((sp)->p)

/*
 * STR_LEN - since we have the value handy and pre-calculated
 */
#define STR_LEN(sp)	((sp)->i)	/* remember, not i-1, zero offset! */

/*
 * STR_GET - access the character at index 'pos' in a dynamic string
 *
 * This makes it easy to use one of the main benefits of this dynamic string
 * implementation without having to directly know anything about the data
 * structure's internal fields, namely access the character at the end of the
 * string without having to search down the whole array for a terminator.
 */
#define STR_GET(sp, pos)	((sp)->p[(pos)])

/* STR_CHECK - call X_CHECK (from alloc.h) for a string */
#define STR_CHECK(sp)	(void) ((sp) ? X_CHECK((sp)->p) :		\
			 	(write_log(WRITE_LOG_PANIC,		\
					   "STR_CHECK(NULL), line=%d, file=%s", \
					   __LINE__, __FILE__),		\
				 x_dont_panic ?				\
				    FAIL :				\
				    (abort(), 0)))

/* STR_ALLOCSZ - access the allocated size of the string buffer */
#define STR_ALLOCSZ(sp)	((sp)->a)

/* STR_BUMP - the basic quantum of allocation space */
#define STR_BUMP	64

/*
 * STR_INIT - initialize the variables for a dynamic string region
 * this macro should be called with the variables to be passed to
 * other macros in this package before those other macros are used
 */
#define STR_INIT(sp)					\
	(((sp)->a = STR_BUMP),				\
	 ((sp)->i = 0),					\
	 ((sp)->p = xmalloc((sp)->a)))

/*
 * STR_CLEAR - prepare to re-use a dynamic string
 */
#define STR_CLEAR(sp)		((sp)->i = 0)

/*
 * STR_ZAP - give up a dynamic string after passing the pointer elsewhere
 */
#define STR_ZAP(sp)					\
	(((sp)->a = 0),					\
	 ((sp)->i = 0),					\
	 ((sp)->p = NULL))

/*
 * STR_NEXT - write to the next character in a dynamic string region, growing
 * the region if no successor character currently is allocated.  This can be
 * used in the form:
 *
 *	STR_NEXT(p, character expression);
 *
 * to load successive characters into the string.
 */
#define STR_NEXT(sp, c) 				\
	{						\
	    if ((sp)->i >= (sp)->a) {			\
		(sp)->a += STR_BUMP;			\
		(sp)->p = xrealloc((sp)->p, (sp)->a);	\
	    }						\
	    (sp)->p[(sp)->i++] = (c);			\
	}

/*
 * STR_PREV - remove the previous character from a dynamic string
 */
#define STR_PREV(sp)		((sp)->i--)

/*
 * STR_TRIM - trim a dynamic string to length 'len'
 */
#define STR_TRIM(sp, len)	((sp)->i = (len))

/*
 * STR_CAT - concatenate a C string onto the end of a dynamic string region
 * (thus NUL-terminating it), growing the storage region as necessary, but
 * leave the NUL un-accounted for in the dynamic string's current length so
 * that futher str_cat(), str_ncat(), or STR_NEXT(), etc. operations simply
 * overwrite it.
 *
 * STR_NCAT - concatenate an array of characters of a given length onto the end
 * of a dynamic string region, growing the storage region as necessary.
 *
 * These are now implemented as functions in string.c.
 */
#define STR_CAT(sp, cs)		str_cat((sp), (cs))
#define STR_NCAT(sp, cs, len)	str_ncat((sp), (cs), (len))

/*
 * STR_DONE - finish building a dynamic string region.  This is not
 * required, though it will xrealloc a region to minimum length, which
 * may be useful if xmalloc and xrealloc call something besides the
 * stock malloc and realloc functions.
 */
#define STR_DONE(sp)	((sp)->p = xrealloc((char *) ((sp)->p),		\
					    ((sp)->i + 1)),		\
			 (sp)->a = (sp)->i + 1)

/*
 * STR_FREE - free a region, returning its storage to the free pool
 */
#define STR_FREE(sp)	((sp)->p ? xfree((sp)->p) : (void) 1, (sp)->p = NULL, (sp)->i = 0)

/*
 * STR_ALIGN - if region index is not aligned add bytes to align it.
 */
#define STR_ALIGN(sp)	{ while ((sp)->i % BYTES_PER_ALIGN) STR_NEXT((sp), 0); }

/*
 * COPY_STRING - copy a C-style string to a new xmalloc'd region
 */
#define COPY_STRING(sp)	(strcpy(xmalloc((size_t) (strlen((sp)) + 1)), (sp)))

/* 
 * Local Variables:
 * c-file-style: "smail"
 * End:
 */
