
/*  Assembler for the HuC6280 microprocessor found in the PC Engine console.
 *  ----
 *  This program was originaly a 6502 assembler written by
 *  J. H. Van Ornum, it has been modified by David Michel
 *  to support the HuC6280.
 *
 *  This program is freeware. You are free to distribute, use and
 *  modifiy it as you wish.
 *
 *  Enjoy!
 */

#include <stdio.h>
#include <string.h>
#include "defs.h"
#include "externs.h"
#include "vars.h"

/***** DEFINES *************/

/***** GLOBALS *************/

int    infile_error;
int    infile_num;
int    switch_throwback;
char   i_file[128];
char   o_file[128];
char   l_file[128];
FILE  *iptr;
FILE  *optr;
FILE  *lptr;
struct t_input_info input_file[8];
/*----------------*/

int field[] = {
	SFIELD,
	SFIELD + 8,
	SFIELD + 14,
	SFIELD + 14,
	SFIELD + 14,
	SFIELD + 14,
/* 	SFIELD + 23, */
/* 	SFIELD + 43, */
/* 	SFIELD + 75 */
};

/***** EXTERNALS ***********/

/*
 *  main :
 *  -----
 *
 */

main(int argc, char **argv)
{
	char *p;
	int i, usage = 1;

        i_file[0] = o_file[0] = l_file[0] = 0;
        switch_throwback = 0;
        for (i = 1; i < argc && usage; i++) {
            if (!strcmp(argv[i], "-o")) strcpy(o_file, argv[++i]);
            else if (!strcmp(argv[i], "-throwback")) switch_throwback = 1;
            else if (argv[i][0] != '-') {
                if (i_file[0] == 0) strcpy(i_file, argv[i]);
                else if (l_file[0] == 0) strcpy(l_file, argv[i]);
                else usage = 0;
            }
            else usage = 0;
        }
        if (usage == 0 || o_file[0] == 0 || i_file[0] == 0) {
            fprintf(stderr, "Syntax: magicasm <source file> -o <output file> [-throwback] [<list file>]\n");
            return(1);
        }
        if (l_file[0] == 0) strcpy(l_file, "null:$.l_file");

	/* --  auto-add the file extensions. */

/*	strupr(i_file);*/

/*	if (p = strrchr(i_file, '.')) {
		if (!strchr(p, '\\'))
		   *p = '\0';
		else
			p = NULL;
	}

	strcpy(o_file, i_file);
	strcpy(l_file, i_file);
	strcat(o_file, ".PCE");
	strcat(l_file, ".LST");

	if (p)
	   *p = '.';
	else
		strcat(i_file, ".ASM");*/

	/* --  open the input file. */

	if (open_input(i_file)) {
		fprintf(stdout, "Can not open input file '%s'!\n", i_file);
		exit(1);
	}

	/* --  clear the code array. */

	memset(rom, 8192 * 128, 0);

	/* --  assemble. */

	for (i = 0; i < 256; i++) {
		hash_tbl[i] = NULL;
		macro_tbl[i] = NULL;
	}

	for (pass = FIRST_PASS; pass <= LAST_PASS; pass++) {
		infile_error = -1;
		errcnt = 0;
		page = 0;
		bank = 0;
		max_bank = 0;
		loccnt = 0;
		slnum = 0;
		mcounter = 0;
		mcntmax = 0;
		clist = 0;
		mlist = 0;
		glablptr = NULL;
		rsbase = 0;

		for (i = 0; i < 128; i++) {
			bank_offset[i] = 0;
			bank_page[i] = 0;
		}
		while (readline() != -1) {
			assemble();
			if (loccnt > 0x2000) {
				error("Out of range, bank offset > $1FFF!");
				break;
			}
		}
		if (errcnt) {
		        if (switch_throwback == 2) {
		            DDEUtils_ThrowbackEnd();
		            switch_throwback = 1;
		        }
			fprintf(stdout, "# %d ERROR(s)\n", errcnt);
			break;
		}

		rewind(iptr);

		if (pass == FIRST_PASS) {
			if (xlist) {
				if ((lptr = fopen(l_file, "w")) == NULL) {
					fprintf(stdout, "Can not open listing file '%s'!\n", l_file);
					exit(1);
				}
				fprintf(lptr, "#[1]   %s\n", input_file[1].name);
			}
		}
	}

	if (errcnt == 0) {
		if ((optr = fopen(o_file, "wb")) == NULL) {
			fprintf(stdout, "Can not open object file '%s'!\n", o_file);
			exit(1);
		}
		fwrite(rom, 8192, max_bank + 1, optr);
		fclose(optr);
	}
	if (xlist)
		fclose(lptr);
	fclose(iptr);
	return(0);
}

