#include <stdio.h>
#include <libraries/dosextens.h>
#include <functions.h>
#include "hunk.h"
#include <exec/types.h>

#define	DC	SET_UNCHANGED		/* dont change flag */

int	first = 0, last = 1, current, listsize;
struct	FileHandle *fd;
ULONG	codemem=DC, datamem=DC, bssmem=DC, memtype(), *changelist = NULL;
BOOL	verbose = FALSE;

main(argc, argv)
int	argc;
char	**argv;
{
	int	i = 2;

	if (argc < 3)
	{
		show_usage(argv[0]);
	}
	while (i < argc)
	{
		if (argv[i][0] == '-')
		{
			if (argv[i][1] == VERBOSE_FLAG) {
				verbose = TRUE;
			}
		}
		else if ((argv[i][1] != '=') && (argv[i][0] != '-'))
		{
			show_usage(argv[0]);
			exit(0);
		}
		else {
			set_mem_flags(argv[i]);
		}
		i++;
	}
	if ((fd = Open(argv[1],MODE_OLDFILE))==NULL)
	{
		printf("Sorry, file: %s not found\n",argv[1]);
		exit(10);
	}
	processfile();
	fixhunk();
	Exit();
}

/***********************************************************************
*
*  ROUTINE:	memtype
*
*  IMPORTS:	char	type;		character after '=' in CLI arg
*
*  RETURNS:	ULONG	memtype;	memory specification long word
*
*  DESCRIPTION:	returns the mask for the type of memory specified by
*		the character after the '=' in a CLI argument
*
***********************************************************************/

ULONG	memtype(type)
char	type;
{
	ULONG	settype;

	switch (type)
	{
	case	SPEC_CHIP:
		settype = SET_CHIP;
		break;

	case	SPEC_FAST:
		settype	= SET_FAST;
		break;

	case	SPEC_EITHER:
		settype = SET_EITHER;
		break;

	default:
		settype = SET_UNCHANGED;
	}
	return(settype);
}
		
/***********************************************************************
*
*  ROUTINE:	processfile
*
*  IMPORTS:	none
*
*  RETURNS:	none
*
*  DESCRIPTION:	reads through the file until the last hunk has bee processed
*
***********************************************************************/

processfile()
{
	ULONG	hunk, readlong();

	while (first <= last)
	{
		hunk = (readlong());
		if (verbose) {
			printf("Hunk type %x\n", hunk);
		}
		processhunk(hunk);
	}
}

/***********************************************************************
*
*  ROUTINE:	readlong
*
*  IMPORTS:	NONE
*
*  RETURNS:	ULONG	data;	long word read from the file
*
*  DESCRIPTION:	reads the next long word in the file
*
***********************************************************************/

ULONG	readlong()
{
	ULONG	hunk[2];
	int	bytes;

	if ((bytes = Read(fd, hunk, sizeof(ULONG))) < sizeof(ULONG))
	{
		printf("could not read full long word\n");
		Exit(0);
	}
	return(hunk[0]);
}

/***********************************************************************
*
*  ROUTINE:	processhunk
*
*  IMPORTS:	ULONG	hunk;	hunk type
*
*  RETURNS:	NONE
*
*  DESCRIPTION:	calls the handler routine for the specified hunk type
*
***********************************************************************/

processhunk(hunk)
ULONG	hunk;
{
	switch (hunk)
	{
	case	HUNK_HEADER:
		header_hunk();
		break;

	case	HUNK_CODE:
		code_hunk();
		break;

	case	HUNK_RELOC8:
	case	HUNK_RELOC16:
	case	HUNK_RELOC32:
		reloc_hunk();
		break;

	case	HUNK_DEBUG:
		debug_hunk();
		break;

	case	HUNK_END:
		first++;
		break;

	case	HUNK_DATA:
		data_hunk();
		break;

	case	HUNK_BSS:
		bss_hunk();
		break;

	default	:
		break;
	}
}

