shithub: rgbds

ref: ac5b311005c582f447cf073b9182a7f86110ef61
dir: /src/link/main.c/

View raw version
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#include "asmotor.h"

#include "link/object.h"
#include "link/output.h"
#include "link/assign.h"
#include "link/patch.h"
#include "link/mylink.h"
#include "link/mapfile.h"
#include "link/main.h"
#include "link/library.h"

// Quick and dirty...but it works
#ifdef __GNUC__
#define strcmpi	strcasecmp
#endif

enum eBlockType {
	BLOCK_COMMENT,
	BLOCK_OBJECTS,
	BLOCK_LIBRARIES,
	BLOCK_OUTPUT
};

SLONG options = 0;
SLONG fillchar = 0;
enum eOutputType outputtype = OUTPUT_GBROM;
char temptext[1024];
char smartlinkstartsymbol[256];

/*
 * Print out an errormessage
 *
 */

void 
fatalerror(char *s)
{
	printf("*ERROR* : %s\n", s);
	exit(5);
}
/*
 * Print the usagescreen
 *
 */

void 
PrintUsage(void)
{
	printf("xLink v" LINK_VERSION " (part of ASMotor " ASMOTOR_VERSION
	    ")\n\n" "Usage: xlink [options] linkfile\n"
	    "Options:\n\t-h\t\tThis text\n"
	    "\t-m<mapfile>\tWrite a mapfile\n"
	    "\t-n<symfile>\tWrite a NO$GMB compatible symfile\n"
	    "\t-z<hx>\t\tSet the byte value (hex format) used for uninitialised\n"
	    "\t\t\tdata (? for random, default is 0x00)\n"
	    "\t-s<symbol>\tPerform smart linking starting with <symbol>\n"
	    "\t-t\t\tOutput target\n" "\t\t-tg\tGameboy ROM image(default)\n"
	    "\t\t-ts\tGameboy small mode (32kB)\n"
	    "\t\t-tp\tPsion2 reloc module\n");
	exit(0);
}
/*
 * Parse the linkfile and load all the objectfiles
 *
 */

void 
ProcessLinkfile(char *tzLinkfile)
{
	FILE *pLinkfile;
	enum eBlockType CurrentBlock = BLOCK_COMMENT;

	pLinkfile = fopen(tzLinkfile, "rt");
	if (!pLinkfile) {
		sprintf(temptext, "Unable to find linkfile '%s'\n", tzLinkfile);
		fatalerror(temptext);
	}
	while (!feof(pLinkfile)) {
		char tzLine[256];

		fscanf(pLinkfile, "%s\n", tzLine);
		if (tzLine[0] != '#') {
			if (tzLine[0] == '['
			    && tzLine[strlen(tzLine) - 1] == ']') {
				if (strcmpi("[objects]", tzLine) == 0)
					CurrentBlock = BLOCK_OBJECTS;
				else if (strcmpi("[output]", tzLine) ==
				    0)
					CurrentBlock = BLOCK_OUTPUT;
				else if (strcmpi("[libraries]", tzLine)
				    == 0)
					CurrentBlock = BLOCK_LIBRARIES;
				else if (strcmpi("[comment]", tzLine) ==
				    0)
					CurrentBlock = BLOCK_COMMENT;
				else {
					fclose(pLinkfile);
					sprintf(temptext,
					    "Unknown block '%s'\n",
					    tzLine);
					fatalerror(temptext);
				}
			} else {
				switch (CurrentBlock) {
				case BLOCK_COMMENT:
					break;
				case BLOCK_OBJECTS:
					obj_Readfile(tzLine);
					break;
				case BLOCK_LIBRARIES:
					lib_Readfile(tzLine);
					break;
				case BLOCK_OUTPUT:
					out_Setname(tzLine);
					break;
				}
			}
		}
	}

	fclose(pLinkfile);
}
/*
 * The main routine
 *
 */

int 
main(int argc, char *argv[])
{
	SLONG argn = 0;

	argc -= 1;
	argn += 1;

	if (argc == 0)
		PrintUsage();

	while (*argv[argn] == '-') {
		char opt;
		argc -= 1;
		switch (opt = argv[argn++][1]) {
		case '?':
		case 'h':
			PrintUsage();
			break;
		case 'm':
			SetMapfileName(argv[argn - 1] + 2);
			break;
		case 'n':
			SetSymfileName(argv[argn - 1] + 2);
			break;
		case 't':
			switch (opt = argv[argn - 1][2]) {
			case 'g':
				outputtype = OUTPUT_GBROM;
				break;
			case 's':
				outputtype = OUTPUT_GBROM;
				options |= OPT_SMALL;
				break;
			case 'p':
				outputtype = OUTPUT_PSION2;
				break;
			default:
				sprintf(temptext, "Unknown option 't%c'\n",
				    opt);
				fatalerror(temptext);
				break;
			}
			break;
		case 'z':
			if (strlen(argv[argn - 1] + 2) <= 2) {
				if (strcmp(argv[argn - 1] + 2, "?") == 0) {
					fillchar = -1;
				} else {
					int result;

					result =
					    sscanf(argv[argn - 1] + 2, "%lx",
					    &fillchar);
					if (!((result == EOF) || (result == 1))) {
						fatalerror
						    ("Invalid argument for option 'z'\n");
					}
				}
			} else {
				fatalerror("Invalid argument for option 'z'\n");
			}
			break;
		case 's':
			options |= OPT_SMART_C_LINK;
			strcpy(smartlinkstartsymbol, argv[argn - 1] + 2);
			break;
		default:
			sprintf(temptext, "Unknown option '%c'\n", opt);
			fatalerror(temptext);
			break;
		}
	}

	if (argc == 1) {
		ProcessLinkfile(argv[argn++]);
		AddNeededModules();
		AssignSections();
		CreateSymbolTable();
		Patch();
		Output();
		CloseMapfile();
	} else
		PrintUsage();

	return (0);
}