#include <fido.h>
#include <ascii.h>

/*
	Compiles a .LXT file, producing the .SLG file (SM+ and LM messages)
	and the .CLG file, containing the CM messages.


*/

struct _fido fido;
_stack = 4000;

#define SIZE 1000		/* max. strings per table */
unsigned ptr[SIZE];		/* table of text offsets */
char *text;			/* the text blob */
unsigned size;			/* it's maximum size */
unsigned highest;		/* highest index, per table */
unsigned amt;			/* how much in there, per table */

unsigned totl_strings;		/* total number of strings */
unsigned totl_size;		/* total string size */

char fname[SS];			/* language filename */

int logfile;			/* log shit here */

main(argc,argv)
int argc;
char **argv;
{
char buff[256],*cp,*op;
char et;			/* element type */
unsigned en;			/* element number */
int in,out;			/* file handles */
int phase;			/* which pass: LM, SM, CM */
int i,n;
unsigned totl_strings,totl_size;

	printf("FidoText Language File Compiler -- 1 Dec 89\r\n");
	printf("Copyright Tom Jennings 1984, 1985, 1986, 1987, 1988, 1989\r\n");
	printf("Fido Software, Box 77731, San Francisco CA 94107\r\n");
	printf("All rights reserved. \"Fido\", \"FidoNet\" and the\r\n");
	printf("dog-with-diskette are registered trademarks of Tom Jennings.\r\n\r\n");

	printf("\r\nThis is a restricted use program. Not for distribution.\r\n");
	allmem();
	fastfile(6);

	size= sizmem();

	if (size < 20000) {
		printf("Not enough memory to run!\r\n");
		exit(1);
	}
	text= (char *) getmem(size);		/* get working storage */

	if (--argc) 				/* get filename */
		cpyarg(fname,*++argv);		/* from command line */
	else {
		printf("You have to specify a language filename\r\n");
		exit(1);
	}

	n= open("fido.sys",0);				/* load system stuff */
	if (n == -1) {
		clprintf("The Fido system file \"FIDO.SYS\" is missing!\r\n");
		exit(1);
	}
	read(n,&fido,sizeof(fido));
	close(n);
	if (fido.fido_version != FIDOVER) {
		clprintf("Wrong Fido/FidoNet version!\r\n");
		exit(1);
	}

/* Pre-process the filename so that we have a clean copy of the name portion
around for making the full filename. Basically, lop off any extention and
make upper case. */

	for (cp= fname; *cp; cp++) {			/* remove any extention */
		if (*cp == '.') {			/* from filename */
			*cp= NUL;
			break;
		}
	}
	stoupper(fname);				/* make all upper case */

	strcpy(buff,fname);
	strcat(buff,".LXT");				/* input file name */
	in= open(buff,0);
	if (in == -1) {
		printf("Can't find \"%s\" input file!\r\n",buff);
		exit(1);
	}
	strcpy(text,fname);
	strcat(text,".LOG");
	logfile= creat(text,2);				/* start logging */

	clprintf("Log File:               %s\r\n",text);
	clprintf("Input File:             %s\r\n",buff);
	clprintf("Maximum String Size:    %8,lu\r\n",0L + size);
	clprintf("Maximum Table Elements: %8,d\r\n",SIZE);

/* Now compile the output file. */

	newdelim(" ,\t");				/* the only delimiters */
	phase= 'S';					/* from the top */
	totl_strings= totl_size= 0;			/* zero tally counters */

	while (phase != 'X') {
		switch (phase) {
			case 'S': out= makeout(".SLG"); wrthdr(out); break;
			case 'C': out= makeout(".CLG"); wrthdr(out); break;
		}

		op= text;				/* set output pointer */
		amt= highest= 0;			/* table index */
		lseek(in,0L,0);				/* start from the beginning */
		for (i= 0; i < SIZE; i++) ptr[i]= 0;	/* clear the table */

/* Lines have the format:

XMnnn	"string"

Where X is the element type, and nnn is the element number. */


		while (getline(in,buff,sizeof(buff))) {	/* read a line */
			cp= skip_delim(buff);
			et= toupper(*cp);		/* get element type */
			en= atoi(&cp[2]);		/* element number */

			if ((et == phase) || (et == 'N')) { /* if correct phase */
				cp= next_arg(cp);	/* skip keyword */
				cpyscrarg(op,cp);	/* copy, strip quotes */
				scrmac(op,op);		/* expand controls */
				if (en >= SIZE) {
					clprintf("OOPS -- A numerator is out of range!\r\n");
					clprintf("I give up!\r\n");
					phase= 'X';
					break;
				}
				ptr[en]= op - text;	/* set it's place in the table */
				if (en > highest) highest= en;
				++totl_strings;		/* count total defined */
				i= strlen(op) + 1;	/* length of this item */
				if (amt + i > size) {
					clprintf("OOPS -- Total size of text strings is too large!\r\n");
					clprintf("I give up!\r\n");
					phase= 'X';
					break;
				}
				amt += i;		/* total count */
				op += i;		/* advance pointer */
				totl_size += i;		/* total string size */
			}
		}

/* End of file -- write the table out. First we have to fixup all the offsets
in the pointer table; the table is loaded with the text immediately following;
the offsets should be relative to the start of the table. */

		ptr[0] += highest * 2;			/* 0 is always lang. name */
		for (i= 0; i <= highest; i++) {		/* add table size to */
			if (ptr[i]) 			/* if defined, */
				ptr[i] += highest * 2;	/* each str offset */
		}

		write(out,(char *)&ptr[0],highest * 2);	/* write table */
 		if (write(out,text,amt) != amt) {	/* then text */
			clprintf("OOPS -- Disk full!\r\n");
			clprintf("I give up!\r\n");
			phase= 'X';
		}

/* Switch to the next phase. */

		switch (phase) {
			case 'S': 			/* this phase complete */
				clprintf("SM Table String Size:   %8,d\r\n",amt);
				clprintf("Highest Element:           SM%03d\r\n",highest);
				logholes(phase); close(out); phase= 'C'; break;

			case 'C': 
				clprintf("CM Table String Size:   %8,d\r\n",amt);
				clprintf("Highest Element:           CM%03d\r\n",highest);
				logholes(phase); close(out); phase= 'X'; break;
		}
	}
	clprintf("\r\n");
	clprintf("Total String Size:      %8,d\r\n",totl_size);
	clprintf("Total String Elements:  %8,d\r\n",totl_strings);
	close(in);
	close(logfile);
}

