/*
 * Copyright (c) 2005, 2006 Sendmail, Inc. and its suppliers.
 *	All rights reserved.
 *
 * By using this file, you agree to the terms and conditions set
 * forth in the LICENSE file which can be found at the top level of
 * the sendmail distribution.
 */

#include "sm/generic.h"
SM_RCSID("@(#)$Id: cstrscpyv0.c,v 1.6 2006/10/05 04:27:37 ca Exp $")

#include "sm/assert.h"
#include "sm/magic.h"
#include "sm/memops.h"
#include "sm/varargs.h"
#include "sm/limits.h"
#include "sm/cstr.h"

/*
**  SM_CSTR_SCPYVN0 -- Create a cstring and copy n bytes from src into it;
**	repeat that process until a NULL is encountered.
**	This is used to create a '\0' terminated string without counting
**	the trailing '\0'.
**
**	Parameters:
**		src -- Byte array to copy from
**		n -- Number of bytes to copy from src
**		... repeated until src == NULL
**
**	Returns:
**		New cstr object
**		NULL on error (ENOMEM)
*/

sm_cstr_P
sm_cstr_scpyvn0(const uchar *src, uint n, ...)
{
	sm_cstr_P cstr;
	const uchar *s0;
	uint total_len, n0, offset;
	va_list ap;
#if MTA_USE_PTHREADS
	int r;
#endif

	SM_REQUIRE(src != NULL);
	if (n >= CSTR_MAX_SIZE)
		return NULL;
	total_len = 0;
	va_start(ap, n);
	s0 = src;
	n0 = n;
	while (s0 != NULL)
	{
		total_len += n0;
		if (n0 >= CSTR_MAX_SIZE)
			return NULL;
		if (total_len >= CSTR_MAX_SIZE)
			return NULL;
		s0 = va_arg(ap, uchar *);
		if (s0 != NULL)
			n0 = va_arg(ap, uint);
	}
	va_end(ap);

	cstr = sm_malloc(sizeof(*cstr));
	if (cstr == NULL)
		return NULL;
	cstr->sm_cstr_base = sm_malloc(total_len + 1);
	if (cstr->sm_cstr_base == NULL)
	{
		sm_free_size(cstr, sizeof(*cstr));
		return NULL;
	}
#if MTA_USE_PTHREADS
	r = pthread_mutex_init(&cstr->sm_cstr_mutex, SM_PTHREAD_MUTEXATTR);
	if (r != 0)
	{
		sm_free_size(cstr->sm_cstr_base, n + 1);
		sm_free_size(cstr, sizeof(*cstr));
		return NULL;
	}
#endif /* MTA_USE_PTHREADS */
	cstr->sm_cstr_len = total_len;
	cstr->sm_cstr_refcnt = 1;

	va_start(ap, n);
	s0 = src;
	n0 = n;
	offset = 0;
	while (s0 != NULL)
	{
		SM_ASSERT(offset < total_len);
		SM_ASSERT(offset + n0 <= total_len);
		if (n0 > 0)
		{
			sm_memcpy(cstr->sm_cstr_base + offset, s0, n0);
			offset += n0;
		}
		s0 = va_arg(ap, uchar *);
		if (s0 != NULL)
			n0 = va_arg(ap, uint);
	}
	va_end(ap);
	cstr->sm_cstr_base[total_len] = '\0';

	cstr->sm_magic = SM_CSTR_MAGIC;
	return cstr;
}


syntax highlighted by Code2HTML, v. 0.9.1