cc65/src/grc65/main.c

1031 lines
28 KiB
C

/* GEOS resource compiler
by Maciej 'YTM/Elysium' Witkowiak
see GEOSLib documentation for license info
*/
/* - make it work, then do it better
- more or less comments? it was hard to code, should be even harder to
understand =D
- add loadable icons feature (binary - 63 bytes)
*/
/* - err, maybe free allocated memory, huh? (who cares, it's just a little prog...)
*/
#include <stdio.h>
#include <stdlib.h>
#include <stdarg.h>
#include <string.h>
#include <errno.h>
#include <time.h>
/* common stuff */
#include "abend.h"
#include "cmdline.h"
#include "fname.h"
#include "chartype.h"
#include "target.h"
#include "version.h"
#include "xmalloc.h"
/* I hope that no one will be able to create a .grc bigger than this... */
#define BLOODY_BIG_BUFFER 65000
struct menuitem {
char *name;
char *type;
char *target;
struct menuitem *next;
};
struct menu {
char *name;
int top, left;
int bot, right;
char *type;
struct menuitem *item;
};
struct appheader {
int year, month, day, hour, min;
int mode;
int dostype;
int geostype;
int structure;
char *dosname;
char *classname;
char *version;
char *author;
char *info;
char *icon;
};
const char *mainToken[] = {"MENU", "HEADER", "ICON", "DIALOG", "MEMORY", ""};
const char *toggle[] = {"off", "no", "0", "on", "yes", "1", ""};
const char *hdrFTypes[] = {"APPLICATION", "AUTO_EXEC", "DESK_ACC", "ASSEMBLY",
"DISK_DEVICE", "PRINTER", "SYSTEM", ""};
const char *hdrFields[] = {"author", "info", "date", "dostype", "mode", "structure", "icon", ""};
const char *hdrDOSTp[] = {"seq", "SEQ", "prg", "PRG", "usr", "USR", ""};
const char *hdrStructTp[] = {"seq", "SEQ", "vlir", "VLIR", ""};
const char *hdrModes[] = {"any", "40only", "80only", "c64only", ""};
const char *memFields[] = {"stacksize", "overlaysize", "overlaynums", "backbuffer", ""};
const int BSWTab[] = {0, 0x005, 0x007, 0x00b, 0x011, 0x017, 0x01d, 0x023,
0x025, 0x029, 0x02d, 0x033, 0x039, 0x03c, 0x041, 0x043, 0x04a, 0x04f,
0x052, 0x056, 0x05a, 0x05f, 0x063, 0x068, 0x06d, 0x072, 0x077, 0x079,
0x07c, 0x080, 0x084, 0x088, 0x08e, 0x094, 0x09a, 0x09f, 0x0a4, 0x0a9,
0x0ad, 0x0b1, 0x0b6, 0x0bc, 0x0be, 0x0c2, 0x0c8, 0x0cc, 0x0d4, 0x0da,
0x0e0, 0x0e5, 0x0eb, 0x0f0, 0x0f5, 0x0f9, 0x0fe, 0x104, 0x10c, 0x112,
0x118, 0x11e, 0x121, 0x129, 0x12c, 0x132, 0x13a, 0x13e, 0x143, 0x148,
0x14d, 0x152, 0x157, 0x15a, 0x15f, 0x164, 0x166, 0x168, 0x16d, 0x16f,
0x177, 0x17c, 0x182, 0x187, 0x18c, 0x18f, 0x193, 0x196, 0x19b, 0x1a1,
0x1a9, 0x1af, 0x1b4, 0x1ba, 0x1be, 0x1c0, 0x1c4, 0x1ca, 0x1d2, 0x1dd};
const unsigned char icon1[] = {255, 255, 255, 128, 0, 1, 128, 0, 1,
128, 0, 1, 128, 0, 1, 128, 0, 1,
128, 0, 1, 128, 0, 1, 128, 0, 1,
128, 0, 1, 128, 0, 1, 128, 0, 1,
128, 0, 1, 128, 0, 1, 128, 0, 1,
128, 0, 1, 128, 0, 1, 128, 0, 1,
128, 0, 1, 128, 0, 1, 255, 255, 255};
const char *outputCName = NULL;
const char *outputSName = NULL;
FILE *outputCFile, *outputSFile;
int CFnum = 0, SFnum = 0;
int apple = 0;
char outputCMode[2] = "w";
char outputSMode[2] = "w";
static void Usage (void)
{
printf (
"Usage: %s [options] file\n"
"Short options:\n"
" -V\t\t\tPrint the version number\n"
" -h\t\t\tHelp (this text)\n"
" -o name\t\tName the C output file\n"
" -s name\t\tName the asm output file\n"
" -t sys\t\tSet the target system\n"
"\n"
"Long options:\n"
" --help\t\tHelp (this text)\n"
" --target sys\t\tSet the target system\n"
" --version\t\tPrint the version number\n",
ProgName);
}
static void OptHelp (const char* Opt attribute ((unused)),
const char* Arg attribute ((unused)))
/* Print usage information and exit */
{
Usage ();
exit (EXIT_SUCCESS);
}
static void OptTarget (const char* Opt attribute ((unused)), const char* Arg)
/* Set the target system */
{
switch (FindTarget (Arg)) {
case TGT_GEOS_CBM:
apple = 0;
break;
case TGT_GEOS_APPLE:
apple = 1;
break;
case TGT_UNKNOWN:
AbEnd ("Unknown target system '%s'", Arg);
break;
default:
/* Target is known but unsupported */
AbEnd ("Unsupported target system '%s'", Arg);
break;
}
}
static void OptVersion (const char* Opt attribute ((unused)),
const char* Arg attribute ((unused)))
/* Print the program version */
{
fprintf (stderr, "%s V%s\n", ProgName, GetVersionAsString ());
exit(EXIT_SUCCESS);
}
static void printCHeader (void)
{
fprintf (outputCFile,
"//\n"
"//\tThis file was generated by the GEOS Resource Compiler\n"
"//\n"
"//\tDO NOT EDIT! Any changes will be lost!\n"
"//\n"
"//\tEdit proper resource file instead.\n"
"//\n\n");
}
static void printSHeader (void)
{
fprintf (outputSFile,
";\n"
";\tThis file was generated by the GEOS Resource Compiler\n"
";\n"
";\tDO NOT EDIT! Any changes will be lost!\n"
";\n"
";\tEdit proper resource file instead.\n"
";\n\n");
}
static void openCFile (void)
{
if ((outputCFile = fopen (outputCName,outputCMode)) == 0) {
AbEnd ("Can't open file %s for writing: %s", outputCName, strerror (errno));
}
if (CFnum == 0) {
outputCMode[0] = 'a';
printCHeader ();
CFnum++;
}
}
static void openSFile (void)
{
if ((outputSFile = fopen (outputSName, outputSMode)) == 0) {
AbEnd ("Can't open file %s for writing: %s", outputSName, strerror (errno));
}
if (SFnum == 0) {
outputSMode[0] = 'a';
printSHeader ();
SFnum++;
}
}
static int findToken (const char * const *tokenTbl, const char *token)
{
/* takes as input table of tokens and token, returns position in table or -1 if not found */
int i;
if (token != NULL) {
for (i = 0; tokenTbl[i][0]; i++) {
if (strcmp (tokenTbl[i], token) == 0) {
return i;
}
}
}
return -1;
}
static char *nextPhrase (void)
{
return strtok (NULL, "\"");
}
static char *nextWord (void)
{
return strtok (NULL, " ");
}
static void setLen (char *name, unsigned len)
{
if (strlen (name) > len) {
name[len] = '\0';
}
}
static void fillOut (char *name, int len, char *filler)
{
int a;
setLen (name, len);
fprintf (outputSFile, "\t.byte \"%s\"\n", name);
a = strlen (name);
if (a < len) {
fprintf (outputSFile, "\t.res (%i - %i), %s\n", len, a, filler);
}
}
static char *bintos (unsigned char a, char out[7])
{
int i=0;
for (; i < 8; i++) {
out[7 - i] = ((a & 1) == 0) ? '0' : '1';
a = a >> 1;
}
out[i] = '\0';
return out;
}
static int getNameSize (const char *word)
{
/* count length of a word using BSW 9 font table */
int a = 0, i = 0;
while (word[i] != '\0') {
a += (BSWTab[word[i] - 31] - BSWTab[word[i] - 32]);
i++;
}
return a;
}
static void DoMenu (void)
{
int a, size, tmpsize, item = 0;
char *token;
char namebuff[255] = "";
struct menu myMenu;
struct menuitem *curItem, *newItem;
openCFile ();
myMenu.name = nextWord ();
myMenu.left = atoi (nextWord ());
myMenu.top = atoi (nextWord ());
myMenu.type = nextWord ();
if (strcmp (nextWord (), "{") != 0) {
AbEnd ("Menu '%s' description has no opening bracket!", myMenu.name);
}
curItem = xmalloc (sizeof(struct menuitem));
myMenu.item = curItem;
for (;;) {
token = nextWord ();
if (strcmp (token, "}") == 0) break;
if (token[strlen (token) - 1] != '"') {
strcpy (namebuff, token);
do {
token = nextWord ();
strcat (namebuff, " ");
strcat (namebuff, token);
} while (token[strlen (token) - 1] != '"');
token = xmalloc (strlen (namebuff));
strcpy (token, namebuff);
}
curItem->name = token;
curItem->type = nextWord ();
curItem->target = nextWord ();
newItem = xmalloc (sizeof(struct menuitem));
curItem->next = newItem;
curItem = newItem;
item++;
}
if (item == 0) AbEnd ("Menu '%s' has 0 items!", myMenu.name);
if (item > 31) AbEnd ("Menu '%s' has too many items!", myMenu.name);
curItem->next = NULL;
/* count menu sizes */
size = 0;
curItem = myMenu.item;
if (strstr (myMenu.type, "HORIZONTAL") != NULL) {
/* menu is HORIZONTAL, ysize=15, sum xsize of all items +~8?*/
myMenu.bot = myMenu.top + 15;
for (a = 0; a != item; a++) {
size += getNameSize (curItem->name);
curItem = curItem->next;
}
} else {
/* menu is VERTICAL, ysize=item*15, count largest xsize of all items +~8? */
myMenu.bot = myMenu.top + (14 * item);
for (a = 0; a != item; a++) {
tmpsize = getNameSize (curItem->name);
size = (size > tmpsize) ? size : tmpsize;
curItem = curItem->next;
}
}
myMenu.right = myMenu.left + size - 1;
curItem = myMenu.item;
for (a = 0; a != item; a++) {
/* print prototype only if MENU_ACTION or DYN_SUB_MENU are present in type */
if ((strstr (curItem->type, "MENU_ACTION") != NULL) || (strstr (curItem->type, "DYN_SUB_MENU") != NULL)) {
fprintf (outputCFile,
"void %s (void);\n",
curItem->target);
}
curItem=curItem->next;
}
fprintf (outputCFile,
"\n"
"const void %s = {\n"
"\t(char)%i, (char)%i,\n"
"\t(int)%i, (int)%i,\n"
"\t(char)(%i | %s),\n",
myMenu.name, myMenu.top, myMenu.bot, myMenu.left, myMenu.right, item, myMenu.type);
curItem = myMenu.item;
for (a = 0; a != item; a++) {
fprintf (outputCFile,
"\t%s, (char)%s, (int)",
curItem->name, curItem->type);
if ((strstr (curItem->type, "SUB_MENU") != NULL) && (strstr (curItem->type, "DYN_SUB_MENU") == NULL)) {
fprintf (outputCFile,
"&");
}
fprintf (outputCFile,
"%s,\n",
curItem->target);
curItem = curItem->next;
}
fprintf (outputCFile,
"};\n\n");
if (fclose (outputCFile) != 0) {
AbEnd ("Error closing %s: %s", outputCName, strerror (errno));
}
}
static void DoHeader (void)
{
time_t t;
struct tm *my_tm;
struct appheader myHead;
char *token;
char i1[9], i2[9], i3[9];
int i;
openSFile ();
token = nextWord ();
i = findToken (hdrFTypes, token);
if (apple == 1) {
switch (i) {
case 0:
myHead.geostype = 0x82;
break;
default:
AbEnd ("Filetype '%s' is not supported yet", token);
}
} else {
switch (i) {
case 0:
myHead.geostype = 6;
break;
case 1:
myHead.geostype = 14;
break;
default:
AbEnd ("Filetype '%s' is not supported yet", token);
}
}
myHead.dosname = nextPhrase ();
nextPhrase ();
myHead.classname = nextPhrase ();
nextPhrase ();
myHead.version = nextPhrase ();
/* put default values into myHead here */
myHead.author = "cc65";
myHead.info = "Program compiled with cc65 and GEOSLib.";
myHead.dostype = 128;
if (apple == 0) myHead.dostype += 3;
myHead.structure = 0;
myHead.mode = 0;
myHead.icon = NULL;
t = time (NULL);
my_tm = localtime (&t);
myHead.year = my_tm->tm_year % 100;
myHead.month = my_tm->tm_mon + 1;
myHead.day = my_tm->tm_mday;
myHead.hour = my_tm->tm_hour;
myHead.min = my_tm->tm_min;
if (strcmp (nextWord (), "{") != 0) {
AbEnd ("Header '%s' has no opening bracket!", myHead.dosname);
}
for (;;) {
token = nextWord ();
if (strcmp (token, "}") == 0) break;
switch (findToken (hdrFields, token)) {
case -1:
AbEnd ("Unknown field '%s' in header '%s'", token, myHead.dosname);
break;
case 0: /* author */
myHead.author = nextPhrase ();
break;
case 1: /* info */
myHead.info = nextPhrase ();
break;
case 2: /* date */
myHead.year = atoi (nextWord ());
myHead.month = atoi (nextWord ());
myHead.day = atoi (nextWord ());
myHead.hour = atoi (nextWord ());
myHead.min = atoi (nextWord ());
break;
case 3: /* dostype */
switch (i = findToken (hdrDOSTp, nextWord ())) {
case -1:
AbEnd ("Unknown dostype in header '%s'", myHead.dosname);
break;
default:
if (apple == 0) myHead.dostype = i / 2 + 128 + 1;
break;
}
break;
case 4: /* mode */
switch (findToken (hdrModes, nextWord ())) {
case -1:
AbEnd ("Unknown mode in header '%s'", myHead.dosname);
case 0:
if (apple == 0) myHead.mode = 0x40;
break;
case 1:
if (apple == 0) myHead.mode = 0x00;
break;
case 2:
if (apple == 0) myHead.mode = 0xc0;
break;
case 3:
if (apple == 0) myHead.mode = 0x80;
break;
}
break;
case 5: /* structure */
switch (findToken (hdrStructTp, nextWord ())) {
case -1:
AbEnd ("unknown structure type in header '%s'", myHead.dosname);
case 0:
case 1:
myHead.structure = 0;
break;
case 2:
case 3:
myHead.structure = 1;
break;
}
break;
case 6: /* icon */
myHead.icon = nextPhrase ();
break;
}
}
/* OK, all information is gathered, do flushout */
fprintf (outputSFile,
"\t\t.segment \"DIRENTRY\"\n\n");
if (apple == 1) {
if (myHead.structure == 0) {
fprintf (outputSFile,
"\t.import __VLIR0_START__, __VLIR0_LAST__, __BSS_SIZE__\n\n");
}
fprintf (outputSFile,
"\t.byte %i << 4 | %u\n",
myHead.structure + 2, (unsigned)strlen (myHead.dosname));
fillOut (myHead.dosname, 15, "0");
fprintf (outputSFile,
"\t.byte $%02x\n"
"\t.word 0\n"
"\t.word 0\n"
"\t.word %s\n"
"\t.byte 0\n"
"\t.word %i << 9 | %i << 5 | %i, %i << 8 | %i\n"
"\t.byte 0\n"
"\t.byte 0\n"
"\t.byte 0\n"
"\t.word 0\n"
"\t.word %i << 9 | %i << 5 | %i, %i << 8 | %i\n"
"\t.word 0\n\n",
myHead.geostype,
myHead.structure == 0 ?
"__VLIR0_LAST__ - __VLIR0_START__ - __BSS_SIZE__" : "0",
myHead.year, myHead.month, myHead.day, myHead.hour, myHead.min,
myHead.year, myHead.month, myHead.day, myHead.hour, myHead.min);
} else {
fprintf (outputSFile,
"\t.byte %i\n"
"\t.word 0\n",
myHead.dostype);
fillOut (myHead.dosname, 16, "$a0");
fprintf (outputSFile,
"\t.word 0\n"
"\t.byte %i\n"
"\t.byte %i\n"
"\t.byte %i, %i, %i, %i, %i\n\n"
"\t.word 0\n"
"\t.byte \"PRG formatted GEOS file V1.0\"\n\n",
myHead.structure, myHead.geostype,
myHead.year, myHead.month, myHead.day, myHead.hour, myHead.min);
}
fprintf (outputSFile,
"\t\t.segment \"FILEINFO\"\n\n"
"\t.import __VLIR0_START__, __STARTUP_RUN__\n\n"
"\t.byte 3, 21, 63 | $80\n");
if (myHead.icon != NULL) {
fprintf (outputSFile,
"\t.incbin \"%s\", 0, 63\n",
myHead.icon);
} else {
for (i = 0; i != 63; i = i + 3) {
fprintf (outputSFile,
"\t.byte %%%s, %%%s, %%%s\n",
bintos (icon1[i], i1), bintos (icon1[i+1], i2), bintos (icon1[i+2], i3));
}
}
fprintf (outputSFile,
"\t.byte %i, %i, %i\n"
"\t.word __VLIR0_START__, __VLIR0_START__ - 1, __STARTUP_RUN__\n\n",
myHead.dostype, myHead.geostype, myHead.structure);
fillOut (myHead.classname, 12, "$20");
fillOut (myHead.version, 4, "0");
fprintf (outputSFile,
"\t.byte 0, 0, 0\n"
"\t.byte %i\n\n",
myHead.mode);
setLen (myHead.author, 62);
fprintf (outputSFile,
"\t.byte \"%s\"\n"
"\t.byte 0\n"
"\t.res (63 - %i)\n\n",
myHead.author, (int)(strlen (myHead.author) + 1));
setLen (myHead.info, 95);
fprintf (outputSFile,
"\t.byte \"%s\"\n"
"\t.byte 0\n\n",
myHead.info);
if (fclose (outputSFile) != 0) {
AbEnd ("Error closing %s: %s", outputSName, strerror (errno));
}
}
static void DoMemory (void)
{
char *token;
int stacksize, overlaysize;
int overlaytable[127];
int number, lastnumber;
int backbuffer;
openSFile ();
stacksize = -1;
overlaysize = -1;
memset (overlaytable, 0, sizeof (overlaytable));
lastnumber = -1;
backbuffer = -1;
if (strcmp (nextWord (), "{") != 0) {
AbEnd ("MEMORY description has no opening bracket!");
}
token = NULL;
for (;;) {
if (token == NULL) token = nextWord ();
if (strcmp (token, "}") == 0) break;
switch (findToken (memFields, token)) {
case -1:
AbEnd ("Unknown field '%s' in MEMORY description", token);
break;
case 0: /* stacksize */
stacksize = strtol (nextWord (), NULL, 0);
token = NULL;
break;
case 1: /* overlaysize */
overlaysize = strtol (nextWord (), NULL, 0);
token = NULL;
break;
case 2: /* overlaynums */
do {
token = nextWord ();
if (IsDigit (token[0]) == 0) break;
number = atoi (token);
if (number < 0 || number > 126) {
AbEnd ("Overlay number %i is out of range 0-126", number);
}
if (overlaytable[number] == 1) {
AbEnd ("Overlay number %i is defined twice", number);
}
overlaytable[number] = 1;
if (number > lastnumber) lastnumber = number;
} while (IsDigit (token[0]) != 0);
if (lastnumber == -1) {
AbEnd ("There must be at least one overlay number");
}
/* always include number 0 */
overlaytable[0] = 1;
break;
case 3: /* backbuffer */
switch (findToken (toggle, nextWord ())) {
case -1:
AbEnd ("Unknown value for 'backbuffer'");
break;
case 0:
case 1:
case 2:
backbuffer = 0;
break;
default:
backbuffer = 1;
break;
}
token = NULL;
break;
}
}
/* OK, all information is gathered, do flushout */
if (lastnumber != -1) {
fprintf (outputSFile,
"\t\t.segment \"RECORDS\"\n\n");
if (apple == 1) {
for (number = 0; number <= lastnumber; number++) {
fprintf (outputSFile,
"\t.byte %s\n",
overlaytable[number] == 1 ? "$00" : "$FF");
}
fprintf (outputSFile,
"\n");
for (number = 0; number <= lastnumber; number++) {
if (overlaytable[number] == 1) {
fprintf (outputSFile,
"\t\t.segment \"VLIRIDX%i\"\n\n"
"\t.import __VLIR%i_START__, __VLIR%i_LAST__%s\n\n"
"\t.res 255\n"
"\t.byte .lobyte (__VLIR%i_LAST__ - __VLIR%i_START__%s)\n"
"\t.res 255\n"
"\t.byte .hibyte (__VLIR%i_LAST__ - __VLIR%i_START__%s)\n\n",
number, number, number,
number == 0 ? ", __BSS_SIZE__" : "",
number, number,
number == 0 ? " - __BSS_SIZE__" : "",
number, number,
number == 0 ? " - __BSS_SIZE__" : "");
}
}
} else {
for (number = 0; number <= lastnumber; number++) {
if (overlaytable[number] == 1) {
fprintf (outputSFile,
"\t.import __VLIR%i_START__, __VLIR%i_LAST__%s\n",
number, number, number == 0 ? ", __BSS_SIZE__" : "");
}
}
fprintf (outputSFile,
"\n");
for (number = 0; number <= lastnumber; number++) {
if (overlaytable[number] == 1) {
fprintf (outputSFile,
"\t.byte .lobyte ((__VLIR%i_LAST__ - __VLIR%i_START__%s - 1) / 254) + 1\n"
"\t.byte .lobyte ((__VLIR%i_LAST__ - __VLIR%i_START__%s - 1) .MOD 254) + 2\n",
number, number, number == 0 ? " - __BSS_SIZE__" : "",
number, number, number == 0 ? " - __BSS_SIZE__" : "");
} else {
fprintf (outputSFile,
"\t.byte $00\n"
"\t.byte $FF\n");
}
}
fprintf (outputSFile,
"\n");
}
openCFile ();
fprintf (outputCFile,
"extern void _OVERLAYADDR__[];\n"
"extern void _OVERLAYSIZE__[];\n\n"
"#define OVERLAY_ADDR (char*) _OVERLAYADDR__\n"
"#define OVERLAY_SIZE (unsigned)_OVERLAYSIZE__\n\n");
if (fclose (outputCFile) != 0) {
AbEnd ("Error closing %s: %s", outputCName, strerror (errno));
}
}
if (stacksize != -1) {
fprintf (outputSFile,
"\t.export __STACKSIZE__ : absolute = $%04x\n\n",
stacksize);
}
if (overlaysize != -1) {
fprintf (outputSFile,
"\t.export __OVERLAYSIZE__ : absolute = $%04x\n\n",
overlaysize);
}
if (backbuffer != -1) {
fprintf (outputSFile,
"\t.export __BACKBUFSIZE__ : absolute = $%04x\n\n",
backbuffer ? 0x2000 : 0x0000);
}
if (fclose (outputSFile) != 0) {
AbEnd ("Error closing %s: %s", outputSName, strerror (errno));
}
}
static char *filterInput (FILE *F, char *tbl)
{
/* loads file into buffer filtering it out */
int a, prevchar = -1, i = 0, bracket = 0, quote = 1;
a = getc(F);
while (1) {
if (i >= BLOODY_BIG_BUFFER) {
AbEnd ("File too large for internal parsing buffer (%d bytes)",BLOODY_BIG_BUFFER);
}
if (((a == '\n') || (a == '\015')) ||
(a == ',' && quote)) {
a = ' ';
}
if (a == '\042') {
quote =! quote;
}
if (quote) {
if ((a == '{') || (a == '(')) {
bracket++;
}
if ((a == '}') || (a == ')')) {
bracket--;
}
}
if (a == EOF) {
tbl[i] = '\0';
tbl = xrealloc (tbl, i + 1);
break;
}
if (IsSpace (a)) {
if ((prevchar != ' ') && (prevchar != -1)) {
tbl[i++] = ' ';
prevchar = ' ';
}
} else {
if (a == ';' && quote) {
do {
a = getc (F);
} while (a != '\n' && a != EOF);
/* Don't discard this newline/EOF, continue to next loop.
** A previous implementation used fseek(F,-1,SEEK_CUR),
** which is invalid for text mode files, and was unreliable across platforms.
*/
continue;
} else {
tbl[i++] = a;
prevchar = a;
}
}
a = getc(F);
}
if (bracket != 0) AbEnd ("There are unclosed brackets!");
return tbl;
}
static void processFile (const char *filename)
{
FILE *F;
char *str;
char *token;
int head = 0; /* number of processed HEADER sections */
int memory = 0; /* number of processed MEMORY sections */
if ((F = fopen (filename, "r")) == 0) {
AbEnd ("Can't open file %s for reading: %s", filename, strerror (errno));
}
str = filterInput (F, xmalloc (BLOODY_BIG_BUFFER));
token = strtok (str, " ");
do {
if (str != NULL) {
switch (findToken (mainToken, token)) {
case 0:
DoMenu ();
break;
case 1:
if (++head != 1) {
AbEnd ("More than one HEADER section, aborting");
} else {
DoHeader ();
}
break;
case 2: break; /* icon not implemented yet */
case 3: break; /* dialog not implemented yet */
case 4:
if (++memory != 1) {
AbEnd ("More than one MEMORY section, aborting");
} else {
DoMemory ();
}
break;
default:
AbEnd ("Unknown section '%s'", token);
break;
}
}
token = nextWord ();
} while (token != NULL);
}
int main (int argc, char *argv[])
{
/* Program long options */
static const LongOpt OptTab[] = {
{ "--help", 0, OptHelp},
{ "--target", 1, OptTarget},
{ "--version", 0, OptVersion},
};
unsigned ffile = 0;
unsigned I;
/* Initialize the cmdline module */
InitCmdLine (&argc, &argv, "grc65");
/* Check the parameters */
I = 1;
while (I < ArgCount) {
/* Get the argument */
const char* Arg = ArgVec [I];
/* Check for an option */
if (Arg[0] == '-') {
switch (Arg[1]) {
case '-':
LongOption (&I, OptTab, sizeof(OptTab)/sizeof(OptTab[0]));
break;
case 'o':
outputCName = GetArg (&I, 2);
break;
case 's':
outputSName = GetArg (&I, 2);
break;
case 't':
OptTarget (Arg, GetArg (&I, 2));
break;
case 'h':
case '?':
OptHelp (Arg, 0);
break;
case 'V':
OptVersion (Arg, 0);
break;
default:
UnknownOption (Arg);
}
} else {
ffile++;
if (outputCName == NULL) outputCName = MakeFilename (Arg, ".h");
if (outputSName == NULL) outputSName = MakeFilename (Arg, ".s");
processFile (Arg);
}
/* Next argument */
++I;
}
if (ffile == 0) AbEnd ("No input file");
return EXIT_SUCCESS;
}