/* Log all the holes in the table. */

logholes(phase)
char phase;
{
int i,n;

	for (n= -1, i= 0; i < highest; i++) {
		if (ptr[i] == 0) {
			if (n == -1) {
				clprintf("Unused stringIDs:\r\n");
				n= 0;
			}
			clprintf("%cM%-3d  ",phase,i);
			if (++n >= 8) {
				clprintf("\r\n");
				n= 0;
			}
		}
	}
	if (n > 0) clprintf("\r\n");
}

/* Write out some junk as a file header. */

wrthdr(f)
unsigned f;
{
char *cp;
int i;

	for (cp= text, i= 256; i--;) *cp++= NUL;	/* clear out memory */
	strcpy(text,"The contents of this file are Copyright ");
	strcat(text,"Tom Jennings\Fido Software, San Francisco CA 94107.\r\n");
	strcat(text,"All rights reserved. For use with the Fido/FidoNet software ");
	strcat(text,"system only. This file should not be modified.\r\n");
	strcat(text,"\26");
	write(f,text,256);				/* write out the header */
}

/* Get a line from the file; return 0 if the file is empty. */

getline(f,buff,len)
int f;
char *buff;
{
char *cp;

	while (rline(f,buff,len)) {			/* read a line of source, */
		cp= skip_delim(buff);
		if (*cp == ';') continue;		/* ignore comments */
		if (! *cp) continue;			/* and blank lines */
		return(1);				/* got one */
	}
	return(0);					/* file empty */
}

/* Make and output filename */

makeout(ext)
char *ext;
{
char buff[SS];
int out;

	strcpy(buff,fname);			/* make full name */
	strcat(buff,ext);
	clprintf("\r\n");
	printf("Creating output file: \"%s\"\r\n",buff);
	out= creat(buff,2);
	if (out == -1) {
		printf("File creation error!\r\n");
		exit(1);
	}
	return(out);
}

/* Copy a script arg; either a single word or a quoted string. */

cpyscrarg(dp,sp)
char *dp,*sp;
{
char lastc,c,q;

	if (*sp == '"') q= *sp++; else q= NUL;		/* optional quote stripping */
	lastc= NUL;
	while (c= *sp) {
		++sp;				/* next ... */
		if ((c == q) && (lastc != '\\')) /* if the quote char & not quoted */
			break;			/* end of argument */
		if (!q && delim(c)) break;	/* else stop if a delimiter */
		*dp++= c;			/* else part of same arg */
		lastc= c;			/* remember last char */
	}
	*dp= NUL;
}

/* Convert C-like control characters. */

static scrmac(dp,sp)
char *dp,*sp;
{
char *cp,c;
int i;

	while (c= *sp++) {
		if (c == '\\') {			/* if literal, */
			c= *sp;				/* get the next char */
			if (c) ++sp;			/* (dont skip the NUL!) */
			switch (tolower(c)) {
				case '0':
				case '1':
				case '2':
				case '3':
				case '4':
				case '5':
				case '6':
				case '7':
				case '8':
				case '9':
					c= atoi(--sp); 
					while (isdigit(*sp)) ++sp;
					break;

				case 'r': c= CR; break;
				case 'n': c= LF; break;
				case 'b': c= BS; break;
				case 't': c= TAB; break;

				default: break;		/* else leave literal as-is */
			}
		}
		if (c) *dp++= c;
	}
	*dp= NUL;
}

clprintf(f)
char *f;
{
char buf[400],*p;

	_spr(buf,&f);
	p= buf;
	write (logfile,p,strlen(p));
	while (*p) bdos(2,*p++);

}
/* Return true if the FBIT is set. */

fbit(bit)
int bit;
{
	return(fido.fbits[bit / sizeof(char)] & (1 << bit % sizeof(char)));
}
