
/*
 * main.c
 *
 * Apple 2 assembler
 * Copyright (C) 1995 by Archie L. Cobbs
 *
 */

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

/*
 * DEFINITIONS
 */

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

/*
 * GLOBAL VARIABLES
 */

	char			*gProgName = "a2asm";
	char			*gUsageMsg = "[-65[c]02] [-l] [-o outfile] file ...";

	int				g65c02 = DEFAULT_65C02;
	int				gDebug = FALSE;
	int				gVerbose = FALSE;

	FILE			*gListFile = NULL;
	int				gLocLabel = FALSE;

	int				gHiBit;
	int				gExpand;
	int				gAssembleOn;

	int				gPass;
	int				gLineNumber;
	struct SegRel	gSegrel;
	int				gListBytes;
	char			gLineBuf[MAX_LISTING_LINE];

	char			*gFileName;
	FILE			*gInFile;
	FILE			*gInFileList;

	Names			gNames;
	Names			gObjNames;

	int				gSegment;
	unsigned		gAddress[NUM_SEGMENTS];
	unsigned		gMaxAddress[NUM_SEGMENTS];
	Byte			*gSegBuffer[NUM_SEGMENTS];

/*
 * INTERNAL FUNCTIONS
 */

	static void	DoPass(FILE *fp, int pass);

/*
 * main()
 */

int
main(int ac, char *av[])
{
	char	*outfilename = NULL;
	FILE	*fpout;

/* Get command line paramters	*/

	while (nextArg && *currArg == '-')
		if (!strcmp(currArg, "-65c02"))
			g65c02 = TRUE;
		else if (!strcmp(currArg, "-6502"))
			g65c02 = FALSE;
		else if (!strcmp(currArg, "-l"))
			gListFile = stdout;
		else if (!strcmp(currArg, "-v"))
			gVerbose = TRUE;
		else if (!strcmp(currArg, "-d"))
			gDebug = TRUE;
		else if (!strcmp(currArg, "-o"))
		{
			if (!nextArg)
				Usage("missing output filename parameter");
			outfilename = currArg;
		}
		else
			Usage(NULL);

/* Get file name */

	if (!currArg)
		Usage("no input file specified");
	gFileName = currArg;
	if (nextArg)
		Usage("too many arguments");

/* Open input file */

	if ((gInFile = fopen(gFileName, "r")) == NULL)
	{
		perror("fopen");
		Panic("can't open input file \"%s\"", gFileName);
	}
	if (!outfilename)
	{
		int		len;

		if ((len = strlen(gFileName)) >= 2
				&& gFileName[len - 2] == '.'
				&& (gFileName[len - 1] == 's'
				 || gFileName[len - 1] == 'S'))
		{
			strcpy(outfilename = GetMem(len + 1), gFileName);
			outfilename[len - 1] = 'o';
		}
		else
			outfilename = DEFAULT_OUTFILE;
	}

/* Create names databases */

	gNames = NewNames(MAX_SYMBOL_CHARS);
	gObjNames = NewNames(MAX_SYMBOL_CHARS);

/* Install Opcodes */

	OpcodeInit();

/* Do first pass */

	DoPass(gInFile, 1);

	if (gDebug)
	{
		SymDump(stderr);
		fprintf(stderr, "CODE: $%04X\nDATA: $%04X\nBSS:  $%04X\n",
			gMaxAddress[CodeSegment],
			gMaxAddress[DataSegment],
			gMaxAddress[BssSegment]);
	}

/* Abort if any errors */

	if (gNumErrors)
		return(gNumErrors);

/* Allocate code and data segment memory */

	gSegBuffer[CodeSegment] = GetMem(gMaxAddress[CodeSegment]);
	gSegBuffer[DataSegment] = GetMem(gMaxAddress[DataSegment]);

/* Do second pass */

	DoPass(gInFile, 2);

/* Halt now if any errors */

	if (gNumErrors)
		return(gNumErrors);

/* Write object file */

	if (gVerbose)
		fprintf(stderr, "*** Writing file \"%s\"...\n", outfilename);

	if ((fpout = fopen(outfilename, "w")) == NULL)
	{
		perror("fopen");
		Panic("can't open output file \"%s\"", outfilename);
	}
	WriteObj(fpout);
	fclose(fpout);

/* Done */

	return(0);
}

/*
 * DoPass()
 */

static	void
DoPass(FILE *fp, int pass)
{

/* Set pass number */

	gPass = pass;

/* Restart the input */

	rewind(fp);
	yyrestart(fp);

/* Reset variables to initial state */

	gAddress[CodeSegment] = 0;
	gAddress[DataSegment] = 0;
	gAddress[BssSegment] = 0;

	gSegment = INITIAL_SEGMENT;

	gLineNumber = 1;
	gSegrel.segment = -1;
	gListBytes = FALSE;

/* Open second descriptor on input for listing during pass 2 */

	if (gListFile && gPass == 2)
	{
		if ((gInFileList = fdopen(fileno(fp), "r")) == NULL)
		{
			perror("fdopen");
			cerror("can't fdopen input file");
		}
		rewind(gInFileList);
	}

/* Read input */

	if (gVerbose)
		fprintf(stderr, "*** PASS %d ***\n", gPass);

	yyparse();

/* Segments always even multiple of four bytes */

	gAddress[CodeSegment] = RoundUp(gAddress[CodeSegment], 4);
	gAddress[DataSegment] = RoundUp(gAddress[DataSegment], 4);
	gAddress[BssSegment] = RoundUp(gAddress[BssSegment], 4);

	gMaxAddress[CodeSegment] = RoundUp(gMaxAddress[CodeSegment], 4);
	gMaxAddress[DataSegment] = RoundUp(gMaxAddress[DataSegment], 4);
	gMaxAddress[BssSegment] = RoundUp(gMaxAddress[BssSegment], 4);
}

