/* TLPatch.c V1.0 */
/* Translator.library patch utility */
/* Richard Sheppard - Jan. 7, 1991 */
/* Toronto, Canada */

#include <exec/types.h>
#include <stdio.h>
#include <exec/execbase.h>
#include <exec/nodes.h>

char line[256];									/* line buffer */
LONG codesize;										/* size of code & xtbl hunk */
LONG jmptab[28];									/* jump table array */
FILE *fp1, *fp2;					/* input file (exception table), outfile */
FILE *fp3;							/* input file (translator.library) */
WORD code[969];									/* original code at start */
LONG reloc[38] =									/* reloc table at end of file */
{
	0x000003EC, 0x00000004,	0x00000000, 0x000000F4,
	0x000000F0, 0x000000EC,	0x000000E8, 0x00000012,
	0x00000000, 0x0000063E,	0x0000063A, 0x00000636,
	0x00000632, 0x0000062E,	0x0000062A, 0x00000626,
	0x00000622, 0x0000061E,	0x0000061A, 0x00000616,
	0x00000612, 0x0000060E,	0x000005D6, 0x000003B2,
	0x0000039A, 0x000001EE,	0x00000176, 0x00000001,
	0x00000000, 0x000000F8,	0x00000001, 0x00000000,
	0x000000C8, 0x00000000,	0x000003F2, 0x000003E9,
	0x00000000, 0x000003F2
};
struct ExecBase *ExecBase = NULL;
struct Node *node;

void main(),AddFile(),Validate(),Extract();
int GetLine(char line[], int max);
int GetExcept(char line[], int max);
int StrIndex(char source[], char searchfor[]);

char pattern[] = "[A";									/* 1st search pattern */

void
main(argc,argv)
int argc;
char *argv[];
{
	int c,opt,x = 0,xcnt = 0,size = 0;

	printf("\n\tTLPatch - translator.library patch utility V1.0\n");
	printf("\t            Richard Sheppard - 1991\n\n");
	while(--argc > 0)
		if((*++argv)[0] == '-')				/* parse command line arguments */
		{
			while(opt = *++argv[0])
				switch(opt)
				{
					case 'x':
					case 'X':
						Extract();
						exit(0);
						break;
					default:
						break;
				}
		}
	if((fp1 = fopen("ram:except.tbl","r")) == NULL)
	{
		printf("*** Can't open ram:except.tbl\n");
		printf("--- Copy your except.tbl to ram: or\n");
		printf("--- use \"%s -x\" to extract table.\n",*argv);
		exit(0);
	}
	else if((fp2 = fopen("ram:xtable.new","w")) == NULL)
	{
		printf("*** Can't open ram:xtable.new\n");
		fclose(fp1);
		exit(0);
	}
	else if((fp3 = fopen("sys:libs/translator.library","rb")) == NULL)
	{
		printf("*** Can't open sys:libs/translator.library\n");
		fclose(fp2);
		fclose(fp1);
		exit(0);
	}

	if(!(ExecBase = (struct ExecBase *)OpenLibrary("exec.library", 0L)))
		printf("*** Can't open ExecBase\n");
	else 
		if((node = (struct Node *)FindName(&ExecBase->LibList,"translator.library")) != 0)
		{
			printf("\tRemoving resident translator.library\n");
			Remove(node);
		}

	printf("\tReading exception table ...\n");
	while((c = GetLine(line,256)) > 0)
	{
		size = size + c;
		if(StrIndex(line, pattern) >= 0)
		{
			jmptab[x] = (LONG)(size - c + 112);			/* 112 = table size */
			x++;
			pattern[1]++;						/* increment search character */
			if(pattern[1] == 91)
				pattern[1] = 48;				/* "0"  - start of numbers */
			if(pattern[1] == 49)
				pattern[1] = 32;				/* " "  - start of punctuation */
			if(pattern[1] == 33)
				pattern[0] = 0;							/* NULL */
		}
		fprintf(fp2,"%s",line);							/* write new xtable */
		xcnt++;												/* exception count */
	}
	fputc('\0',fp2);							/* NULL at end of exception table */
	size++;													/* size + NULL */
	if((size + 2) % 4)
	{
		for(x = ((size + 2) % 4);x < 4;x++)
		{
			fputc('\0',fp2);					/* align table to WORD boundary */
			size++;
		}
	}
	codesize = (size + 2014) / 4;						/* 2014 = code + jmptab */
	fclose(fp2);
	fclose(fp1);
	printf("\tReading original code ...\n");
	Validate();
	fclose(fp3);
	if(codesize < 65536)
	{
		code[10] = 0x0000;								/* patch hunk size */
		code[11] = (WORD)codesize;
	}
	else
	{
		code[10] = (WORD)codesize / 65535;			/* patch hunk size */
		code[11] = (WORD)codesize % 65535;
	}
	code[16] = code[10];									/* 2nd copy of hunk size */
	code[17] = code[11];

	if((fp1 = fopen("ram:translator.library","wb")) == NULL)
	{
		printf("*** Can't create ram:translator.library\n");
		exit(0);
	}
	fwrite((char *)&code,2,969,fp1);					/* write 969 words */
	fwrite((char *)&jmptab,2,56,fp1);				/* write new jump table */
	AddFile();												/* append new xtable */
	fwrite((char *)&reloc,2,76,fp1);					/* write reloc table */
	fclose(fp1);
	remove("ram:xtable.new");
	printf("\n\tThe new translator.library is now in ram:\n");
	printf("\t\t\t%d exceptions\n\n",xcnt);
	if(ExecBase)
		CloseLibrary(ExecBase);
	exit(0);
}

