/*
**  Logging routines.
**  Copyright (c) 1991 Bolt Beranek and Newman, Inc.
**  All rights reserved.
**
**  Redistribution and use in source and binary forms are permitted
**  provided that: (1) source distributions retain this entire copyright
**  notice and comment, and (2) distributions including binaries display
**  the following acknowledgement:  ``This product includes software
**  developed by Bolt Beranek and Newman, Inc. and CREN/CSNET'' in the
**  documentation or other materials provided with the distribution and in
**  all advertising materials mentioning features or use of this software.
**  Neither the name of Bolt Beranek and Newman nor CREN/CSNET may be used
**  to endorse or promote products derived from this software without
**  specific prior written permission.
**
**  THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
**  WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
**  MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
*/
/*
 * Copyright (c) 1992 Purdue University
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms are permitted
 * provided that the above copyright notice and this paragraph are
 * duplicated in all such forms and that any documentation,
 * advertising materials, and other materials related to such
 * distribution and use acknowledge that the software was developed
 * by Purdue University.  The name of the University may not be used
 * to endorse or promote products derived * from this software without
 * specific prior written permission.
 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
 * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
 * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
 *
 * Note: this copyright applies to portions of this software developed
 * at Purdue beyond the software covered by the original copyright.
 */
#include <stdio.h>
#include <varargs.h>
#include <time.h>
#include <sys/types.h>
#include "dp.h"


/*
**  Current logging level.
*/
int	log_level = DLOG_GENERAL;


/*
**  Internal logging routine.
*/
void
d_vlog(level, where, format, ap)
    int			level;
    char		*where;
    char		*format;
    va_list		ap;
{
    extern time_t	time();
    extern struct tm	*localtime();
    extern char		*strerror();
    extern int		errno;
    static char		CONSOLE[] = "/dev/console";
    static char		*LOG;
    FILE		*F;
    struct tm		*tp;
    time_t		t;
    char		form[30];
    char		*fp;
    char		c;
    int			oerrno;
    int			mvalue;
    int			islong;
    int			done;

    if (level > log_level)
	return;

    if (!LOG)
	LOG = expand_dir_file("$DPLOG_DIR", LOG_FILE);

    /* Save errno for %m. */
    mvalue = errno;

    /* Open the log file */
    if ((F = fopen(LOG, "a")) == NULL) {
	oerrno = errno;
	if ((F = fopen("/dev/console", "a")) == NULL) {
	    (void)fprintf(stderr, "%s:  Can't open logfile \"%s\",\n\t%s\n",
		    progname, LOG, strerror(oerrno));
	    return;
	}
	(void)fprintf(stderr,
		"%s:  Can't open logfile \"%s\",\n\t%s, using \"%s\"\n",
		progname, LOG, strerror(oerrno), CONSOLE);
    }

    /* Get the timestamp, write the message header. */
    (void)time(&t);
    tp = localtime(&t);
    (void)fprintf(F, "%02d/%02d %02d:%02d:%02d\t%d\t%s: ",
	tp->tm_mon + 1, tp->tm_mday, tp->tm_hour, tp->tm_min, tp->tm_sec,
	getpid(), where);

    while (c = *format++) {
	if (c != '%') {
	    (void)fputc(c, F);
	    continue;
	}
	if (*format == '%') {
	    (void)fputc('%', F);
	    format++;
	    continue;
	}

	/* A standard printf format. copy it into form. */
	for (islong = 0, fp = form, *fp++ = c, done = 0; done == 0; )
	    switch (c = *format++) {
	    default:
		*fp++ = c;
		break;
	    case 'o': case 'c': case 'd': case 's': case 'u': case 'x':
	    case 'e': case 'E': case 'f': case 'g': case 'G':
	    case 'm':
		done++;
		/* FALLTHROUGH */
	    case ' ': case '+': case '-': case '.': case '#':
	    case '0': case '1': case '2': case '3': case '4':
	    case '5': case '6': case '7': case '8': case '9':
		*fp++ = c;
		break;
	    case 'l':
		islong++;
		*fp++ = c;
		break;
	    }
	*fp = '\0';

	/* We have the format string, get the argument and print it. */
	switch (fp[-1]) {
	case 'x': case 'o': case 'c': case 'd': case 'u':
	    if (islong)
		(void)fprintf(F, form, va_arg(ap, long));
	    else
		(void)fprintf(F, form, va_arg(ap, int));
	    break;
	case 'e': case 'E': case 'f': case 'g': case 'G':
	    (void)fprintf(F, form, va_arg(ap, double));
	    break;
	case 's':
	    (void)fprintf(F, form, va_arg(ap, char*));
	    break;
	case 'm':
	    fp[-1] = 's';
	    (void)fprintf(F, form, strerror(mvalue));
	    break;
	}
    }
    (void)fputc('\n', F);
    (void)fclose(F);
}



/*
**  Write debug log entries.  Calling sequence:
**	d_log(level, where, format, args...)
*/
/* VARARGS0 */
void
d_log(va_alist)
    va_dcl
{
    int		level;
    char	*where;
    char	*format;
    va_list	ap;

    va_start(ap);
    level = va_arg(ap, int);
    where = va_arg(ap, char*);
    format = va_arg(ap, char*);
    d_vlog(level, where, format, ap);
    va_end(ap);
}
