]> git.sur5r.net Git - cc65/blob - src/grc65/grc65.c
First steps towards supporting Apple GEOS.
[cc65] / src / grc65 / grc65.c
1 /* GEOS resource compiler
2
3    by Maciej 'YTM/Elysium' Witkowiak
4
5    see GEOSLib documentation for license info
6 */
7
8 /* - make it work, then do it better
9    - more or less comments? it was hard to code, should be even harder to
10      understand =D
11    - add loadable icons feature (binary - 63 bytes)
12 */
13
14 /* - err, maybe free allocated memory, huh? (who cares, it's just a little prog...)
15 */
16
17 #include <stdio.h>
18 #include <stdlib.h>
19 #include <stdarg.h>
20 #include <string.h>
21 #include <errno.h>
22 #include <time.h>
23
24 /* common stuff */
25 #include "fname.h"
26 #include "abend.h"
27 #include "chartype.h"
28 #include "target.h"
29 #include "xmalloc.h"
30
31 /* I hope that no one will be able to create a .grc bigger than this... */
32 #define BLOODY_BIG_BUFFER 65000
33
34 /* there are no 6MB GEOS binaries... I hope! */
35 #define THIS_BUFFER_IS_SOOO_HUGE 6000000
36
37
38 struct menuitem {
39     char *name;
40     char *type;
41     char *target;
42     struct menuitem *next;
43 };
44
45 struct menu {
46     char *name;
47     int top, left;
48     int bot, right;
49     char *type;
50     struct menuitem *item;
51 };
52
53 struct appheader {
54     int year, month, day, hour, min;
55     int mode;
56     int dostype;
57     int geostype;
58     int structure;
59     char *dosname;
60     char *classname;
61     char *version;
62     char *author;
63     char *info;
64     char *icon;
65 };
66
67 const char *mainToken[] = {"MENU", "HEADER", "ICON", "DIALOG", "VLIR", ""};
68
69 const char *hdrFTypes[] = {"APPLICATION", "AUTO_EXEC", "DESK_ACC", "ASSEMBLY",
70                            "DISK_DEVICE", "PRINTER", "SYSTEM", ""};
71
72 const char *hdrFields[] = {"author", "info", "date", "dostype", "mode", "structure", "icon", ""};
73
74 const char *hdrDOSTp[] = {"seq", "SEQ", "prg", "PRG", "usr", "USR", ""};
75
76 const char *hdrStructTp[] = {"seq", "SEQ", "vlir", "VLIR", ""};
77
78 const char *hdrModes[] = {"any", "40only", "80only", "c64only", ""};
79
80 const int BSWTab[] = {0, 0x005, 0x007, 0x00b, 0x011, 0x017, 0x01d, 0x023,
81     0x025, 0x029, 0x02d, 0x033, 0x039, 0x03c, 0x041, 0x043, 0x04a, 0x04f,
82     0x052, 0x056, 0x05a, 0x05f, 0x063, 0x068, 0x06d, 0x072, 0x077, 0x079,
83     0x07c, 0x080, 0x084, 0x088, 0x08e, 0x094, 0x09a, 0x09f, 0x0a4, 0x0a9,
84     0x0ad, 0x0b1, 0x0b6, 0x0bc, 0x0be, 0x0c2, 0x0c8, 0x0cc, 0x0d4, 0x0da,
85     0x0e0, 0x0e5, 0x0eb, 0x0f0, 0x0f5, 0x0f9, 0x0fe, 0x104, 0x10c, 0x112,
86     0x118, 0x11e, 0x121, 0x129, 0x12c, 0x132, 0x13a, 0x13e, 0x143, 0x148,
87     0x14d, 0x152, 0x157, 0x15a, 0x15f, 0x164, 0x166, 0x168, 0x16d, 0x16f,
88     0x177, 0x17c, 0x182, 0x187, 0x18c, 0x18f, 0x193, 0x196, 0x19b, 0x1a1,
89     0x1a9, 0x1af, 0x1b4, 0x1ba, 0x1be, 0x1c0, 0x1c4, 0x1ca, 0x1d2, 0x1dd};
90
91 const unsigned char icon1[] = {255, 255, 255, 128,   0,   1, 128,   0,   1,
92                                128,   0,   1, 128,   0,   1, 128,   0,   1,
93                                128,   0,   1, 128,   0,   1, 128,   0,   1,
94                                128,   0,   1, 128,   0,   1, 128,   0,   1,
95                                128,   0,   1, 128,   0,   1, 128,   0,   1,
96                                128,   0,   1, 128,   0,   1, 128,   0,   1,
97                                128,   0,   1, 128,   0,   1, 255, 255, 255};
98
99 char *ProgName; /* for AbEnd, later remove and use common/cmdline.h */
100
101 char *outputCName = NULL, *outputSName = NULL;
102 FILE *outputCFile, *outputSFile;
103 int CFnum = 0, SFnum = 0;
104 int apple = 0;
105 char outputCMode[2] = "w";
106 char outputSMode[2] = "w";
107
108
109 void printUsage(void) {
110
111     printf("Usage: %s [options] file\n"
112            "Options:\n"
113            "\t-h, -?\t\tthis help\n"
114            "\t-o name\t\tname C output file\n"
115            "\t-s name\t\tname asm output file\n"
116            "\t-t sys\t\tset target system\n",
117            ProgName);
118 }
119
120
121 void printCHeader(void) {
122
123     fprintf(outputCFile,
124         "//\n"
125         "//\tThis file was generated by the GEOS Resource Compiler\n"
126         "//\n"
127         "//\tDO NOT EDIT! Any changes will be lost!\n"
128         "//\n"
129         "//\tEdit proper resource file instead.\n"
130         "//\n\n");
131 }
132
133
134 void printSHeader(void) {
135
136     fprintf(outputSFile,
137         ";\n"
138         ";\tThis file was generated by the GEOS Resource Compiler\n"
139         ";\n"
140         ";\tDO NOT EDIT! Any changes will be lost!\n"
141         ";\n"
142         ";\tEdit proper resource file instead.\n"
143         ";\n\n");
144 }
145
146
147 void openCFile(void) {
148
149     if ((outputCFile = fopen(outputCName,outputCMode)) == 0) {
150         AbEnd("can't open file %s for writing: %s\n", outputCName, strerror(errno));
151     }
152
153     if (CFnum == 0) {
154         outputCMode[0] = 'a';
155         printCHeader();
156         CFnum++;
157     }
158 }
159
160
161 void openSFile(void) {
162
163     if ((outputSFile = fopen(outputSName, outputSMode)) == 0) {
164         AbEnd("can't open file %s for writing: %s\n", outputSName, strerror(errno));
165     }
166
167     if (SFnum == 0) {
168         outputSMode[0] = 'a';
169         printSHeader();
170         SFnum++;
171     }
172 }
173
174
175 int findToken(const char **tokenTbl, const char *token) {
176
177     /* takes as input table of tokens and token, returns position in table or -1 if not found */
178     int a = 0;
179
180     while (strlen(tokenTbl[a]) != 0) {
181         if (strcmp(tokenTbl[a], token) == 0) break;
182         a++;
183     }
184
185     if (strlen(tokenTbl[a]) == 0) a = -1;
186     return a;
187 }
188
189
190 char *nextPhrase() {
191     return strtok(NULL, "\"");
192 }
193
194
195 char *nextWord() {
196     return strtok(NULL, " ");
197 }
198
199
200 void setLen(char *name, unsigned len) {
201     if (strlen(name) > len)
202         name[len] = '\0';
203 }
204
205
206 void fillOut(char *name, int len, char *filler) {
207
208     int a;
209
210     setLen(name, len);
211     fprintf(outputSFile, "\t.byte \"%s\"\n", name);
212     
213     a = strlen(name);
214     if (a < len) {
215         fprintf(outputSFile, "\t.res  (%i - %i), %s\n", len, a, filler);
216     }
217 }
218
219
220 char *bintos(unsigned char a, char out[7]) {
221
222     int i=0;
223
224     for (; i < 8; i++) {
225         out[7 - i] = ((a & 1) == 0) ? '0' : '1';
226         a = a >> 1;
227     }
228     out[i] = '\0';
229
230     return out;
231 }
232
233
234 int getNameSize(const char *word) {
235
236     /* count length of a word using BSW 9 font table */
237     int a = 0, i = 0;
238
239     while (word[i] != '\0') {
240         a += (BSWTab[word[i] - 31] - BSWTab[word[i] - 32]);
241         i++;
242     }
243
244     return a;
245 }
246
247
248 void DoMenu(void) {
249
250     int a, size, tmpsize, item = 0;
251     char *token;
252     char namebuff[255] = "";
253     struct menu myMenu;
254     struct menuitem *curItem, *newItem;
255
256     openCFile();
257
258     myMenu.name = nextWord();
259     myMenu.left = atoi(nextWord());
260     myMenu.top = atoi(nextWord());
261     myMenu.type = nextWord();
262
263     if (strcmp(nextWord(), "{") != 0) {
264         AbEnd("menu '%s' description has no opening bracket!\n", myMenu.name);
265     }
266     curItem = xmalloc(sizeof(struct menuitem));
267     myMenu.item = curItem;
268     do {
269         token = nextWord();
270         if (strcmp(token, "}") == 0) break;
271         if (token[strlen(token) - 1] != '"') {
272             strcpy(namebuff, token);
273             do {
274                 token = nextWord();
275                 strcat(namebuff, " ");
276                 strcat(namebuff, token);
277             } while (token[strlen(token) - 1] != '"');
278             token = xmalloc(strlen(namebuff));
279             strcpy(token, namebuff);
280         }
281         curItem->name = token;
282         curItem->type = nextWord();
283         curItem->target = nextWord();
284         newItem = xmalloc(sizeof(struct menuitem));
285         curItem->next = newItem;
286         curItem = newItem;
287         item++;
288         } while (strcmp(token, "}") != 0);
289     if (item == 0) AbEnd("menu '%s' has 0 items!\n", myMenu.name);
290     if (item > 31) AbEnd("menu '%s' has too many items!\n", myMenu.name);
291
292     curItem->next = NULL;
293
294     /* count menu sizes */
295     size = 0;
296     curItem = myMenu.item;
297     if (strstr(myMenu.type, "HORIZONTAL") != NULL) {
298         /* menu is HORIZONTAL, ysize=15, sum xsize of all items +~8?*/
299         myMenu.bot = myMenu.top + 15;
300         for (a = 0; a != item; a++) {
301             size += getNameSize(curItem->name);
302             curItem = curItem->next;
303         }
304     } else {
305         /* menu is VERTICAL, ysize=item*15, count largest xsize of all items +~8? */
306         myMenu.bot = myMenu.top + (14 * item);
307         for (a = 0; a != item; a++) {
308             tmpsize = getNameSize(curItem->name);
309             size = (size > tmpsize) ? size : tmpsize;
310             curItem = curItem->next;
311         }
312     }
313     myMenu.right = myMenu.left + size - 1;
314
315     curItem = myMenu.item;
316     for (a = 0; a != item; a++) {
317         /* print prototype only if MENU_ACTION or DYN_SUB_MENU are present in type */
318         if ((strstr(curItem->type, "MENU_ACTION") != NULL) || (strstr(curItem->type, "DYN_SUB_MENU") != NULL)) {
319             fprintf(outputCFile,
320                 "void %s (void);\n",
321                 curItem->target);
322         }
323         curItem=curItem->next;
324     }
325
326     fprintf(outputCFile,
327         "\n"
328         "const void %s = {\n"
329         "\t(char)%i, (char)%i,\n"
330         "\t(int)%i, (int)%i,\n"
331         "\t(char)(%i | %s),\n",
332         myMenu.name, myMenu.top, myMenu.bot, myMenu.left, myMenu.right, item, myMenu.type);
333
334     curItem = myMenu.item;
335     for (a = 0; a != item; a++) {
336         fprintf(outputCFile,
337             "\t%s, (char)%s, (int)",
338             curItem->name, curItem->type);
339         if ((strstr(curItem->type, "SUB_MENU") != NULL) && (strstr(curItem->type, "DYN_SUB_MENU") == NULL))
340             fprintf(outputCFile,
341                 "&");
342         fprintf(outputCFile,
343             "%s,\n",
344             curItem->target);
345         curItem = curItem->next;
346     }
347
348     fprintf(outputCFile,
349         "};\n\n");
350
351     if (fclose(outputCFile) != 0)
352         AbEnd("error closing %s: %s\n", outputCName, strerror(errno));
353 }
354
355
356 void DoHeader(void) {
357
358     time_t t;
359     struct tm *my_tm;
360
361     struct appheader myHead;
362     char *token;
363     char i1[9], i2[9], i3[9];
364     int a, b;
365
366     openSFile();
367
368     token = nextWord();
369
370     a = findToken(hdrFTypes, token);
371
372     if (apple == 1) {
373         switch (a) {
374             case 0:
375                 myHead.geostype = 0x82;
376                 break;
377             default:
378                 AbEnd("filetype '%s' is not supported yet\n", token);
379         }
380     } else {
381         switch (a) {
382             case 0:
383                 myHead.geostype = 6;
384                 break;
385             case 1:
386                 myHead.geostype = 14;
387                 break;
388             default:
389                 AbEnd("filetype '%s' is not supported yet\n", token);
390         }
391     }
392
393     myHead.dosname = nextPhrase();
394     nextPhrase();
395     myHead.classname = nextPhrase();
396     nextPhrase();
397     myHead.version = nextPhrase();
398
399     /* put default values into myHead here */
400     myHead.author = "cc65";
401     myHead.info = "Program compiled with cc65 and GEOSLib.";
402     myHead.dostype = 128;
403     if (apple == 0) myHead.dostype += 3;
404     myHead.structure = 0;
405     myHead.mode = 0;
406     myHead.icon = NULL;
407
408     t = time(NULL);
409     my_tm = localtime(&t);
410
411     myHead.year = my_tm->tm_year;
412     myHead.month = my_tm->tm_mon+1;
413     myHead.day = my_tm->tm_mday;
414     myHead.hour = my_tm->tm_hour;
415     myHead.min = my_tm->tm_min;
416
417     if (strcmp(nextWord(), "{") != 0) {
418         AbEnd("header '%s' has no opening bracket!\n", myHead.dosname);
419     }
420
421     do {
422         token = nextWord();
423         if (strcmp(token, "}") == 0) break;
424         switch (a = findToken(hdrFields, token)) {
425             case -1:
426                 AbEnd("unknown field '%s' in header '%s'\n", token, myHead.dosname);
427                 break;
428             case 0: /* author */
429                 myHead.author = nextPhrase();
430                 break;
431             case 1: /* info */
432                 myHead.info = nextPhrase();
433                 break;
434             case 2: /* date */
435                 myHead.year = atoi(nextWord());
436                 myHead.month = atoi(nextWord());
437                 myHead.day = atoi(nextWord());
438                 myHead.hour = atoi(nextWord());
439                 myHead.min = atoi(nextWord());
440                 break;
441             case 3: /* dostype */
442                 switch (b = findToken(hdrDOSTp, nextWord())) {
443                     case -1:
444                         AbEnd("unknown dostype in header '%s'\n", myHead.dosname);
445                         break;
446                     default:
447                         if (apple == 0) myHead.dostype = b / 2 + 128 + 1;
448                         break;
449                 }
450                 break;
451             case 4: /* mode */
452                 switch (b = findToken(hdrModes, nextWord())) {
453                     case -1:
454                         AbEnd("unknown mode in header '%s'\n", myHead.dosname);
455                     case 0:
456                         if (apple == 0) myHead.mode = 0x40;
457                         break;
458                     case 1:
459                         if (apple == 0) myHead.mode = 0x00;
460                         break;
461                     case 2:
462                         if (apple == 0) myHead.mode = 0xc0;
463                         break;
464                     case 3:
465                         if (apple == 0) myHead.mode = 0x80;
466                         break;
467                 }
468                 break;
469             case 5: /* structure */
470                 switch (b = findToken(hdrStructTp, nextWord())) {
471                     case -1:
472                         AbEnd("unknown structure type in header '%s'\n", myHead.dosname);
473                     case 0:
474                     case 1:
475                         myHead.structure = 0;
476                         break;
477                     case 2:
478                     case 3:
479                         myHead.structure = 1;
480                         break;
481                 }
482                 break;
483             case 6: /* icon */
484                 myHead.icon = nextPhrase();
485                 break;
486         }
487
488     } while (strcmp(token, "}") != 0);
489
490     /* OK, all information is gathered, do flushout */
491
492     fprintf(outputSFile,
493         "\n"
494         "\t\t.segment \"DIRENTRY\"\n\n");
495
496     if (apple == 1) {
497
498         fprintf(outputSFile,
499             "\t.byte %i << 4 | %i\n",
500             myHead.structure + 2, strlen(myHead.dosname));
501
502         fillOut(myHead.dosname, 15, "0");
503
504         fprintf(outputSFile,
505             "\t.byte $%02x\n"
506             "\t.word 0\n"
507             "\t.word 0\n"
508             "\t.byte 0, 0, 0\n"
509             "\t.word %i << 9 | %i << 5 | %i, %i << 8 | %i\n"
510             "\t.byte 0\n"
511             "\t.byte 0\n"
512             "\t.byte 0\n"
513             "\t.word 0\n"
514             "\t.word %i << 9 | %i << 5 | %i, %i << 8 | %i\n"
515             "\t.word 0\n",
516             myHead.geostype,
517             myHead.year % 100, myHead.month, myHead.day, myHead.hour, myHead.min,
518             myHead.year % 100, myHead.month, myHead.day, myHead.hour, myHead.min);
519
520     } else {
521
522         fprintf(outputSFile,
523             "\t.byte %i\n"
524             "\t.word 0\n",
525             myHead.dostype);
526
527         fillOut(myHead.dosname, 16, "$a0");
528
529         fprintf(outputSFile,
530             "\t.word 0\n"
531             "\t.byte %i\n"
532             "\t.byte %i\n"
533             "\t.byte %i, %i, %i, %i, %i\n\n"
534             "\t.word 0\n"
535             "\t.byte \"PRG formatted GEOS file V1.0\"\n\n",
536             myHead.structure, myHead.geostype,
537             myHead.year, myHead.month, myHead.day, myHead.hour, myHead.min);
538     }
539
540     fprintf(outputSFile,
541         "\n"
542         "\t\t.segment \"FILEINFO\"\n\n"
543         "\t.import __VLIR0_START__, __STARTUP_RUN__\n\n"
544         "\t.byte 3, 21, 63 | $80\n");
545
546     if (myHead.icon != NULL) {
547         fprintf(outputSFile,
548             "\t.incbin \"%s\", 0, 63\n",
549             myHead.icon);
550     } else {
551         for (a = 0; a != 63; a = a + 3) {
552             fprintf(outputSFile,
553                 "\t.byte %%%s, %%%s, %%%s\n",
554                 bintos(icon1[a], i1), bintos(icon1[a+1], i2), bintos(icon1[a+2], i3));
555         }
556     }
557
558     fprintf(outputSFile,
559         "\t.byte %i, %i, %i\n"
560         "\t.word __VLIR0_START__, __VLIR0_START__ - 1, __STARTUP_RUN__\n\n",
561         myHead.dostype, myHead.geostype, myHead.structure);
562
563     fillOut(myHead.classname, 12, "$20");
564
565     fillOut(myHead.version, 4, "0");
566
567     fprintf(outputSFile,
568         "\t.byte 0, 0, 0\n"
569         "\t.byte %i\n\n",
570         myHead.mode);
571
572     setLen(myHead.author, 62);
573     fprintf(outputSFile,
574         "\t.byte \"%s\"\n"
575         "\t.byte 0\n"
576         "\t.res  (63 - %i)\n\n",
577         myHead.author, (int)(strlen(myHead.author) + 1));
578
579     setLen(myHead.info, 95);
580     fprintf(outputSFile,
581         "\t.byte \"%s\"\n"
582         "\t.byte 0\n\n",
583         myHead.info);
584
585     if (fclose (outputSFile) != 0)
586         AbEnd("error closing %s: %s\n", outputSName, strerror(errno));
587 }
588
589
590 void DoVLIR(void) {
591
592     char *token;
593     int record, lastrecord;
594     int vlirsize, vlirtable[127];
595
596     openSFile();
597
598     vlirsize = strtol(nextWord(), NULL, 0);
599
600     if (strcmp(nextWord(), "{") != 0) {
601         AbEnd ("VLIR description has no opening bracket!\n");
602     }
603
604     lastrecord = -1;
605     memset(vlirtable, 0, sizeof(vlirtable));
606
607     do {
608         token = nextWord();
609         if (strcmp(token, "}") == 0) break;
610
611         record = atoi(token);
612         if (record < 0 || record > 126) {
613             AbEnd("VLIR record %i is out of range 0-126.\n", record);
614         }
615         if (vlirtable[record] == 1) {
616             AbEnd("VLIR record %i is defined twice.\n", record);
617         }
618
619         vlirtable[record] = 1;
620         if (record > lastrecord) lastrecord = record;
621     } while (strcmp(token, "}") != 0);
622
623     if (lastrecord == -1) {
624         AbEnd("There must be at least one VLIR record.\n");
625     }
626     
627     /* always include record 0 */
628     vlirtable[0] = 1;
629
630     /* OK, all information is gathered, do flushout */
631
632     fprintf(outputSFile,
633         "\n"
634         "\t\t.segment \"RECORDS\"\n\n"
635         "\t.export __OVERLAYSIZE__ : absolute = $%04x\n\n",
636         vlirsize);
637
638     for (record = 0; record <= lastrecord; record++) {
639         if (vlirtable[record] == 1) {
640             fprintf(outputSFile,
641                 "\t.import __VLIR%i_START__, __VLIR%i_LAST__\n",
642                 record, record);
643         }
644     }
645     fprintf(outputSFile,
646         "\n");
647
648     for (record = 0; record <= lastrecord; record++) {
649         if (vlirtable[record] == 1) {
650             fprintf(outputSFile,
651                 "\t.byte .lobyte ((__VLIR%i_LAST__ - __VLIR%i_START__ - 1) /    254) + 1\n"
652                 "\t.byte .lobyte ((__VLIR%i_LAST__ - __VLIR%i_START__ - 1) .MOD 254) + 2\n",
653                 record, record, record, record);
654         } else {
655             fprintf(outputSFile,
656                 "\t.byte $00\n"
657                 "\t.byte $FF\n");
658         }
659     }
660     fprintf(outputSFile,
661         "\n");
662
663     if (fclose(outputSFile) != 0)
664         AbEnd("error closing %s: %s\n", outputSName, strerror(errno));
665
666     openCFile();
667
668     fprintf(outputCFile,
669         "extern void _OVERLAYADDR__;\n"
670         "extern void _OVERLAYSIZE__;\n\n"
671         "#define OVERLAY_ADDR (char*)   &_OVERLAYADDR__\n"
672         "#define OVERLAY_SIZE (unsigned)&_OVERLAYSIZE__\n\n");
673
674     if (fclose(outputCFile) != 0)
675         AbEnd("error closing %s: %s\n", outputCName, strerror(errno));
676 }
677
678
679 char *filterInput(FILE *F, char *tbl) {
680
681     /* loads file into buffer filtering it out */
682     int a, prevchar = -1, i = 0, bracket = 0, quote = 1;
683
684     while (1) {
685         a = getc(F);
686         if ((a == '\n') || (a == '\015')) a = ' ';
687         if (a == ',' && quote) a = ' ';
688         if (a == '\042') quote =! quote;
689         if (quote) {
690             if ((a == '{') || (a == '(')) bracket++;
691             if ((a == '}') || (a == ')')) bracket--;
692         }
693         if (a == EOF) {
694             tbl[i] = '\0';
695             xrealloc(tbl, i + 1);
696             break;
697         }
698         if (IsSpace(a)) {
699             if ((prevchar != ' ') && (prevchar != -1)) {
700                 tbl[i++] = ' ';
701                 prevchar = ' ';
702             }
703         } else {
704             if (a == ';' && quote) {
705                 do {
706                     a = getc(F);
707                 } while (a != '\n');
708                 fseek(F, -1, SEEK_CUR);
709             } else {
710                 tbl[i++] = a;
711                 prevchar = a;
712             }
713         }
714     }
715
716     if (bracket != 0) AbEnd("there are unclosed brackets!\n");
717
718     return tbl;
719 }
720
721
722 void processFile(const char *filename) {
723
724     FILE *F;
725
726     char *str;
727     char *token;
728
729     int head = 0; /* number of processed HEADER sections */
730     int vlir = 0; /* number of processed VLIR sections */
731
732     if ((F = fopen(filename, "r")) == 0) {
733         AbEnd("can't open file %s for reading: %s\n", filename, strerror(errno));
734     }
735
736     str = filterInput(F, xmalloc(BLOODY_BIG_BUFFER));
737
738     token = strtok(str, " ");
739
740     do {
741         if (str != NULL) {
742             switch (findToken(mainToken, token)) {
743                 case 0:
744                     DoMenu();
745                     break;
746                 case 1:
747                     if (++head != 1) {
748                         AbEnd("more than one HEADER section, aborting.\n");
749                     } else {
750                         DoHeader();
751                     }
752                     break;
753                 case 2: break; /* icon not implemented yet */
754                 case 3: break; /* dialog not implemented yet */
755                 case 4:
756                     if (++vlir != 1) {
757                         AbEnd("more than one VLIR section, aborting.\n");
758                     } else {
759                         DoVLIR();
760                     }
761                     break;
762                 default:
763                     AbEnd("unknown section %s.\n",token);
764                     break;
765             }
766         }
767         token = nextWord();
768     } while (token != NULL);
769 }
770
771
772 int main(int argc, char *argv[]) {
773
774     int ffile = 0, i = 1;
775
776     ProgName = argv[0];
777
778     while (i < argc) {
779         const char *arg = argv[i];
780
781         if (arg[0] == '-') {
782             switch (arg[1]) {
783                 case 'o':
784                     outputCName = argv[++i];
785                     break;
786                 case 's':
787                     outputSName = argv[++i];
788                     break;
789                 case 't':
790                     switch (FindTarget(argv[++i])) {
791                         case TGT_GEOS: /* todo: TGT_GEOS-CBM */
792                             apple = 0;
793                             break;
794                         case TGT_COUNT: /* todo: TGT_GEOS-APPLE */
795                             apple = 1;
796                             break;
797                         default:
798                             AbEnd("unknown target system type %s\n", argv[i]);
799                     }
800                     break;
801                 case 'h':
802                 case '?':
803                     printUsage();
804                     exit(EXIT_SUCCESS);
805                     break;
806                 default:
807                     AbEnd("unknown option %s\n", arg);
808             }
809         } else {
810             ffile++;
811
812             if (outputCName == NULL) outputCName = MakeFilename(arg, ".h");
813             if (outputSName == NULL) outputSName = MakeFilename(arg, ".s");
814
815             processFile(arg);
816         }
817
818         i++;
819     }
820
821     if (ffile == 0) AbEnd("no input file\n");
822
823     return EXIT_SUCCESS;
824 }