#include "wantassert.h"
#include "leafnode.h"
#include "ln_log.h"

#include <stdarg.h>
#include <assert.h>
#include <syslog.h>
#include <stdio.h>
#include <errno.h>
#include <string.h>
#include <stdlib.h>		/* for getenv */

#ifdef WITH_DMALLOC
#include <dmalloc.h>
#endif

#include <signal.h>		/* for raise */
/* add LOG_NEWS where it doesn't exist */
#if !defined(LOG_NEWS)
#define LOG_NEWS LOG_DAEMON
#endif
/* if LOG_CONS isn't supported, do without */
#if !defined(LOG_CONS)
#define LOG_CONS 0
#endif

static int maylog_console = 1; /* if 0, ln_log* stuff will not log to consoles */

void ln_log_use_console(int en) {
    maylog_console = en;
}

static void vln_log_core(int slg, FILE /*@null@*/ * console,
			 int severity,
			 int context, const char *format, va_list ap);

/* log to syslog if slg != 0
 * log to stream console if console != 0
 * ctx to have verbosity like context
 * other arguments like syslog */
static void
vln_log_core(int slg, FILE * console, int severity,
	     int context, const char *format, va_list ap)
{
    char buf[2048], fmt[2048], *y;
    const char *x;
    int errno_save = errno;

    assert(severity >= LNLOG_SMIN);
    assert(context >= 0);
    assert(verbose >= 0);
    /* support %m */
    for (x = format, y = fmt; *x && y < fmt + sizeof(fmt) - 2; x++) {
	if (*x == '%') {
	    x++;
	    if (*x == '%') {
		*y++ = *x;
		*y++ = *x;
	    } else if (*x == 'm') {
		const char *z = strerror(errno_save);

		while (*z && y < fmt + sizeof(fmt)) {
		    if (*z == '%')
			*(y++) = *z;
		    *(y++) = *(z++);
		}
	    } else {
		*y++ = '%';
		*y++ = *x;
	    }
	} else {
	    *y++ = *x;
	}
    }
    *y = '\0';
    vsnprintf(buf, sizeof(buf), fmt, ap);
#ifndef TESTMODE
    if (slg != 0 && (severity < LNLOG_SDEBUG || debugmode)) {
	syslog(severity, "%s", buf);
    }
#endif /* not TESTMODE */

    if (severity <= LNLOG_SERR) {
	/* check if environment demands kill on first error */
	char *k = getenv("LN_LOG_ABORT_ON_ERROR");
	if (k)
	    abort();
    }

    if (console && maylog_console) {
	/* always log LNLOG_SERR and more severe,
	   regardless of verbosity */
	if (context <= verbose+1 || severity <= LNLOG_SERR) {
	    (void)fputs(buf, console);
	    (void)fputc('\n', console);
	}
    }
}

void
ln_log(int sev, int ctx, const char *format, ...)
{
    va_list ap;

    va_start(ap, format);
    vln_log_core(1, stderr, sev, ctx, format, ap);
    va_end(ap);
}

void
ln_log_so(int sev, int ctx, const char *format, ...)
{
    va_list ap;

    va_start(ap, format);
    vln_log_core(1, stdout, sev, ctx, format, ap);
    va_end(ap);
}

void
ln_log_prt(int sev, int ctx, const char *format, ...)
{
    va_list ap;

    va_start(ap, format);
    vln_log_core(0, stderr, sev, ctx, format, ap);
    va_end(ap);
}

void
ln_log_sys(int sev, int ctx, const char *format, ...)
{
    va_list ap;

    va_start(ap, format);
    vln_log_core(1, NULL, sev, ctx, format, ap);
    va_end(ap);
}


syntax highlighted by Code2HTML, v. 0.9.1