/*
 * MAIN.C (VEC)
 *
 * Copyright (c) 1993 Ville Saari
 * All rights reserved
 *
 * Created: 07-Apr-93
 * Updated: 06-Dec-93
 */

#include <limits.h>
#include "vec.h"

const unsigned short crc16tab[256]=
	{
	0x0000, 0xc0c1, 0xc181, 0x0140, 0xc301, 0x03c0, 0x0280, 0xc241,
	0xc601, 0x06c0, 0x0780, 0xc741, 0x0500, 0xc5c1, 0xc481, 0x0440,
	0xcc01, 0x0cc0, 0x0d80, 0xcd41, 0x0f00, 0xcfc1, 0xce81, 0x0e40,
	0x0a00, 0xcac1, 0xcb81, 0x0b40, 0xc901, 0x09c0, 0x0880, 0xc841,
	0xd801, 0x18c0, 0x1980, 0xd941, 0x1b00, 0xdbc1, 0xda81, 0x1a40,
	0x1e00, 0xdec1, 0xdf81, 0x1f40, 0xdd01, 0x1dc0, 0x1c80, 0xdc41,
	0x1400, 0xd4c1, 0xd581, 0x1540, 0xd701, 0x17c0, 0x1680, 0xd641,
	0xd201, 0x12c0, 0x1380, 0xd341, 0x1100, 0xd1c1, 0xd081, 0x1040,
	0xf001, 0x30c0, 0x3180, 0xf141, 0x3300, 0xf3c1, 0xf281, 0x3240,
	0x3600, 0xf6c1, 0xf781, 0x3740, 0xf501, 0x35c0, 0x3480, 0xf441,
	0x3c00, 0xfcc1, 0xfd81, 0x3d40, 0xff01, 0x3fc0, 0x3e80, 0xfe41,
	0xfa01, 0x3ac0, 0x3b80, 0xfb41, 0x3900, 0xf9c1, 0xf881, 0x3840,
	0x2800, 0xe8c1, 0xe981, 0x2940, 0xeb01, 0x2bc0, 0x2a80, 0xea41,
	0xee01, 0x2ec0, 0x2f80, 0xef41, 0x2d00, 0xedc1, 0xec81, 0x2c40,
	0xe401, 0x24c0, 0x2580, 0xe541, 0x2700, 0xe7c1, 0xe681, 0x2640,
	0x2200, 0xe2c1, 0xe381, 0x2340, 0xe101, 0x21c0, 0x2080, 0xe041,
	0xa001, 0x60c0, 0x6180, 0xa141, 0x6300, 0xa3c1, 0xa281, 0x6240,
	0x6600, 0xa6c1, 0xa781, 0x6740, 0xa501, 0x65c0, 0x6480, 0xa441,
	0x6c00, 0xacc1, 0xad81, 0x6d40, 0xaf01, 0x6fc0, 0x6e80, 0xae41,
	0xaa01, 0x6ac0, 0x6b80, 0xab41, 0x6900, 0xa9c1, 0xa881, 0x6840,
	0x7800, 0xb8c1, 0xb981, 0x7940, 0xbb01, 0x7bc0, 0x7a80, 0xba41,
	0xbe01, 0x7ec0, 0x7f80, 0xbf41, 0x7d00, 0xbdc1, 0xbc81, 0x7c40,
	0xb401, 0x74c0, 0x7580, 0xb541, 0x7700, 0xb7c1, 0xb681, 0x7640,
	0x7200, 0xb2c1, 0xb381, 0x7340, 0xb101, 0x71c0, 0x7080, 0xb041,
	0x5000, 0x90c1, 0x9181, 0x5140, 0x9301, 0x53c0, 0x5280, 0x9241,
	0x9601, 0x56c0, 0x5780, 0x9741, 0x5500, 0x95c1, 0x9481, 0x5440,
	0x9c01, 0x5cc0, 0x5d80, 0x9d41, 0x5f00, 0x9fc1, 0x9e81, 0x5e40,
	0x5a00, 0x9ac1, 0x9b81, 0x5b40, 0x9901, 0x59c0, 0x5880, 0x9841,
	0x8801, 0x48c0, 0x4980, 0x8941, 0x4b00, 0x8bc1, 0x8a81, 0x4a40,
	0x4e00, 0x8ec1, 0x8f81, 0x4f40, 0x8d01, 0x4dc0, 0x4c80, 0x8c41,
	0x4400, 0x84c1, 0x8581, 0x4540, 0x8701, 0x47c0, 0x4680, 0x8641,
	0x8201, 0x42c0, 0x4380, 0x8341, 0x4100, 0x81c1, 0x8081, 0x4040
	};