/***********************************************************************
*
*  ROUTINE:	fastforward
*
*  IMPORTS:	NONE
*
*  RETURNS:	NONE
*
*  DESCRIPTION:	advances <offset> long words through the file;
*
***********************************************************************/

fastforward(offset)
long	offset;
{
	ULONG	readlong();
	int	oldpos, i;

	offset *= sizeof(ULONG);
	oldpos = Seek(fd, offset, OFFSET_CURRENT);
}

/***********************************************************************
*
*  ROUTINE:	fastback
*
*  IMPORTS:	NONE
*
*  RETURNS:	NONE
*
*  DESCRIPTION:	Backs up 1 long word in the file
*
***********************************************************************/

fastback()
{
	int oldpos;

	oldpos = Seek(fd, -sizeof(ULONG), OFFSET_CURRENT);
}

/***********************************************************************
*
*  ROUTINE:	header_hunk
*
*  IMPORTS:	none
*
*  RETURNS:	none
*
*  DESCRIPTION:	Processes the header hunk and allocates enough memory
*		for the hunk table.
*
***********************************************************************/

header_hunk()
{
	ULONG	chars_in_name, size, readlong();
	int	oldposition, i;
	long	offset;

	chars_in_name = readlong();
	while (chars_in_name)
	{
		offset = chars_in_name;
		fastforward(offset);
		chars_in_name = readlong();
	}
	size = readlong();
	first = readlong();
	last = readlong();
	offset = 0;
	for (i = first; i <= last; i++)
	{
		offset += readlong();
	}
	changelist = (ULONG *)AllocMem(size * sizeof(ULONG), 0);
	listsize = size;
	current = 0;
}

/***********************************************************************
*
*  ROUTINE:	code_hunk
*
*  IMPORTS:	NONE
*
*  RETURNS:	NONE
*
*  DESCRIPTION:	processes all code hunks
*
***********************************************************************/

code_hunk()
{
	ULONG	size, temp, readlong();

	changelist[current++] = codemem;
	size = readlong();
	fastforward(size);
}

/***********************************************************************
*
*  ROUTINE:	reloc_hunk
*
*  IMPORTS:	NONE
*
*  RETURNS:	NONE
*
*  DESCRIPTION:	handles all reloc32 hunks
*
***********************************************************************/

reloc_hunk()
{
	ULONG	num, garb, readlong();
	int	i;

	num = readlong();
	while (num != 0)
	{
		num++;
		fastforward(num);
		num = readlong();
	}
}

/***********************************************************************
*
*  ROUTINE:	debug_hunk
*
*  IMPORTS:	NONE
*
*  RETURNS:	NONE
*
*  DESCRIPTION:	handles all debug hunks
*
***********************************************************************/

debug_hunk()
{
	ULONG	num, readlong();

	num = readlong();
	if (num >0)
	{
		fastforward(num);
	}
}

/***********************************************************************
*
*  ROUTINE:	data_hunk
*
*  IMPORTS:	NONE
*
*  RETURNS:	NONE
*
*  DESCRIPTION:	processes all data hunks.
*
***********************************************************************/

data_hunk()
{
	ULONG	readlong();
	long	num, check_len;
	BOOL	test_string();

	num = readlong();
	changelist[current++] = datamem;
	fastforward(num);
}

/***********************************************************************
*
*  ROUTINE:	bss_hunk
*
*  IMPORTS:	none
*
*  RETURNS:	none
*
*  DESCRIPTION:	handles all uninitiallized data hunks
*
***********************************************************************/

bss_hunk()
{
	ULONG	num, readlong();

	changelist[current++] = bssmem;
	num = readlong();
}

/***********************************************************************
*
*  ROUTINE:	newtype
*
*  IMPORTS:	ULONG	type;	type of memory hunk is to be loaded into
*
*  RETURNS:	NONE
*
*  DESCRIPTION:	Changes the specification for where a hunk is to be
*		loaded into memory.
*
***********************************************************************/

