#include "tbl-gen.h"
#include "sbuf.h"
#include "tbl-dbg.h"

#if TIME_WITH_SYS_TIME
# include <sys/time.h>
# include <time.h>
#else
# if HAVE_SYS_TIME_H
#  include <sys/time.h>
# else
#  include <time.h>
# endif
#endif

#if STDC_HEADERS || HAVE_STRING_H
#include <string.h>
#else
#include <strings.h>
#endif

#include <fcntl.h>
#include <errno.h>

#if defined(_AIX)
#include <sys/select.h>
#else
#include <sys/types.h>
#endif

int debug = 0;
int strip = 0;
TBL* tbl;
char* progname;
char* tblfilename = "/home/oms2/oms2_u_02/wan/madecode/ICD.HCI53.tt";

int process (char* buffer, int bytes)
    {
    SBuf sb;  /* use simple buffers for reading in (know sizes) */
    GenBuf gb;
    void* val;
    unsigned long bytesDecoded;
    SBufInstallData(&sb, buffer+strip, bytes-strip);
    PutSBufInGenBuf(&sb, &gb);

    DBGMinCode = debug? TDEINFO: TDEWARNING;
    if (!TdeDecode(tbl, &gb, &bytesDecoded, DBGType, DBGSimple, DBGExc))
	fprintf(stdout,"%s: !!! Decoding error occured after %d bytes.\n",
		progname,(int)bytesDecoded);
    fflush(stdout);
    return (int) bytesDecoded+strip;
    }

int readable(int fd)
    {
    int result;
    fd_set fds;
    struct timeval tim;
    FD_ZERO(&fds);
    FD_SET(fd,&fds);
    tim.tv_sec = tim.tv_usec = 0;
    result = select(fd+1,&fds,NULL,NULL,&tim);
    return result;
    }

int decode(int fd)
    {
    char buffer[40960], *pointer;
    int bytes = 0;
    int nr;
    int result;

    if (tblfilename)
	{
	tbl = LoadTblFile(tblfilename);
	if (tbl == NULL)
	    {
	    fprintf(stderr,"%s: !!! Can't load ASN.1 grammar table '%s'.\n",
		    progname,tblfilename);
	    exit(2);
	    }
	tblfilename = NULL;
	}

    while(1)
	{
	if (bytes==0 || readable(fd))
	    {
	    nr = read(fd,buffer+bytes,sizeof(buffer)-bytes);
	    if (nr<0)
		{
		perror("!!! read failed");
		return(2);
		}
	    bytes += nr;
	    if (bytes==0)
		break;
	    }
	result = process(buffer,bytes);
	if (result<=strip)
	    {
	    while (readable(fd))
		{
		nr = read(fd,buffer,sizeof(buffer));
		if (nr<0)
		    {
		    perror("!!! read failed");
		    return(2);
		    }
		if (nr==0)
		    return 0;
		}
	    bytes = 0;
	    continue;
	    }
	bytes -= result;
	if (bytes<0)
	    {
	    fprintf(stdout,"%s: !!! Decoded past end of buffer.\n",progname);
	    fflush(stdout);
	    bytes = 0;
	    }
	if (bytes)
	    memcpy(buffer,buffer+result,bytes);
	}
    return(0);
    }

int decodefn (char* filename)
    {
    if (!strcmp(filename,"-"))
	decode(0);
    else
	{
	int fd = open(filename,O_RDONLY);
	if (fd<0)
	    {
	    perror(filename);
	    return 2;
	    }
	decode(fd);
	close(fd);
	}
    }

int main (int argc, char* argv[])
    {
    int status = 0;
    int files = 0;

    progname = argv[0];

    InitNibbleMem(1024,1024);

    while (--argc)
	{
	++argv;
	if (!strcmp(*argv,"-s")
		|| !strcmp(*argv,"-strip"))
	    {
	    strip = strtol(*++argv,NULL,0);
	    argc--;
	    }
	else if (!strcmp(*argv,"-d")
		|| !strcmp(*argv,"-debug"))
	    {
	    debug = 1;
	    }
	else if (!strcmp(*argv,"-T")
		|| !strcmp(*argv,"-table"))
	    {
	    if (!tblfilename)
		{
		fprintf(stderr,"%s: Give <tblfilename> before all filenames.\n",
			progname);
		return 1;
		}
	    else
		{
		tblfilename = *++argv;
		argc--;
		}
	    }
	else
	    {
	    files++;
	    status += decodefn(*argv);
	    }
	}
    if (!files)
	{
	char* revision = "$Revision: 1.2 $";
	char* date = "$Date: 2003/12/17 19:05:04 $";
	char* p;
	p = strchr(revision,' ');
	if (p)
	    revision = p+1;
	p = strchr(revision,' ');
	if (p)
	    *p = '\0';
	p = strchr(date,' ');
	if (p)
	    date = p+1;
	p = strchr(date,' ');
	if (p)
	    *p = '\0';
	fprintf(stderr,"Usage: %s [-s|-strip <bytestostrip>] [-d|-debug]\n",
		progname);
	fprintf(stderr,"        [-T|-table <tablefilename] {<filename>|-}\n");
	fprintf(stderr,"\n");
	fprintf(stderr,"This is berdecode, revision %s as of %s.\n",
		revision,date);
	fprintf(stderr,"This program reads a binary ASN.1 grammar file generated by snacc -T\n");
	fprintf(stderr,"and uses it to decode ASN.1 BER encoded data from files or stdin.\n");
	fprintf(stderr,"\n");
	fprintf(stderr,"From every message the first <bytestostrip> bytes (default 0)\n");
	fprintf(stderr,"are skipped.\n");
	fprintf(stderr,"\n");
	fprintf(stderr,"Flag -d gives additional information during decoding.\n");
	status = 1;
	}
    return status;
    }
