
/*
 * objx.c
 *
 * (C) Copyright 1995 Archie L. Cobbs
 */

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "util.h"
#include "error.h"
#include "names.h"
#include "obj.h"
#include "objx.h"

/*
 * DEFINITIONS
 */

	#define currArg		(ac ? *av : NULL)
	#define nextArg		((ac && --ac) ? *++av : NULL)

/*
 * GLOBAL VARIABLES
 */

	char				*gProgName = "a2objx";
	char				*gUsageMsg = "[-v] file";

	char				*gFileName;
	int					gLineNumber = 0;
	int					gVerbose = FALSE;

	struct ObjHeader	gHeader;
	Names				gNames;

/*
 * INTERNAL FUNCTIONS
 */

	static	void		DoRelocs(FILE *fp, int num);
	static	void		DoExports(FILE *fp, int num);

/*
 *	main()
 */

int
main(int ac, char *av[])
{
	FILE	*infp;

/* Get command line paramters	*/

	while (nextArg && *currArg == '-')
		if (!strcmp(currArg, "-v"))
			gVerbose = TRUE;
		else
			Usage(NULL);
	if (ac != 1)
		Usage(NULL);

/* Open file */

	if ((infp = fopen(gFileName = currArg, "r")) == NULL)
	{
		perror("fopen");
		cerror("can't open file");
	}

/* Read header */

	if (fread(&gHeader, sizeof(struct ObjHeader), 1, infp) != 1)
	{
		if (ferror(infp))
			perror("fread");
		cerror("can't read header");
	}
	if (gHeader.n_magic != OBJ_HEADER_MAGIC)
		cerror("wrong object file format");

	printf("*** Header info:\n");
	printf("\tTEXT SIZE = $%04X bytes\n", gHeader.n_text);
	printf("\tDATA SIZE = $%04X bytes\n", gHeader.n_data);
	printf("\tBSS SIZE  = $%04X bytes\n", gHeader.n_bss);
	printf("\tThere are %d TEXT relocation entries\n", gHeader.n_treloc);
	printf("\tThere are %d DATA relocation entries\n", gHeader.n_dreloc);
	printf("\tThere are %d exported symbols\n", gHeader.n_symbols);
	printf("\tThere are %d bytes of string data\n", gHeader.n_strings);

/* Load strings */

	if (fseek(infp, -gHeader.n_strings, SEEK_END) < 0)
	{
		perror("fseek");
		cerror("can't seek to strings");
	}
	gNames = NamesLoad(infp, gHeader.n_strings);

/* Go to text relocations */

	if (fseek(infp, sizeof(gHeader)
		+ gHeader.n_text + gHeader.n_data, SEEK_SET) < 0)
	{
		perror("fseek");
		cerror("can't seek to relocs");
	}

/* Show text relocations */

	printf("*** TEXT Relocations:\n");
	DoRelocs(infp, gHeader.n_treloc);

/* Show data relocations */

	printf("*** DATA Relocations:\n");
	DoRelocs(infp, gHeader.n_dreloc);

/* Show exported symbols */

	printf("*** Exported symbols:\n");
	DoExports(infp, gHeader.n_symbols);

/* Done */

	fclose(infp);
	return(0);
}

/*
 * DoRelocs()
 */

static	void
DoRelocs(FILE *fp, int num)
{
	int					k;
	struct ObjReloc		reloc;

	for (k = 0; k < num; k++)
	{

	/* Read reloc */

		if (fread(&reloc, sizeof(reloc), 1, fp) != 1)
		{
			perror("fread");
			cerror("can't read reloc #%d", k + 1);
		}

	/* Display it */

		printf("\t$%04X: ", reloc.r_address);
		switch (reloc.r_bytes)
		{
			case 0x01:
				printf("low-order byte");
				break;
			case 0x02:
				printf("high-order byte");
				break;
			case 0x03:
				printf("word format");
				break;
			case 0x0F:
				printf("long format");
				break;
			default:
				printf("format %X", reloc.r_bytes);
				break;
		}
		printf(", %s endian: ", reloc.r_bigend ? "big" : "little");

		if (reloc.r_segrel)
			printf("\t--> %s + $%X\n",
				reloc.r_name == CodeSegment ? "CODE" :
				reloc.r_name == DataSegment ? "DATA" : "BSS ",
				reloc.r_offset);
		else
			printf("\t--> \"%s\" + $%X\n",
				Name(gNames, reloc.r_name), reloc.r_offset);
	}
}

/*
 * DoExports()
 */

static	void
DoExports(FILE *fp, int num)
{
	int					k, j;
	char				*name;
	struct ObjSymbol	symbol;

	for (k = 0; k < num; k++)
	{

	/* Read symbol */

		if (fread(&symbol, sizeof(symbol), 1, fp) != 1)
		{
			perror("fread");
			cerror("can't read symbol #%d", k + 1);
		}

	/* Display it */

		name = Name(gNames, symbol.s_name);
		printf("\t\"%s\"", name);
		for (j = 0; j < 14 - (int) strlen(name); j++)
			printf(" ");
		printf("%s segment, offset $%04X\n",
			symbol.s_segment == CodeSegment ? "CODE" :
			symbol.s_segment == DataSegment ? "DATA" :
			symbol.s_segment == BssSegment ? "BSS" :
			symbol.s_segment == AbsSegment ? "ABSL" : "???",
			symbol.s_offset);
	}
}