newtype(type)
ULONG	type;
{
	ULONG	readlong(), oldval, wrote, newval;

	oldval = readlong();
	if (type != SET_UNCHANGED)
	{
		fastback();
		oldval &= SET_MASK;
		newval = oldval | type;
		if (verbose) {
			printf("changing %x to %x\n", oldval, newval);
		}
		wrote = Write(fd, &newval, sizeof(ULONG));
		if (wrote != sizeof(ULONG))
		{
			printf("did not write full hunk label\n");
			Exit();
		}
	}
}

/***********************************************************************
*
*  ROUTINE:	Exit
*
*  IMPORTS:	NONE
*
*  RETURNS:	NONE
*
*  DESCRIPTION:	Frees memory, closes file, exits program.
*
***********************************************************************/

Exit()
{
	int	i;

	if (changelist != NULL)
	{
		FreeMem(changelist, listsize);
		changelist = NULL;
	}
	Close(fd);
	exit(0);
}

/***********************************************************************
*
*  ROUTINE:	fixhunk
*
*  IMPORTS:	none
*
*  RETURNS:	none
*
*  DESCRIPTION:	read through the table of hunk definitions made by this
*		program and calls newtype() for all hunks that have been
*		changed
*
***********************************************************************/

fixhunk()
{
	ULONG	chars_in_name, size, readlong();
	int	oldposition, i;
	long	offset;

	oldposition = Seek(fd, 4L, OFFSET_BEGINNING);
	chars_in_name = readlong();
	while (chars_in_name)
	{
		offset = chars_in_name;
		fastforward(offset);
		chars_in_name = readlong();
	}
	size = readlong();
	size = readlong();
	size = readlong();
	for (i = 0; i < current; i++)
	{
		newtype(changelist[i]);
	}
}

/***********************************************************************
*
*  ROUTINE:	set_mem_flags
*
*  IMPORTS:	char	*arg;	CLI argument to be interpreted
*
*  RETURNS:	none
*
*  DESCRIPTION:	interprets a hunk memory specification
*
***********************************************************************/

set_mem_flags(arg)
char	*arg;
{
	switch(arg[0])
	{
	case	SPEC_DATA:
		datamem = memtype(arg[2]);
		break;

	case	SPEC_CODE:
		codemem = memtype(arg[2]);
		break;

	case	SPEC_BSS:
		bssmem = memtype(arg[2]);
		break;
	}
}

/***********************************************************************
*
*  ROUTINE:	show_usage
*
*  IMPORTS:	char	*name;	program name
*
*  RETURNS:	none
*
*  DESCRIPTION:	shows usage for the program
*
***********************************************************************/

show_usage(name)
char	*name;
{
	printf("USAGE: %s <file> [-v] [c,d,b]=[c,f,e]\n", name);
	printf("\n-v	sets verbose mode on\n");
	printf("[c/d/b]	specify which hunks are to be altered.\n");
	printf("	c - code, d - data, b - uninitaillized data.\n");
	printf("[c/f/e]	specify where the altered hunks are to load.\n");
	printf("	c - chip, f - fast, e - doesn't matter\n");
	printf("\nNote:	changing two or more hunk types requires that the\n");
	printf("	specification argument be repeated for each hunk\n");
	printf("	type.  ie to load code into fast memory, and data\n");
	printf("	into chip memory, the command would be\n");
	printf("	%s <file> c=f d=c\n", name);
	printf("\nYou may distribute this program free of charge to anyone\n");
	printf("as long as: the README file is distributed with it, and it\n");
 	printf("is not part of a commercial product.\n\n");
	printf("If you use this program and it saves you several hours of\n");
	printf("work, I would appreciate any contribution\n");
 	printf("	Terry Fisher, Jan 17 1988\n");
	exit(0);
}