/*
 * readline :
 * ---------
 * reads and formats an input line.
 *
 */

readline()
{
	char *ptr, *arg, num[8];
	int j, n;
	int	i;		/* pointer into prlnbuf */
	int	c;		/* current character		*/
	int	temp;	/* temp used for line number conversion */

start:
	for (i = 0; i < LAST_CH_POS; i++)
		prlnbuf[i] = ' ';

	/*  if expand_macro get line from macro buffer */

	if (expand_macro) {
		if (mlptr == NULL) {
			while (mlptr == NULL) {
				midx--;
				mlptr = mstack[midx];
				mcounter = mcntstack[midx];
				if (midx == 0) {
					mlptr = NULL;
					expand_macro = 0;
					break;
				}
			}
		}
		if (mlptr) {
			i = SFIELD;
			ptr = mlptr->data;
			while (c = *ptr++) {
				if (c != '\\')
					prlnbuf[i++] = c;
				else {
					c = *ptr++;
					prlnbuf[i] = '\0';
					if (c == '@') {
						n = 4;
						sprintf(num, "%04i", mcounter);
						arg = num;
					}
					else if (c >= '1' && c <= '9') {
						j   = c - '1';
						n   = strlen(marg[midx][j]);
						arg = marg[midx][j];
					}
					else {
						error("Invalid macro argument index!");
						return (-1);
					}
					if ((i + n) >= LAST_CH_POS - 1) {
						error("Invalid line length!");
						return (-1);
					}
					strncpy(&prlnbuf[i], arg, n);
					i += n;
				}
				if (i >= LAST_CH_POS - 1)
					i =  LAST_CH_POS - 1;
			}
			prlnbuf[i] = '\0';
			mlptr = mlptr->next;
			return (0);
		}
	}

	/*  put source line number into prlnbuf. */

	i = 4;
	temp = ++slnum;
	while (temp != 0) {
		prlnbuf[i--] = temp % 10 + '0';
		temp /= 10;
	}
	i = SFIELD;
	while ((c = getc(iptr)) != '\n') {
		if(c == '\r')
			continue;
		prlnbuf[i++] = c;
		if (c == '\t') {
			prlnbuf[--i] = ' ';
			i += (8 - ((i - SFIELD) % 8));
		}
		else if (c == EOF) {
			if (close_input())
				return(-1);
			goto start;
		}
		if (i >= LAST_CH_POS - 1)
			i =  LAST_CH_POS - 1;
	}
	prlnbuf[i] = '\0';
	return(0);
}

/*
 * open_input :
 * -----------
 * open an input file, up to 7 levels.
 *
 */

open_input(char *name)
{
	FILE *fptr;
	char *p;
	int i;

	if (infile_num == 7) {
		error("Too many include levels!");
		return (1);
	}
	if (infile_num) {
		input_file[infile_num].lnum = slnum;
		input_file[infile_num].fptr = iptr;
	}
	strcpy(i_file, name);
/*	strupr(i_file);

	if (p = strrchr(i_file, '.')) {
		if (strchr(p, '\\'))
			strcat(i_file, ".ASM");
	} else
		strcat(i_file, ".ASM");*/
	if (infile_num) {
		for (i = 1; i < infile_num; i++) {
			if (!strcmp(input_file[i].name, i_file)) {
				error("Repeated include file!");
				return (1);
			}
		}
	}
	if ((fptr = fopen(i_file, "r")) == NULL)
		return (-1);

	iptr = fptr;
	slnum = 0;
	infile_num++;
	input_file[infile_num].fptr = fptr;
	strcpy(input_file[infile_num].name, i_file);
	if ((pass == LAST_PASS) && (xlist))
		fprintf(lptr, "#[%i]   %s\n", infile_num, input_file[infile_num].name);
	return (0);
}

/*
 * close_input :
 * ------------
 * close an input file, return -1 if no more files in the stack.
 *
 */

close_input()
{
	if (infile_num <= 1)
		return (-1);

	fclose(iptr);
	infile_num--;
	infile_error = -1;
	slnum = input_file[infile_num].lnum;
	iptr = input_file[infile_num].fptr;
	if ((pass == LAST_PASS) && (xlist))
		fprintf(lptr, "#[%i]   %s\n", infile_num, input_file[infile_num].name);
	return (0);
}