int
GetLine(char s[], int lim)
{
	int c, i;
	i = 0;
	while(--lim > 0 && (c=fgetc(fp1)) != EOF && c != '\n')
		s[i++] = c;
	s[i] = '\0';
	return i;
}

int
GetExcept(char s[], int lim)
{
	int c, i;
	i = 0;
	while(--lim > 0 && (c=fgetc(fp3)) != EOF && c != '\\' && c != '`')
		s[i++] = c;
	if(c == '\\' || c == '`')
		s[i++] = c;
	s[i] = '\0';
	return i;
}

int
StrIndex(char s[], char t[])
{
	int i;
	for(i = 0;s[i] != '\0';i++)
	{
		if(s[i] == t[0] && s[i+1] == t[1])
			return i;
	}
	return -1;
}

void
AddFile()
{
	int c;
	if((fp2 = fopen("ram:xtable.new","r")) == NULL)
	{
		printf("*** Can't re-open ram:xtable.new\n");
		fclose(fp1);
		exit(0);
	}
	while((c = getc(fp2)) != EOF)
		putc(c,fp1);
	fclose(fp2);
	return;
}

void
Validate()
{
	int x;
	fread((char *)&code,2,969,fp3);					/* read 969 words */
	if(code[151] != 0x2033 || code[152] != 0x332E || code[153] != 0x3220)
	{
		printf("*** WARNING - not V33.2, unpredictable results could occur!\n");
		for(x=0;x<3;x++)
			printf("%04x ",code[151+x]);
		printf("\n");
	}
	return;
}

void
Extract()
{
	int c;
	printf("\tExtracting exception table ...\n");
	if((fp1 = fopen("ram:except.tbl","w")) == NULL)
	{
		printf("*** Can't create ram:except.tbl\n");
		exit(0);
	}
	else if((fp3 = fopen("sys:libs/translator.library","rb")) == NULL)
	{
		printf("*** Can't open sys:libs/translator.library\n");
		fclose(fp1);
		exit(0);
	}
	Validate();
	fread((char *)&code,2,56,fp3);					/* read jump table */
	while((c = GetExcept(line,256)) > 0)
	{
		fprintf(fp1,"%s",line);
		if(line[1] != '\\' && line[1] != '`')
			fprintf(fp1,"\n");
	}
	fclose(fp3);
	fclose(fp1);
	printf("\n\tThe exception table (except.tbl) is now in ram:\n\n");
	return;
}

/* end of TLPatch.c */