extern const unsigned char usagestring[];

unsigned char method=DEFMETHOD;
long width=DEFWIDTH;
int quick, silent, decode, nomode, cr, shortlines=1, literaltabs;
int lines=0, pipe=0, resetuu=0;
static int append;
char *name=0;
static filehandle infile;
filehandle outfile, stdoutfile;
static int infileflag=0;
int outfileflag=0;
unsigned char *inbuf, *inptr, *outptr, *inbufend;
static unsigned char *outbuf;
unsigned long bufsize=BUFSIZE;
unsigned long trueread;
unsigned char *outbufend;
static int eof;

void printerrh(const char *string)
	{
	printerr(decode?UDNAME": ":UENAME": ");
	printerr(string);
	}

int main(int ac, char **arg)
	{
	int t, matches=0, retval=OK;
	char *p, *filename=0, *workdir=0;

	if(!ac) return FAIL;

	init();

	if((t=strlen(arg[0]))>1 && tolower(arg[0][t-2])=='d') decode=1;

	while(arg++, --ac && **arg=='-' && *(p=*arg+1))
		do switch(*p)
			{
			case '0':
			case '1':
			case '2':
			case '3':
			case 'a':
			case 'i':
			case 'u':
			case 'x':
				method=*p;
				break;

			case 'd':
				decode=1;
				break;

			case 'e':
				decode=0;
				break;

			case 'f':
				shortlines=0;
				break;

			case 'L':
				lines=2;
				break;

			case 'l':
				lines=1;
				break;

			case 'p':
				pipe=1;
				break;

			case 'q':
				quick=1;
				break;

			case 'r':
				cr=1;
				break;

			case 'R':
				resetuu=1;
				break;

			case 's':
				silent=1;
				break;

			case 't':
				literaltabs=1;
				break;

			case 'D':
				if(!--ac) goto usage;
				workdir=*++arg;
				break;

			case 'n':
				if(!--ac) goto usage;
				name=*++arg;
				break;

			case 'N':
				nomode=1;
				break;

			case 'A':
				if(!--ac) goto usage;
				filename=*++arg;
				append=1;
				break;

			case 'o':
				if(!--ac) goto usage;
				filename=*++arg;
				break;

			case 'b':
				if(!--ac || (bufsize=atoi(*++arg))<512) goto usage;
				break;

			case 'w':
				if(--ac && (width=atoi(*++arg))>=0)
					{
					if(!width) width=LONG_MAX;
					break;
					}

			default:
			usage:
				printerr(usagestring);
				cleanup();
				return FAIL;
			}
		while(*++p);

	if(width<3 && (method=='a' || method=='i')) width=3;

	if(ac && **arg=='-') arg++, ac--;

	if(!(inbuf=malloc(bufsize)) || !(outbuf=malloc(bufsize+SPAREBUF)))
#ifdef FINNISH
		errcleanup("Muisti ei riit" a_ " I/O puskureille.\n");
#else
		errcleanup("Can't allocate memory for I/O buffers.\n");
#endif
	inbufend=inptr=inbuf;
	outptr=outbuf;
	outbufend=outbuf+bufsize;

	if(workdir && !changedir(workdir))
#ifdef FINNISH
		errcleanup("Ty" o_ "hakemiston vaihto ei onnistu.\n");
#else
		errcleanup("Can't change work directory.\n");
#endif

	stdoutfile=getstdout(decode && pipe);

	if(filename)
		{
		if(failedopen(outfile=
			append?openappend(filename, decode):openwrite(filename, decode)))
#ifdef FINNISH
			errcleanup("Tulostustiedosto ei aukea.\n");
#else
			errcleanup("Can't open output file.\n");
#endif
		else
			outfileflag=1;
		}
	else if(!decode || pipe)
		outfile=stdoutfile;

	outptr=outbuf;

	if(ac)
		{
		while(ac--)
			{
			p=firstmatch(*arg);

			while(p)
				{
				matches++;

				if(failedopen(infile=openread(p, !decode)))
					{
#ifdef FINNISH
					printerrh("Tiedosto `");
					printerr(p);
					printerr("' ei aukea.\n");
#else
					printerrh("Can't open input file `");
					printerr(p);
					printerr("'.\n");
#endif
					retval=ERROR;
					}
				else
					{
					infileflag=1;
					eof=0;
					inptr=inbufend;

					if(decode)
						{
						if(!vdc()) retval=ERROR;
						}
					else
						vec(p);

					closefile(infile);
					infileflag=0;
					}

				p=nextmatch();
				}

			arg++;
			}

		if(!matches)
			{
#ifdef FINNISH
			printerr("Ei tiedostoja.\n");
#else
			printerr("No match.\n");
#endif
			retval=WARN;
			}
		}
	else
		{
		infile=getstdin(!decode);
		decode?vdc():vec("");
		}

	if(outfile) flushoutput();
	if(filename) closefile(outfile);

	cleanup();
	return retval;
	}

