/*
 * (c) 2006-2015 Thomas Maier-Komor
 * LICENSE: GPLv2, see file COPYING for details
 */

#include <assert.h>
#include <errno.h>
#include <fcntl.h>
#include <stdarg.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>

#include "log.h"

verbose_t Verbose = Info;

extern void finalize(void);

static int Log = STDERR_FILENO;
static const char *LogName = 0;


void set_log(const char *fn)
{
	int newlog = open(fn,O_WRONLY|O_CREAT,0644);
	if (newlog == -1) {
		warn("unable to open logfile %s: %s\n",fn,strerror(errno));
		return;
	}
	int err = fcntl(newlog,F_SETFD,FD_CLOEXEC);
	assert(err != -1);
	if (Log != STDERR_FILENO)
		(void) close(Log);
	Log = newlog;
	LogName = fn;
}


void dbug(const char *msg, ...)
{
	char *b = 0;
	char buf[4096];
	va_list val;
	int len,r;

	if (Verbose < Debug)
		return;
	va_start(val,msg);
	len = vsnprintf(buf,sizeof(buf),msg,val);
	if (len >= sizeof(buf)) {
		b = malloc(len+1);
		len = vsnprintf(b,len,msg,val);
	} else 
		b = buf;
	va_end(val);
	r = write(Log,b,len);
	if (b != buf)
		free(b);
	if (r == -1) {
		int n;
		n = snprintf(buf,sizeof(buf),"error writing to %s: %s\n",LogName ? LogName : "<stderr>",strerror(errno));
		assert((n > 0) && (n < sizeof(buf)));
		r = write(STDERR_FILENO,msg,n);
		assert(r != -1);
	}
}


void info(const char *msg, ...)
{
	char *b = 0;
	char buf[4096];
	va_list val;
	int len,r;

	if (Verbose < Info)
		return;
	va_start(val,msg);
	len = vsnprintf(buf,sizeof(buf),msg,val);
	if (len >= sizeof(buf)) {
		b = malloc(len+1);
		len = vsnprintf(b,len,msg,val);
	} else 
		b = buf;
	va_end(val);
	r = write(Log,b,len);
	if (b != buf)
		free(b);
	if (r == -1) {
		int n;
		n = snprintf(buf,sizeof(buf),"error writing to %s: %s\n",LogName ? LogName : "<stderr>",strerror(errno));
		assert((n > 0) && (n < sizeof(buf)));
		r = write(STDERR_FILENO,msg,n);
		assert(r != -1);
	}
}


void warn(const char *msg, ...)
{
	char *b = 0;
	char buf[4096];
	va_list val;
	int len,r;

	if (Verbose < Warning)
		return;
	va_start(val,msg);
	len = vsnprintf(buf,sizeof(buf),msg,val);
	if (len >= sizeof(buf)) {
		b = malloc(len+1);
		len = vsnprintf(b,len,msg,val);
	} else 
		b = buf;
	va_end(val);
	r = write(Log,b,len);
	if (b != buf)
		free(b);
	if (r == -1) {
		int n;
		n = snprintf(buf,sizeof(buf),"error writing to %s: %s\n",LogName ? LogName : "<stderr>",strerror(errno));
		assert((n > 0) && (n < sizeof(buf)));
		r = write(STDERR_FILENO,msg,n);
		assert(r != -1);
	}
}


void error(const char *msg, ...)
{
	if (Verbose >= Error) {
		char *b = 0;
		char buf[4096];
		va_list val;
		int len,r;

		va_start(val,msg);
		len = vsnprintf(buf,sizeof(buf),msg,val);
		if (len >= sizeof(buf)) {
			b = malloc(len+1);
			len = vsnprintf(b,len,msg,val);
		} else 
			b = buf;
		va_end(val);
		r = write(Log,b,len);
		if (b != buf)
			free(b);
		if (r == -1) {
			int n;
			n = snprintf(buf,sizeof(buf),"error writing to %s: %s\n",LogName ? LogName : "<stderr>",strerror(errno));
			assert((n > 0) && (n < sizeof(buf)));
			r = write(STDERR_FILENO,msg,n);
			assert(r != -1);
		}
	}
	finalize();
}


