/*
 * $Id: 8b1945abd45384b55003a6f339ff0886a41d00d4 $
 *
 * This file is part of nsmtp.
 *
 * Copyright (c) 2007, 2008 Niklas Olmes <niklas@noxa.de>
 *                          http://www.nevm.de/nsmtp/
 *                          NEVM-RIPE
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License Version 2
 * as published by the Free Software Foundation.
 *
 * This program 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.
 *
 */

#include <stdio.h>
#include <stdlib.h>
#include <stdarg.h>
#include <string.h>
#include <err.h>

#include "log.h"
#include "alloc.h"

static const char rcsid[] = "$Id: 8b1945abd45384b55003a6f339ff0886a41d00d4 $";

static long long nsm_alloc_count = 0;

long long
nsm_alloc_reset(long long count)
{
	long long old;

	old = nsm_alloc_count;
	nsm_alloc_count = count;

	return old;
}

int
nsm_alloc_check(void)
{

	if (nsm_alloc_count != 0)
		xwarn("warn: nsm_alloc_check() => alloc count (%lld) != 0", nsm_alloc_count);
	return nsm_alloc_count == 0;
}

void *
nsm_calloc(size_t n, size_t size)
{
	void *p;

	if ((p = calloc(n, size)) == NULL)
		err(EXIT_FAILURE, "calloc(%lu, %lu) failed", (unsigned long)n, (unsigned long)size);
	++nsm_alloc_count;
	return p;
}

void *
nsm_malloc(size_t size)
{
	void *p;

	if ((p = malloc(size)) == NULL)
		err(EXIT_FAILURE, "malloc(%lu) failed", (unsigned long)size);
	(void)memset(p, 0, size);
	++nsm_alloc_count;
	return p;
}

void *
nsm_realloc(void *p, size_t size)
{
	char *p2;

	if ((p2 = realloc(p, size)) == NULL)
		err(EXIT_FAILURE, "realloc(.., %lu) failed", (unsigned long)size);
	return p2;
}

char *
nsm_strdup(const char *str)
{
	char *p;

	if ((p = strdup(str)) == NULL)
		err(EXIT_FAILURE, "strdup() (strlen == %lu) failed", (unsigned long)strlen(str));
	++nsm_alloc_count;
	return p;
}

void
nsm_asprintf(char **ret, const char *fmt, ...)
{
	va_list ap;
	char buf[65536];

	va_start(ap, fmt);
	if (vsnprintf(buf, sizeof(buf), fmt, ap) < 0)
		err(EXIT_FAILURE, "vsnprintf(buf, %lu, fmt, ...) failed", (unsigned long)sizeof(buf));
	va_end(ap);

	*ret = nsm_strdup(buf);
}

void
nsm_free(void *p)
{

	if (nsm_alloc_count < 1)
		xfatal("fatal: nsm_free() => freeing more than we alloced here, alloc count (%lld)", nsm_alloc_count);
	free(p);
	--nsm_alloc_count;
}
