/*
 * loglib.h
 *
 * A non-intrusive minimal log framework.
 *
 * History:
 *      14/03/2014 Creation
 *
 * Author: Dario Rodriguez dario@softhome.net
 * This file is licensed under the terms of the GNU LGPL v2+
 */

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <time.h>
#include <stdarg.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>

#include "loglib.h"

#define MAXLOGFILENAME 1024
#define LOGWRITEBUFSIZE 4096
#define LOGWRITEHEXDUMPSIZE 4096

#define DEFAULTFD 2

void
log_write(char *type, char *format, ...)
{
        static void (*writefunc)(int fd, char *buf, long bufsize, void *usrptr)=NULL;
        static void *usrptr=NULL;
        static int fd=DEFAULTFD;
        static char logfilename[MAXLOGFILENAME]={""};
        static char writebuf[LOGWRITEBUFSIZE];
        char *ptr;
        time_t t;
        struct tm stm;
        va_list arglist;
        /* if it is a special action, perform it */
        if(type==((char *)log_setlogfile)) {
                if(fd!=DEFAULTFD)
                        close(fd),fd=DEFAULTFD;
                strncpy(logfilename,format,sizeof(logfilename)-1);
                logfilename[sizeof(logfilename)-1]='\0';
                return;
        } else if(type==((char *)log_closelogfile)) {
                if(fd!=DEFAULTFD)
                        close(fd),fd=DEFAULTFD;
                return;
        } else if(type==((char *)log_setwritefunc)) {
                writefunc=(void (*)(int /*fd*/, char * /*buf*/, long /*bufsize*/, void */*usrptr*/)) format;
                va_start(arglist,format);
                usrptr=va_arg(arglist,void *);
                va_end(arglist);
                return;
        }
        /* it is a new log entry */
        /* make sure the file is open */
        if(fd==DEFAULTFD && logfilename[0]!='\0') {
                if((fd=open(logfilename,O_WRONLY|O_CREAT|O_APPEND,0640))==-1) {
                        fd=DEFAULTFD;
                        return;
                }
        }
        /* prepare the string */
        t=time(NULL);
        localtime_r(&t,&stm);
        ptr=writebuf;
        strftime(ptr,writebuf+LOGWRITEBUFSIZE-ptr-1,"%b %e %H:%M:%S ",&stm);
        writebuf[LOGWRITEBUFSIZE-1]='\0';
        ptr+=strlen(ptr);
        snprintf(ptr,writebuf+LOGWRITEBUFSIZE-ptr-1,"%s: ",type);
        writebuf[LOGWRITEBUFSIZE-1]='\0';
        ptr+=strlen(ptr);
        va_start(arglist,format);
        vsnprintf(ptr,writebuf+LOGWRITEBUFSIZE-ptr-1,format,arglist);
        va_end(arglist);
        writebuf[LOGWRITEBUFSIZE-1]='\0';
        ptr+=strlen(ptr);
        /* if the string is not terminated with a '\n', add the '\n' */
        if(ptr>writebuf && ptr[-1]!='\n') {
                if(ptr<(writebuf+LOGWRITEBUFSIZE-1)) {
                        *(ptr++)='\n';
                        *ptr='\0';
                } else
                        ptr[-1]='\n';
        }
        /* commit the data */
        if(writefunc!=NULL)
                writefunc(fd,writebuf,ptr-writebuf,usrptr);
        else
                write(fd,writebuf,ptr-writebuf);
}

char *
log_hexdumpstr(char *data, long datasize)
{
        static char hexdumpbuf[LOGWRITEHEXDUMPSIZE];
        char c,*ptr;
        long i,l;
        l=(datasize>(LOGWRITEHEXDUMPSIZE/3))?(LOGWRITEHEXDUMPSIZE/3):datasize;
        for(i=0,ptr=hexdumpbuf;i<l;i++) {
                c=data[i]&0xf;
                *(ptr++)=(c<0xa)?c+'0':c+'a'-10;
                c=(data[i]>>4)&0xf;
                *(ptr++)=(c<0xa)?c+'0':c+'a'-10;
                *(ptr++)=' ';
        }
        ptr[(i>0)?i-1:0]='\0';
        return(hexdumpbuf);
}

void
log_setlogfile(char *filename)
{
        log_write((char *)log_setlogfile,(char *)filename);
}

void
log_closelogfile(void)
{
        void *dummy=NULL;
        log_write((char *)log_closelogfile,(char *)dummy);
}


void
log_setwritefunc(void (*newwritefunc)(int fd, char *buf, long bufsize, void *usrptr),void *usrptr)
{
        log_write((char *)log_setwritefunc,(char *)newwritefunc,usrptr);
}