Files
rgbds/src/link/main.c

192 lines
3.7 KiB
C

#include <err.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.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 smartlinkstartsymbol[256];
/*
* 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) {
errx(5, "Unable to find linkfile '%s'", tzLinkfile);
}
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);
errx(5,
"Unknown block '%s'",
tzLine);
}
} 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[])
{
int ch;
char *ep;
SLONG argn = 0;
if (argc == 1)
PrintUsage();
while ((ch = getopt(argc, argv, "m:n:s:t:z:")) != -1) {
switch (ch) {
case 'm':
SetMapfileName(optarg);
break;
case 'n':
SetSymfileName(optarg);
break;
case 's':
options |= OPT_SMART_C_LINK;
strcpy(smartlinkstartsymbol, optarg);
break;
case 't':
switch (optarg[0]) {
case 'g':
outputtype = OUTPUT_GBROM;
break;
case 's':
outputtype = OUTPUT_GBROM;
options |= OPT_SMALL;
break;
case 'p':
outputtype = OUTPUT_PSION2;
break;
default:
errx(5, "Invalid argument to option t");
break;
}
break;
case 'z':
if (optarg[0] == '?')
fillchar = -1;
else {
fillchar = strtoul(optarg, &ep, 0);
if (optarg[0] == '\0' || *ep != '\0')
errx(5, "Invalid argument for option 'z'");
if (fillchar < 0 || fillchar > 0xFF)
errx(5, "Argument for option 'z' must be between 0 and 0xFF");
}
break;
default:
PrintUsage();
/* NOTREACHED */
}
}
argc -= optind;
argv += optind;
if (argc == 1) {
ProcessLinkfile(argv[argc - 1]);
AddNeededModules();
AssignSections();
CreateSymbolTable();
Patch();
Output();
CloseMapfile();
} else
PrintUsage();
return (0);
}