void errcleanup(const char *msg)
	{
	if(infileflag) closefile(infile);
	if(outfileflag) closefile(outfile);

	if(msg)
		printerrh(msg);

	cleanup();
	exit(FAIL);
	}

int fillbuffer(int clear)
	{
	unsigned char *t=inbuf+bufsize;
	long s;

	if(interrupt()) errcleanup("*** Break\n");

	if(eof) return 0;

	if(clear) inbufend=inptr=inbuf;

	do inbufend+=s=readfile(infile, inbufend, t-inbufend);
	while(s>0 && inbufend<t);

#ifdef FINNISH
	if(s<0) errcleanup("Virhe tiedostoa lukiessa.\n");
#else
	if(s<0) errcleanup("Error while reading input file.\n");
#endif
	if(!s) eof=1;

	return 1;
	}

unsigned char *get(unsigned long size)
	{
	unsigned char *t=inptr;
	long s;

	trueread=size;

	if((inptr+=size)<=inbufend) return t;

	memcpy(inbuf, t, s=inbufend-t);
	inbufend=inbuf+s;

	fillbuffer(0);

	if((inptr=inbuf+size)>inbufend)
		{
		inptr=inbufend;
		trueread=inbufend-inbuf;
		}

	return inbuf;
	}

void flushoutput(void)
	{
	unsigned char *t=outbuf;
	long s;

	if(interrupt()) errcleanup("*** Break\n");

	while(t<outptr)
		{
		if((s=writefile(outfile, t, outptr-t))<=0)
#ifdef FINNISH
			errcleanup("Virhe tiedostoa kirjoittaessa.\n");
#else
			errcleanup("Error while writing output file.\n");
#endif

		t+=s;
		}

	outptr=outbuf;
	}

void put(const unsigned char *data, unsigned long size)
	{
	while(outptr+size>outbufend)
		{
		unsigned long t=outbufend-outptr;

		memcpy(outptr, data, t);
		outptr=outbufend;
		data+=t;
		size-=t;

		flushoutput();
		}

	memcpy(outptr, data, size);
	outptr+=size;
	}

char *ltoa(unsigned long l)
	{
	static char buf[10];
	char *p=buf+9;

	do	*--p='0'+l%10; while(l/=10);

	return p;
	}
