]> git.sur5r.net Git - cc65/blob - src/cl65/main.c
Merge remote-tracking branch 'upstream/master' into a5200
[cc65] / src / cl65 / main.c
1 /*****************************************************************************/
2 /*                                                                           */
3 /*                                  main.c                                   */
4 /*                                                                           */
5 /*             Main module for the cl65 compile-and-link utility             */
6 /*                                                                           */
7 /*                                                                           */
8 /*                                                                           */
9 /* (C) 1999-2013, Ullrich von Bassewitz                                      */
10 /*                Roemerstrasse 52                                           */
11 /*                D-70794 Filderstadt                                        */
12 /* EMail:         uz@cc65.org                                                */
13 /*                                                                           */
14 /*                                                                           */
15 /* This software is provided 'as-is', without any expressed or implied       */
16 /* warranty.  In no event will the authors be held liable for any damages    */
17 /* arising from the use of this software.                                    */
18 /*                                                                           */
19 /* Permission is granted to anyone to use this software for any purpose,     */
20 /* including commercial applications, and to alter it and redistribute it    */
21 /* freely, subject to the following restrictions:                            */
22 /*                                                                           */
23 /* 1. The origin of this software must not be misrepresented; you must not   */
24 /*    claim that you wrote the original software. If you use this software   */
25 /*    in a product, an acknowledgment in the product documentation would be  */
26 /*    appreciated but is not required.                                       */
27 /* 2. Altered source versions must be plainly marked as such, and must not   */
28 /*    be misrepresented as being the original software.                      */
29 /* 3. This notice may not be removed or altered from any source              */
30 /*    distribution.                                                          */
31 /*                                                                           */
32 /*****************************************************************************/
33
34
35
36 /* Check out if we have a spawn() function on the system, or if we must use
37  * our own.
38  */
39 #if defined(_WIN32)
40 #  define HAVE_SPAWN 1
41 #else
42 #  define NEED_SPAWN 1
43 #endif
44
45 /* GCC strictly follows http://c-faq.com/ansi/constmismatch.html and issues an
46  * 'incompatible pointer type' warning - that can't be suppressed via #pragma.
47  * The spawnvp() prototype of MinGW (http://www.mingw.org/) differs from the
48  * one of MinGW-w64 (http://mingw-w64.sourceforge.net/) regarding constness.
49  * So there's no alternative to actually distinguish these environments :-(
50  */
51 #define SPAWN_ARGV_CONST_CAST
52 #if defined(__MINGW32__)
53 #  include <_mingw.h>
54 #  if !defined(__MINGW64_VERSION_MAJOR)
55 #    undef  SPAWN_ARGV_CONST_CAST
56 #    define SPAWN_ARGV_CONST_CAST (const char* const *)
57 #  endif
58 #endif
59
60
61 #include <stdio.h>
62 #include <stdlib.h>
63 #include <string.h>
64 #include <ctype.h>
65 #include <errno.h>
66 #if defined(HAVE_SPAWN)
67 #  include <process.h>
68 #endif
69
70 /* common */
71 #include "attrib.h"
72 #include "cmdline.h"
73 #include "filetype.h"
74 #include "fname.h"
75 #include "mmodel.h"
76 #include "strbuf.h"
77 #include "target.h"
78 #include "version.h"
79 #include "xmalloc.h"
80
81 /* cl65 */
82 #include "global.h"
83 #include "error.h"
84
85
86
87 /*****************************************************************************/
88 /*                                   Data                                    */
89 /*****************************************************************************/
90
91
92
93 /* Struct that describes a command */
94 typedef struct CmdDesc CmdDesc;
95 struct CmdDesc {
96     char*       Name;           /* The command name */
97
98     unsigned    ArgCount;       /* Count of arguments */
99     unsigned    ArgMax;         /* Maximum count of arguments */
100     char**      Args;           /* The arguments */
101
102     unsigned    FileCount;      /* Count of files to translate */
103     unsigned    FileMax;        /* Maximum count of files */
104     char**      Files;          /* The files */
105 };
106
107 /* Command descriptors for the different programs */
108 static CmdDesc CC65 = { 0, 0, 0, 0, 0, 0, 0 };
109 static CmdDesc CA65 = { 0, 0, 0, 0, 0, 0, 0 };
110 static CmdDesc CO65 = { 0, 0, 0, 0, 0, 0, 0 };
111 static CmdDesc LD65 = { 0, 0, 0, 0, 0, 0, 0 };
112 static CmdDesc GRC  = { 0, 0, 0, 0, 0, 0, 0 };
113
114 /* Variables controlling the steps we're doing */
115 static int DoLink       = 1;
116 static int DoAssemble   = 1;
117
118 /* The name of the output file, NULL if none given */
119 static const char* OutputName = 0;
120
121 /* The name of the linker configuration file if given */
122 static const char* LinkerConfig = 0;
123
124 /* The name of the first input file. This will be used to construct the
125  * executable file name if no explicit name is given.
126  */
127 static const char* FirstInput = 0;
128
129 /* The names of the files for dependency generation */
130 static const char* DepName = 0;
131 static const char* FullDepName = 0;
132
133 /* Remember if we should link a module */
134 static int Module = 0;
135
136 /* Extension used for a module */
137 #define MODULE_EXT      ".o65"
138
139 /* Name of the target specific runtime library */
140 static char* TargetLib  = 0;
141
142
143
144 /*****************************************************************************/
145 /*                Include the system specific spawn function                 */
146 /*****************************************************************************/
147
148
149
150 #if defined(NEED_SPAWN)
151 #  if defined(SPAWN_AMIGA)
152 #    include "spawn-amiga.inc"
153 #  else
154 #    include "spawn-unix.inc"
155 #  endif
156 #endif
157
158
159
160 /*****************************************************************************/
161 /*                        Command structure handling                         */
162 /*****************************************************************************/
163
164
165
166 static void CmdExpand (CmdDesc* Cmd)
167 /* Expand the argument vector */
168 {
169     unsigned NewMax  = Cmd->ArgMax + 10;
170     char**       NewArgs = xmalloc (NewMax * sizeof (char*));
171     memcpy (NewArgs, Cmd->Args, Cmd->ArgMax * sizeof (char*));
172     xfree (Cmd->Args);
173     Cmd->Args   = NewArgs;
174     Cmd->ArgMax = NewMax;
175 }
176
177
178
179 static void CmdAddArg (CmdDesc* Cmd, const char* Arg)
180 /* Add a new argument to the command */
181 {
182     /* Expand the argument vector if needed */
183     if (Cmd->ArgCount >= Cmd->ArgMax) {
184         CmdExpand (Cmd);
185     }
186
187     /* Add a copy of the new argument, allow a NULL pointer */
188     if (Arg) {
189         Cmd->Args[Cmd->ArgCount++] = xstrdup (Arg);
190     } else {
191         Cmd->Args[Cmd->ArgCount++] = 0;
192     }
193 }
194
195
196
197 static void CmdAddArg2 (CmdDesc* Cmd, const char* Arg1, const char* Arg2)
198 /* Add a new argument pair to the command */
199 {
200     CmdAddArg (Cmd, Arg1);
201     CmdAddArg (Cmd, Arg2);
202 }
203
204
205
206 static void CmdAddArgList (CmdDesc* Cmd, const char* ArgList)
207 /* Add a list of arguments separated by commas */
208 {
209     const char* Arg = ArgList;
210     const char* P   = Arg;
211
212     while (1) {
213         if (*P == '\0' || *P == ',') {
214
215             /* End of argument, add it */
216             unsigned Len = P - Arg;
217
218             /* Expand the argument vector if needed */
219             if (Cmd->ArgCount >= Cmd->ArgMax) {
220                 CmdExpand (Cmd);
221             }
222
223             /* Add the new argument */
224             Cmd->Args[Cmd->ArgCount] = memcpy (xmalloc (Len + 1), Arg, Len);
225             Cmd->Args[Cmd->ArgCount][Len] = '\0';
226             ++Cmd->ArgCount;
227
228             /* If the argument was terminated by a comma, skip it, otherwise
229              * we're done.
230              */
231             if (*P == ',') {
232                 /* Start over at next char */
233                 Arg = ++P;
234             } else {
235                 break;
236             }
237         } else {
238             /* Skip other chars */
239             ++P;
240         }
241     }
242
243 }
244
245
246
247 static void CmdDelArgs (CmdDesc* Cmd, unsigned LastValid)
248 /* Remove all arguments with an index greater than LastValid */
249 {
250     while (Cmd->ArgCount > LastValid) {
251         Cmd->ArgCount--;
252         xfree (Cmd->Args [Cmd->ArgCount]);
253         Cmd->Args [Cmd->ArgCount] = 0;
254     }
255 }
256
257
258
259 static void CmdAddFile (CmdDesc* Cmd, const char* File)
260 /* Add a new file to the command */
261 {
262     /* Expand the file vector if needed */
263     if (Cmd->FileCount == Cmd->FileMax) {
264         unsigned NewMax   = Cmd->FileMax + 10;
265         char**   NewFiles = xmalloc (NewMax * sizeof (char*));
266         memcpy (NewFiles, Cmd->Files, Cmd->FileMax * sizeof (char*));
267         xfree (Cmd->Files);
268         Cmd->Files   = NewFiles;
269         Cmd->FileMax = NewMax;
270     }
271
272     /* If the file name is not NULL (which is legal and is used to terminate
273      * the file list), check if the file name does already exist in the file
274      * list and print a warning if so. Regardless of the search result, add
275      * the file.
276      */
277     if (File) {
278         unsigned I;
279         for (I = 0; I < Cmd->FileCount; ++I) {
280             if (strcmp (Cmd->Files[I], File) == 0) {
281                 /* Duplicate file */
282                 Warning ("Duplicate file in argument list: `%s'", File);
283                 /* No need to search further */
284                 break;
285             }
286         }
287
288         /* Add the file */
289         Cmd->Files [Cmd->FileCount++] = xstrdup (File);
290     } else {
291         /* Add a NULL pointer */
292         Cmd->Files [Cmd->FileCount++] = 0;
293     }
294 }
295
296
297
298 static void CmdInit (CmdDesc* Cmd, const char* Path, const char* Name)
299 /* Initialize the command using the given path and name of the executable */
300 {
301     char* FullName;
302
303     FullName = (char*) xmalloc (strlen (Path) + strlen (Name) + 1);
304     strcpy (FullName, Path);
305     strcat (FullName, Name);
306
307     /* Remember the command */
308     Cmd->Name = xstrdup (FullName);
309
310     /* Use the command name as first argument */
311     CmdAddArg (Cmd, FullName);
312
313     xfree (FullName);
314 }
315
316
317
318 static void CmdSetOutput (CmdDesc* Cmd, const char* File)
319 /* Set the output file in a command desc */
320 {
321     CmdAddArg2 (Cmd, "-o", File);
322 }
323
324
325
326 static void CmdSetTarget (CmdDesc* Cmd, target_t Target)
327 /* Set the output file in a command desc */
328 {
329     CmdAddArg2 (Cmd, "-t", GetTargetName (Target));
330 }
331
332
333
334 static void CmdPrint (CmdDesc* Cmd, FILE* F)
335 /* Output the command line encoded in the command desc */
336 {
337     unsigned I;
338     for (I = 0; I < Cmd->ArgCount && Cmd->Args[I] != 0; ++I) {
339         fprintf (F, "%s ", Cmd->Args[I]);
340     }
341 }
342
343
344
345 /*****************************************************************************/
346 /*                              Target handling                              */
347 /*****************************************************************************/
348
349
350
351 static void SetTargetFiles (void)
352 /* Set the target system files */
353 {
354     /* Determine the names of the target specific library file */
355     if (Target != TGT_NONE) {
356
357         /* Get a pointer to the system name and its length */
358         const char* TargetName = GetTargetName (Target);
359         unsigned    TargetNameLen = strlen (TargetName);
360
361         /* Set the library file */
362         TargetLib = xmalloc (TargetNameLen + 4 + 1);
363         memcpy (TargetLib, TargetName, TargetNameLen);
364         strcpy (TargetLib + TargetNameLen, ".lib");
365
366     }
367 }
368
369
370
371 /*****************************************************************************/
372 /*                               Subprocesses                                */
373 /*****************************************************************************/
374
375
376
377 static void ExecProgram (CmdDesc* Cmd)
378 /* Execute a subprocess with the given name/parameters. Exit on errors. */
379 {
380     int Status;
381
382     /* If in debug mode, output the command line we will execute */
383     if (Debug) {
384         printf ("Executing: ");
385         CmdPrint (Cmd, stdout);
386         printf ("\n");
387     }
388
389     /* Call the program */
390     Status = spawnvp (P_WAIT, Cmd->Name, SPAWN_ARGV_CONST_CAST Cmd->Args);
391
392     /* Check the result code */
393     if (Status < 0) {
394         /* Error executing the program */
395         Error ("Cannot execute `%s': %s", Cmd->Name, strerror (errno));
396     } else if (Status != 0) {
397         /* Called program had an error */
398         exit (Status);
399     }
400 }
401
402
403
404 static void Link (void)
405 /* Link the resulting executable */
406 {
407     unsigned I;
408
409     /* Since linking is always the final step, if we have an output file name
410      * given, set it here. If we don't have an explicit output name given,
411      * try to build one from the name of the first input file.
412      */
413     if (OutputName) {
414
415         CmdSetOutput (&LD65, OutputName);
416
417     } else if (FirstInput && FindExt (FirstInput)) {  /* Only if ext present! */
418
419         const char* Extension = Module? MODULE_EXT : "";
420         char* Output = MakeFilename (FirstInput, Extension);
421         CmdSetOutput (&LD65, Output);
422         xfree (Output);
423
424     }
425
426     /* If we have a linker config file given, add it to the command line.
427      * Otherwise pass the target to the linker if we have one.
428      */
429     if (LinkerConfig) {
430         if (Module) {
431             Error ("Cannot use -C and --module together");
432         }
433         CmdAddArg2 (&LD65, "-C", LinkerConfig);
434     } else if (Module) {
435         CmdSetTarget (&LD65, TGT_MODULE);
436     } else {
437         CmdSetTarget (&LD65, Target);
438     }
439
440     /* Determine which target libraries are needed */
441     SetTargetFiles ();
442
443     /* Add all object files as parameters */
444     for (I = 0; I < LD65.FileCount; ++I) {
445         CmdAddArg (&LD65, LD65.Files [I]);
446     }
447
448     /* Add the system runtime library */
449     if (TargetLib) {
450         CmdAddArg (&LD65, TargetLib);
451     }
452
453     /* Terminate the argument list with a NULL pointer */
454     CmdAddArg (&LD65, 0);
455
456     /* Call the linker */
457     ExecProgram (&LD65);
458 }
459
460
461
462 static void AssembleFile (const char* File, unsigned ArgCount)
463 /* Common routine to assemble a file. Will be called by Assemble() and
464  * AssembleIntermediate(). Adds options common for both routines and
465  * assembles the file. Will remove excess arguments after assembly.
466  */
467 {
468     /* Set the target system */
469     CmdSetTarget (&CA65, Target);
470
471     /* Check if this is the last processing step */
472     if (DoLink) {
473         /* We're linking later. Add the output file of the assembly
474          * the the file list of the linker. The name of the output
475          * file is that of the input file with ".s" replaced by ".o".
476          */
477         char* ObjName = MakeFilename (File, ".o");
478         CmdAddFile (&LD65, ObjName);
479         xfree (ObjName);
480     } else {
481         /* This is the final step. If an output name is given, set it */
482         if (OutputName) {
483             CmdSetOutput (&CA65, OutputName);
484         }
485     }
486
487     /* Add the file as argument for the assembler */
488     CmdAddArg (&CA65, File);
489
490     /* Add a NULL pointer to terminate the argument list */
491     CmdAddArg (&CA65, 0);
492
493     /* Run the assembler */
494     ExecProgram (&CA65);
495
496     /* Remove the excess arguments */
497     CmdDelArgs (&CA65, ArgCount);
498 }
499
500
501
502 static void AssembleIntermediate (const char* SourceFile)
503 /* Assemble an intermediate file which was generated by a previous processing
504  * step with SourceFile as input. The -dep options won't be added and
505  * the intermediate assembler file is removed after assembly.
506  */
507 {
508     /* Generate the name of the assembler output file from the source file
509      * name. It's the same name with the extension replaced by ".s"
510      */
511     char* AsmName = MakeFilename (SourceFile, ".s");
512
513     /* Assemble the intermediate assembler file */
514     AssembleFile (AsmName, CA65.ArgCount);
515
516     /* Remove the input file */
517     if (remove (AsmName) < 0) {
518         Warning ("Cannot remove temporary file `%s': %s",
519                  AsmName, strerror (errno));
520     }
521
522     /* Free the assembler file name which was allocated from the heap */
523     xfree (AsmName);
524 }
525
526
527
528 static void Assemble (const char* File)
529 /* Assemble the given file */
530 {
531     /* Remember the current assembler argument count */
532     unsigned ArgCount = CA65.ArgCount;
533
534     /* We aren't assembling an intermediate file, but one requested by the
535      * user. So add a few options here if they were given on the command
536      * line.
537      */
538     if (DepName && *DepName) {
539         CmdAddArg2 (&CA65, "--create-dep", DepName);
540     }
541     if (FullDepName && *FullDepName) {
542         CmdAddArg2 (&CA65, "--create-full-dep", FullDepName);
543     }
544
545     /* Use the common routine */
546     AssembleFile (File, ArgCount);
547 }
548
549
550
551 static void Compile (const char* File)
552 /* Compile the given file */
553 {
554     /* Remember the current compiler argument count */
555     unsigned ArgCount = CC65.ArgCount;
556
557     /* Set the target system */
558     CmdSetTarget (&CC65, Target);
559
560     /* Check if this is the final step */
561     if (DoAssemble) {
562         /* We will assemble this file later. If a dependency file is to be
563          * generated, set the dependency target to be the final object file,
564          * not the intermediate assembler file. But beware: There may be an
565          * output name specified for the assembler.
566          */
567         if (DepName || FullDepName) {
568             /* Was an output name for the assembler specified? */
569             if (!DoLink && OutputName) {
570                 /* Use this name as the dependency target */
571                 CmdAddArg2 (&CC65, "--dep-target", OutputName);
572             } else {
573                 /* Use the object file name as the dependency target */
574                 char* ObjName = MakeFilename (File, ".o");
575                 CmdAddArg2 (&CC65, "--dep-target", ObjName);
576                 xfree (ObjName);
577             }
578         }
579     } else {
580         /* If we won't assemble, this is the final step. In this case, set
581          * the output name if it was given.
582          */
583         if (OutputName) {
584             CmdSetOutput (&CC65, OutputName);
585         }
586     }
587
588     /* Add the file as argument for the compiler */
589     CmdAddArg (&CC65, File);
590
591     /* Add a NULL pointer to terminate the argument list */
592     CmdAddArg (&CC65, 0);
593
594     /* Run the compiler */
595     ExecProgram (&CC65);
596
597     /* Remove the excess arguments */
598     CmdDelArgs (&CC65, ArgCount);
599
600     /* If this is not the final step, assemble the generated file, then
601      * remove it
602      */
603     if (DoAssemble) {
604         /* Assemble the intermediate file and remove it */
605         AssembleIntermediate (File);
606     }
607 }
608
609
610
611 static void CompileRes (const char* File)
612 /* Compile the given geos resource file */
613 {
614     /* Remember the current assembler argument count */
615     unsigned ArgCount = GRC.ArgCount;
616
617     /* Resource files need an geos-apple or geos-cbm target but this
618      * is checked within grc65.
619      */
620     CmdSetTarget (&GRC, Target);
621
622     /* Add the file as argument for the resource compiler */
623     CmdAddArg (&GRC, File);
624
625     /* Add a NULL pointer to terminate the argument list */
626     CmdAddArg (&GRC, 0);
627
628     /* Run the compiler */
629     ExecProgram (&GRC);
630
631     /* Remove the excess arguments */
632     CmdDelArgs (&GRC, ArgCount);
633
634     /* If this is not the final step, assemble the generated file, then
635      * remove it
636      */
637     if (DoAssemble) {
638         /* Assemble the intermediate file and remove it */
639         AssembleIntermediate (File);
640     }
641 }
642
643
644
645 static void ConvertO65 (const char* File)
646 /* Convert an o65 object file into an assembler file */
647 {
648     /* Remember the current converter argument count */
649     unsigned ArgCount = CO65.ArgCount;
650
651     /* If we won't assemble, this is the final step. In this case, set the
652      * output name.
653      */
654     if (!DoAssemble && OutputName) {
655         CmdSetOutput (&CO65, OutputName);
656     }
657
658     /* Add the file as argument for the object file converter */
659     CmdAddArg (&CO65, File);
660
661     /* Add a NULL pointer to terminate the argument list */
662     CmdAddArg (&CO65, 0);
663
664     /* Run the converter */
665     ExecProgram (&CO65);
666
667     /* Remove the excess arguments */
668     CmdDelArgs (&CO65, ArgCount);
669
670     /* If this is not the final step, assemble the generated file, then
671      * remove it
672      */
673     if (DoAssemble) {
674         /* Assemble the intermediate file and remove it */
675         AssembleIntermediate (File);
676     }
677 }
678
679
680
681 /*****************************************************************************/
682 /*                                   Code                                    */
683 /*****************************************************************************/
684
685
686
687 static void Usage (void)
688 /* Print usage information and exit */
689 {
690     printf ("Usage: %s [options] file [...]\n"
691             "Short options:\n"
692             "  -c\t\t\t\tCompile and assemble, but don't link\n"
693             "  -d\t\t\t\tDebug mode\n"
694             "  -g\t\t\t\tAdd debug info\n"
695             "  -h\t\t\t\tHelp (this text)\n"
696             "  -l name\t\t\tCreate an assembler listing file\n"
697             "  -m name\t\t\tCreate a map file\n"
698             "  -mm model\t\t\tSet the memory model\n"
699             "  -o name\t\t\tName the output file\n"
700             "  -r\t\t\t\tEnable register variables\n"
701             "  -t sys\t\t\tSet the target system\n"
702             "  -u sym\t\t\tForce an import of symbol `sym'\n"
703             "  -v\t\t\t\tVerbose mode\n"
704             "  -vm\t\t\t\tVerbose map file\n"
705             "  -C name\t\t\tUse linker config file\n"
706             "  -Cl\t\t\t\tMake local variables static\n"
707             "  -D sym[=defn]\t\t\tDefine a preprocessor symbol\n"
708             "  -I dir\t\t\tSet a compiler include directory path\n"
709             "  -L path\t\t\tSpecify a library search path\n"
710             "  -Ln name\t\t\tCreate a VICE label file\n"
711             "  -O\t\t\t\tOptimize code\n"
712             "  -Oi\t\t\t\tOptimize code, inline runtime functions\n"
713             "  -Or\t\t\t\tOptimize code, honour the register keyword\n"
714             "  -Os\t\t\t\tOptimize code, inline known C functions\n"
715             "  -S\t\t\t\tCompile, but don't assemble and link\n"
716             "  -T\t\t\t\tInclude source as comment\n"
717             "  -V\t\t\t\tPrint the version number\n"
718             "  -W name[,...]\t\t\tSuppress compiler warnings\n"
719             "  -Wa options\t\t\tPass options to the assembler\n"
720             "  -Wc options\t\t\tPass options to the compiler\n"
721             "  -Wl options\t\t\tPass options to the linker\n"
722             "\n"
723             "Long options:\n"
724             "  --add-source\t\t\tInclude source as comment\n"
725             "  --asm-args options\t\tPass options to the assembler\n"
726             "  --asm-define sym[=v]\t\tDefine an assembler symbol\n"
727             "  --asm-include-dir dir\t\tSet an assembler include directory\n"
728             "  --bin-include-dir dir\t\tSet an assembler binary include directory\n"
729             "  --bss-label name\t\tDefine and export a BSS segment label\n"
730             "  --bss-name seg\t\tSet the name of the BSS segment\n"
731             "  --cc-args options\t\tPass options to the compiler\n"
732             "  --cfg-path path\t\tSpecify a config file search path\n"
733             "  --check-stack\t\t\tGenerate stack overflow checks\n"
734             "  --code-label name\t\tDefine and export a CODE segment label\n"
735             "  --code-name seg\t\tSet the name of the CODE segment\n"
736             "  --codesize x\t\t\tAccept larger code by factor x\n"
737             "  --config name\t\t\tUse linker config file\n"
738             "  --cpu type\t\t\tSet CPU type\n"
739             "  --create-dep name\t\tCreate a make dependency file\n"
740             "  --create-full-dep name\tCreate a full make dependency file\n"
741             "  --data-label name\t\tDefine and export a DATA segment label\n"
742             "  --data-name seg\t\tSet the name of the DATA segment\n"
743             "  --debug\t\t\tDebug mode\n"
744             "  --debug-info\t\t\tAdd debug info\n"
745             "  --feature name\t\tSet an emulation feature\n"
746             "  --force-import sym\t\tForce an import of symbol `sym'\n"
747             "  --help\t\t\tHelp (this text)\n"
748             "  --include-dir dir\t\tSet a compiler include directory path\n"
749             "  --ld-args options\t\tPass options to the linker\n"
750             "  --lib file\t\t\tLink this library\n"
751             "  --lib-path path\t\tSpecify a library search path\n"
752             "  --list-targets\t\tList all available targets\n"
753             "  --listing name\t\tCreate an assembler listing file\n"
754             "  --list-bytes n\t\tNumber of bytes per assembler listing line\n"
755             "  --mapfile name\t\tCreate a map file\n"
756             "  --memory-model model\t\tSet the memory model\n"
757             "  --module\t\t\tLink as a module\n"
758             "  --module-id id\t\tSpecify a module ID for the linker\n"
759             "  --o65-model model\t\tOverride the o65 model\n"
760             "  --obj file\t\t\tLink this object file\n"
761             "  --obj-path path\t\tSpecify an object file search path\n"
762             "  --register-space b\t\tSet space available for register variables\n"
763             "  --register-vars\t\tEnable register variables\n"
764             "  --rodata-name seg\t\tSet the name of the RODATA segment\n"
765             "  --signed-chars\t\tDefault characters are signed\n"
766             "  --standard std\t\tLanguage standard (c89, c99, cc65)\n"
767             "  --start-addr addr\t\tSet the default start address\n"
768             "  --static-locals\t\tMake local variables static\n"
769             "  --target sys\t\t\tSet the target system\n"
770             "  --version\t\t\tPrint the version number\n"
771             "  --verbose\t\t\tVerbose mode\n"
772             "  --zeropage-label name\t\tDefine and export a ZEROPAGE segment label\n"
773             "  --zeropage-name seg\t\tSet the name of the ZEROPAGE segment\n",
774             ProgName);
775 }
776
777
778
779 static void OptAddSource (const char* Opt attribute ((unused)),
780                           const char* Arg attribute ((unused)))
781 /* Strict source code as comments to the generated asm code */
782 {
783     CmdAddArg (&CC65, "-T");
784 }
785
786
787
788 static void OptAsmArgs (const char* Opt attribute ((unused)), const char* Arg)
789 /* Pass arguments to the assembler */
790 {
791     CmdAddArgList (&CA65, Arg);
792 }
793
794
795
796 static void OptAsmDefine (const char* Opt attribute ((unused)), const char* Arg)
797 /* Define an assembler symbol (assembler) */
798 {
799     CmdAddArg2 (&CA65, "-D", Arg);
800 }
801
802
803
804 static void OptAsmIncludeDir (const char* Opt attribute ((unused)), const char* Arg)
805 /* Include directory (assembler) */
806 {
807     CmdAddArg2 (&CA65, "-I", Arg);
808 }
809
810
811
812 static void OptBinIncludeDir (const char* Opt attribute ((unused)), const char* Arg)
813 /* Binary include directory (assembler) */
814 {
815     CmdAddArg2 (&CA65, "--bin-include-dir", Arg);
816 }
817
818
819
820 static void OptBssLabel (const char* Opt attribute ((unused)), const char* Arg)
821 /* Handle the --bss-label option */
822 {
823     CmdAddArg2 (&CO65, "--bss-label", Arg);
824 }
825
826
827
828 static void OptBssName (const char* Opt attribute ((unused)), const char* Arg)
829 /* Handle the --bss-name option */
830 {
831     CmdAddArg2 (&CC65, "--bss-name", Arg);
832     CmdAddArg2 (&CO65, "--bss-name", Arg);
833 }
834
835
836
837 static void OptCCArgs (const char* Opt attribute ((unused)), const char* Arg)
838 /* Pass arguments to the compiler */
839 {
840     CmdAddArgList (&CC65, Arg);
841 }
842
843
844
845 static void OptCfgPath (const char* Opt attribute ((unused)), const char* Arg)
846 /* Config file search path (linker) */
847 {
848     CmdAddArg2 (&LD65, "--cfg-path", Arg);
849 }
850
851
852
853 static void OptCheckStack (const char* Opt attribute ((unused)),
854                            const char* Arg attribute ((unused)))
855 /* Handle the --check-stack option */
856 {
857     CmdAddArg (&CC65, "--check-stack");
858 }
859
860
861
862 static void OptCodeLabel (const char* Opt attribute ((unused)), const char* Arg)
863 /* Handle the --code-label option */
864 {
865     CmdAddArg2 (&CO65, "--code-label", Arg);
866 }
867
868
869
870 static void OptCodeName (const char* Opt attribute ((unused)), const char* Arg)
871 /* Handle the --code-name option */
872 {
873     CmdAddArg2 (&CC65, "--code-name", Arg);
874     CmdAddArg2 (&CO65, "--code-name", Arg);
875 }
876
877
878
879 static void OptCodeSize (const char* Opt attribute ((unused)), const char* Arg)
880 /* Handle the --codesize option */
881 {
882     CmdAddArg2 (&CC65, "--codesize", Arg);
883 }
884
885
886
887 static void OptConfig (const char* Opt attribute ((unused)), const char* Arg)
888 /* Config file (linker) */
889 {
890     if (LinkerConfig) {
891         Error ("Cannot specify -C/--config twice");
892     }
893     LinkerConfig = Arg;
894 }
895
896
897
898 static void OptCPU (const char* Opt attribute ((unused)), const char* Arg)
899 /* Handle the --cpu option */
900 {
901     /* Add the cpu type to the assembler and compiler */
902     CmdAddArg2 (&CA65, "--cpu", Arg);
903     CmdAddArg2 (&CC65, "--cpu", Arg);
904 }
905
906
907
908 static void OptCreateDep (const char* Opt attribute ((unused)), const char* Arg)
909 /* Handle the --create-dep option */
910 {
911     /* Add the file name to the compiler */
912     CmdAddArg2 (&CC65, "--create-dep", Arg);
913
914     /* Remember the file name for the assembler */
915     DepName = Arg;
916 }
917
918
919
920 static void OptCreateFullDep (const char* Opt attribute ((unused)), const char* Arg)
921 /* Handle the --create-full-dep option */
922 {
923     /* Add the file name to the compiler */
924     CmdAddArg2 (&CC65, "--create-full-dep", Arg);
925
926     /* Remember the file name for the assembler */
927     FullDepName = Arg;
928 }
929
930
931
932 static void OptDataLabel (const char* Opt attribute ((unused)), const char* Arg)
933 /* Handle the --data-label option */
934 {
935     CmdAddArg2 (&CO65, "--data-label", Arg);
936 }
937
938
939
940 static void OptDataName (const char* Opt attribute ((unused)), const char* Arg)
941 /* Handle the --data-name option */
942 {
943     CmdAddArg2 (&CC65, "--data-name", Arg);
944     CmdAddArg2 (&CO65, "--data-name", Arg);
945 }
946
947
948
949 static void OptDebug (const char* Opt attribute ((unused)),
950                       const char* Arg attribute ((unused)))
951 /* Debug mode (compiler and cl65 utility) */
952 {
953     CmdAddArg (&CC65, "-d");
954     CmdAddArg (&CO65, "-d");
955     Debug = 1;
956 }
957
958
959
960 static void OptDebugInfo (const char* Opt attribute ((unused)),
961                           const char* Arg attribute ((unused)))
962 /* Debug Info - add to compiler and assembler */
963 {
964     CmdAddArg (&CC65, "-g");
965     CmdAddArg (&CA65, "-g");
966     CmdAddArg (&CO65, "-g");
967 }
968
969
970
971 static void OptFeature (const char* Opt attribute ((unused)), const char* Arg)
972 /* Emulation features for the assembler */
973 {
974     CmdAddArg2 (&CA65, "--feature", Arg);
975 }
976
977
978
979 static void OptForceImport (const char* Opt attribute ((unused)), const char* Arg)
980 /* Emulation features for the assembler */
981 {
982     CmdAddArg2 (&LD65, "-u", Arg);
983 }
984
985
986
987 static void OptHelp (const char* Opt attribute ((unused)),
988                      const char* Arg attribute ((unused)))
989 /* Print help - cl65 */
990 {
991     Usage ();
992     exit (EXIT_SUCCESS);
993 }
994
995
996
997 static void OptIncludeDir (const char* Opt attribute ((unused)), const char* Arg)
998 /* Include directory (compiler) */
999 {
1000     CmdAddArg2 (&CC65, "-I", Arg);
1001 }
1002
1003
1004
1005 static void OptLdArgs (const char* Opt attribute ((unused)), const char* Arg)
1006 /* Pass arguments to the linker */
1007 {
1008     CmdAddArgList (&LD65, Arg);
1009 }
1010
1011
1012
1013 static void OptLib (const char* Opt attribute ((unused)), const char* Arg)
1014 /* Library file follows (linker) */
1015 {
1016     CmdAddArg2 (&LD65, "--lib", Arg);
1017 }
1018
1019
1020
1021 static void OptLibPath (const char* Opt attribute ((unused)), const char* Arg)
1022 /* Library search path (linker) */
1023 {
1024     CmdAddArg2 (&LD65, "--lib-path", Arg);
1025 }
1026
1027
1028
1029 static void OptListBytes (const char* Opt attribute ((unused)), const char* Arg)
1030 /* Set the maximum number of bytes per asm listing line */
1031 {
1032     CmdAddArg2 (&CA65, "--list-bytes", Arg);
1033 }
1034
1035
1036
1037 static void OptListing (const char* Opt attribute ((unused)), const char* Arg)
1038 /* Create an assembler listing */
1039 {
1040     CmdAddArg2 (&CA65, "-l", Arg);
1041 }
1042
1043
1044
1045 static void OptListTargets (const char* Opt attribute ((unused)),
1046                             const char* Arg attribute ((unused)))
1047 /* List all targets */
1048 {
1049     target_t T;
1050
1051     /* List the targets */
1052     for (T = TGT_NONE; T < TGT_COUNT; ++T) {
1053         printf ("%s\n", GetTargetName (T));
1054     }
1055
1056     /* Terminate */
1057     exit (EXIT_SUCCESS);
1058 }
1059
1060
1061
1062 static void OptMapFile (const char* Opt attribute ((unused)), const char* Arg)
1063 /* Create a map file */
1064 {
1065     /* Create a map file (linker) */
1066     CmdAddArg2 (&LD65, "-m", Arg);
1067 }
1068
1069
1070
1071 static void OptMemoryModel (const char* Opt attribute ((unused)), const char* Arg)
1072 /* Set the memory model */
1073 {
1074     mmodel_t MemoryModel = FindMemoryModel (Arg);
1075     if (MemoryModel == MMODEL_UNKNOWN) {
1076         Error ("Unknown memory model: %s", Arg);
1077     } else if (MemoryModel == MMODEL_HUGE) {
1078         Error ("Unsupported memory model: %s", Arg);
1079     } else {
1080         CmdAddArg2 (&CA65, "-mm", Arg);
1081         CmdAddArg2 (&CC65, "-mm", Arg);
1082     }
1083 }
1084
1085
1086
1087 static void OptModule (const char* Opt attribute ((unused)),
1088                        const char* Arg attribute ((unused)))
1089 /* Link as a module */
1090 {
1091     Module = 1;
1092 }
1093
1094
1095
1096 static void OptModuleId (const char* Opt attribute ((unused)), const char* Arg)
1097 /* Specify a module if for the linker */
1098 {
1099     /* Pass it straight to the linker */
1100     CmdAddArg2 (&LD65, "--module-id", Arg);
1101 }
1102
1103
1104
1105 static void OptO65Model (const char* Opt attribute ((unused)), const char* Arg)
1106 /* Handle the --o65-model option */
1107 {
1108     CmdAddArg2 (&CO65, "-m", Arg);
1109 }
1110
1111
1112
1113 static void OptObj (const char* Opt attribute ((unused)), const char* Arg)
1114 /* Object file follows (linker) */
1115 {
1116     CmdAddArg2 (&LD65, "--obj", Arg);
1117 }
1118
1119
1120
1121 static void OptObjPath (const char* Opt attribute ((unused)), const char* Arg)
1122 /* Object file search path (linker) */
1123 {
1124     CmdAddArg2 (&LD65, "--obj-path", Arg);
1125 }
1126
1127
1128
1129 static void OptRegisterSpace (const char* Opt attribute ((unused)), const char* Arg)
1130 /* Handle the --register-space option */
1131 {
1132     CmdAddArg2 (&CC65, "--register-space", Arg);
1133 }
1134
1135
1136
1137 static void OptRegisterVars (const char* Opt attribute ((unused)),
1138                              const char* Arg attribute ((unused)))
1139 /* Handle the --register-vars option */
1140 {
1141     CmdAddArg (&CC65, "-r");
1142 }
1143
1144
1145
1146 static void OptRodataName (const char* Opt attribute ((unused)), const char* Arg)
1147 /* Handle the --rodata-name option */
1148 {
1149     CmdAddArg2 (&CC65, "--rodata-name", Arg);
1150 }
1151
1152
1153
1154 static void OptSignedChars (const char* Opt attribute ((unused)),
1155                             const char* Arg attribute ((unused)))
1156 /* Make default characters signed */
1157 {
1158     CmdAddArg (&CC65, "-j");
1159 }
1160
1161
1162
1163 static void OptStandard (const char* Opt attribute ((unused)), const char* Arg)
1164 /* Set the language standard */
1165 {
1166     CmdAddArg2 (&CC65, "--standard", Arg);
1167 }
1168
1169
1170
1171 static void OptStartAddr (const char* Opt attribute ((unused)), const char* Arg)
1172 /* Set the default start address */
1173 {
1174     CmdAddArg2 (&LD65, "-S", Arg);
1175 }
1176
1177
1178
1179 static void OptStaticLocals (const char* Opt attribute ((unused)),
1180                              const char* Arg attribute ((unused)))
1181 /* Place local variables in static storage */
1182 {
1183     CmdAddArg (&CC65, "-Cl");
1184 }
1185
1186
1187
1188 static void OptTarget (const char* Opt attribute ((unused)), const char* Arg)
1189 /* Set the target system */
1190 {
1191     Target = FindTarget (Arg);
1192     if (Target == TGT_UNKNOWN) {
1193         Error ("No such target system: `%s'", Arg);
1194     } else if (Target == TGT_MODULE) {
1195         Error ("Cannot use `module' as target, use --module instead");
1196     }
1197 }
1198
1199
1200
1201 static void OptVerbose (const char* Opt attribute ((unused)),
1202                         const char* Arg attribute ((unused)))
1203 /* Verbose mode (compiler, assembler, linker) */
1204 {
1205     CmdAddArg (&CC65, "-v");
1206     CmdAddArg (&CA65, "-v");
1207     CmdAddArg (&CO65, "-v");
1208     CmdAddArg (&LD65, "-v");
1209 }
1210
1211
1212
1213 static void OptVersion (const char* Opt attribute ((unused)),
1214                         const char* Arg attribute ((unused)))
1215 /* Print version number */
1216 {
1217     fprintf (stderr, "cl65 V%s\n", GetVersionAsString ());
1218 }
1219
1220
1221
1222 static void OptZeropageLabel (const char* Opt attribute ((unused)), const char* Arg)
1223 /* Handle the --zeropage-label option */
1224 {
1225     CmdAddArg2 (&CO65, "--zeropage-label", Arg);
1226 }
1227
1228
1229
1230 static void OptZeropageName (const char* Opt attribute ((unused)), const char* Arg)
1231 /* Handle the --zeropage-name option */
1232 {
1233     CmdAddArg2 (&CO65, "--zeropage-name", Arg);
1234 }
1235
1236
1237
1238 int main (int argc, char* argv [])
1239 /* Utility main program */
1240 {
1241     /* Program long options */
1242     static const LongOpt OptTab[] = {
1243         { "--add-source",       0,      OptAddSource            },
1244         { "--asm-args",         1,      OptAsmArgs              },
1245         { "--asm-define",       1,      OptAsmDefine            },
1246         { "--asm-include-dir",  1,      OptAsmIncludeDir        },
1247         { "--bin-include-dir",  1,      OptBinIncludeDir        },
1248         { "--bss-label",        1,      OptBssLabel             },
1249         { "--bss-name",         1,      OptBssName              },
1250         { "--cc-args",          1,      OptCCArgs               },
1251         { "--cfg-path",         1,      OptCfgPath              },
1252         { "--check-stack",      0,      OptCheckStack           },
1253         { "--code-label",       1,      OptCodeLabel            },
1254         { "--code-name",        1,      OptCodeName             },
1255         { "--codesize",         1,      OptCodeSize             },
1256         { "--config",           1,      OptConfig               },
1257         { "--cpu",              1,      OptCPU                  },
1258         { "--create-dep",       1,      OptCreateDep            },
1259         { "--create-full-dep",  1,      OptCreateFullDep        },
1260         { "--data-label",       1,      OptDataLabel            },
1261         { "--data-name",        1,      OptDataName             },
1262         { "--debug",            0,      OptDebug                },
1263         { "--debug-info",       0,      OptDebugInfo            },
1264         { "--feature",          1,      OptFeature              },
1265         { "--force-import",     1,      OptForceImport          },
1266         { "--help",             0,      OptHelp                 },
1267         { "--include-dir",      1,      OptIncludeDir           },
1268         { "--ld-args",          1,      OptLdArgs               },
1269         { "--lib",              1,      OptLib                  },
1270         { "--lib-path",         1,      OptLibPath              },
1271         { "--list-targets",     0,      OptListTargets          },
1272         { "--listing",          1,      OptListing              },
1273         { "--list-bytes",       1,      OptListBytes            },
1274         { "--mapfile",          1,      OptMapFile              },
1275         { "--memory-model",     1,      OptMemoryModel          },
1276         { "--module",           0,      OptModule               },
1277         { "--module-id",        1,      OptModuleId             },
1278         { "--o65-model",        1,      OptO65Model             },
1279         { "--obj",              1,      OptObj                  },
1280         { "--obj-path",         1,      OptObjPath              },
1281         { "--register-space",   1,      OptRegisterSpace        },
1282         { "--register-vars",    0,      OptRegisterVars         },
1283         { "--rodata-name",      1,      OptRodataName           },
1284         { "--signed-chars",     0,      OptSignedChars          },
1285         { "--standard",         1,      OptStandard             },
1286         { "--start-addr",       1,      OptStartAddr            },
1287         { "--static-locals",    0,      OptStaticLocals         },
1288         { "--target",           1,      OptTarget               },
1289         { "--verbose",          0,      OptVerbose              },
1290         { "--version",          0,      OptVersion              },
1291         { "--zeropage-label",   1,      OptZeropageLabel        },
1292         { "--zeropage-name",    1,      OptZeropageName         },
1293     };
1294
1295     char* CmdPath;
1296     unsigned I;
1297
1298     /* Initialize the cmdline module */
1299     InitCmdLine (&argc, &argv, "cl65");
1300
1301     /* Initialize the command descriptors */
1302     if (argc == 0) {
1303         CmdPath = xstrdup ("");
1304     } else {
1305         char* Ptr;
1306         CmdPath = xstrdup (argv[0]);
1307         Ptr = strrchr (CmdPath, '/');
1308         if (Ptr == 0) {
1309             Ptr = strrchr (CmdPath, '\\');
1310         }
1311         if (Ptr == 0) {
1312             *CmdPath = '\0';
1313         } else {
1314             *(Ptr + 1) = '\0';
1315         }
1316     }
1317     CmdInit (&CC65, CmdPath, "cc65");
1318     CmdInit (&CA65, CmdPath, "ca65");
1319     CmdInit (&CO65, CmdPath, "co65");
1320     CmdInit (&LD65, CmdPath, "ld65");
1321     CmdInit (&GRC,  CmdPath, "grc65");
1322     xfree (CmdPath);
1323
1324     /* Our default target is the C64 instead of "none" */
1325     Target = TGT_C64;
1326
1327     /* Check the parameters */
1328     I = 1;
1329     while (I < ArgCount) {
1330
1331         /* Get the argument */
1332         const char* Arg = ArgVec[I];
1333
1334         /* Check for an option */
1335         if (Arg [0] == '-') {
1336
1337             switch (Arg [1]) {
1338
1339                 case '-':
1340                     LongOption (&I, OptTab, sizeof(OptTab)/sizeof(OptTab[0]));
1341                     break;
1342
1343                 case 'C':
1344                     if (Arg[2] == 'l' && Arg[3] == '\0') {
1345                         /* Make local variables static */
1346                         OptStaticLocals (Arg, 0);
1347                     } else {
1348                         /* Specify linker config file */
1349                         OptConfig (Arg, GetArg (&I, 2));
1350                     }
1351                     break;
1352
1353                 case 'D':
1354                     /* Define a preprocessor symbol (compiler) */
1355                     CmdAddArg2 (&CC65, "-D", GetArg (&I, 2));
1356                     break;
1357
1358                 case 'I':
1359                     /* Include directory (compiler) */
1360                     OptIncludeDir (Arg, GetArg (&I, 2));
1361                     break;
1362
1363                 case 'L':
1364                     if (Arg[2] == 'n' && Arg[3] == '\0') {
1365                         /* VICE label file (linker) */
1366                         CmdAddArg2 (&LD65, "-Ln", GetArg (&I, 3));
1367                     } else {
1368                         /* Library search path (linker) */
1369                         OptLibPath (Arg, GetArg (&I, 2));
1370                     }
1371                     break;
1372
1373                 case 'O':
1374                     /* Optimize code (compiler, also covers -Oi and others) */
1375                     CmdAddArg (&CC65, Arg);
1376                     break;
1377
1378                 case 'S':
1379                     /* Dont assemble and link the created files */
1380                     DoAssemble = 0;
1381                     DoLink     = 0;
1382                     break;
1383
1384                 case 'T':
1385                     /* Include source as comment (compiler) */
1386                     OptAddSource (Arg, 0);
1387                     break;
1388
1389                 case 'V':
1390                     /* Print version number */
1391                     OptVersion (Arg, 0);
1392                     break;
1393
1394                 case 'W':
1395                     if (Arg[2] == 'a' && Arg[3] == '\0') {
1396                         /* -Wa: Pass options to assembler */
1397                         OptAsmArgs (Arg, GetArg (&I, 3));
1398                     } else if (Arg[2] == 'c' && Arg[3] == '\0') {
1399                         /* -Wc: Pass options to compiler */
1400                         OptCCArgs (Arg, GetArg (&I, 3));
1401                     } else if (Arg[2] == 'l' && Arg[3] == '\0') {
1402                         /* -Wl: Pass options to linker */
1403                         OptLdArgs (Arg, GetArg (&I, 3));
1404                     } else {
1405                         /* Anything else: Suppress warnings (compiler) */
1406                         CmdAddArg2 (&CC65, "-W", GetArg (&I, 2));
1407                     }
1408                     break;
1409
1410                 case 'c':
1411                     /* Don't link the resulting files */
1412                     DoLink = 0;
1413                     break;
1414
1415                 case 'd':
1416                     /* Debug mode (compiler) */
1417                     OptDebug (Arg, 0);
1418                     break;
1419
1420                 case 'g':
1421                     /* Debugging - add to compiler and assembler */
1422                     OptDebugInfo (Arg, 0);
1423                     break;
1424
1425                 case 'h':
1426                 case '?':
1427                     /* Print help - cl65 */
1428                     OptHelp (Arg, 0);
1429                     break;
1430
1431                 case 'j':
1432                     /* Default characters are signed */
1433                     OptSignedChars (Arg, 0);
1434                     break;
1435
1436                 case 'l':
1437                     /* Create an assembler listing */
1438                     OptListing (Arg, GetArg (&I, 2));
1439                     break;
1440
1441                 case 'm':
1442                     /* Create a map file (linker) */
1443                     OptMapFile (Arg, GetArg (&I, 2));
1444                     break;
1445
1446                 case 'o':
1447                     /* Name the output file */
1448                     OutputName = GetArg (&I, 2);
1449                     break;
1450
1451                 case 'r':
1452                     /* Enable register variables */
1453                     OptRegisterVars (Arg, 0);
1454                     break;
1455
1456                 case 't':
1457                     /* Set target system - compiler, assembler and linker */
1458                     OptTarget (Arg, GetArg (&I, 2));
1459                     break;
1460
1461                 case 'u':
1462                     /* Force an import (linker) */
1463                     OptForceImport (Arg, GetArg (&I, 2));
1464                     break;
1465
1466                 case 'v':
1467                     if (Arg [2] == 'm') {
1468                         /* Verbose map file (linker) */
1469                         CmdAddArg (&LD65, "-vm");
1470                     } else {
1471                         /* Verbose mode (compiler, assembler, linker) */
1472                         OptVerbose (Arg, 0);
1473                     }
1474                     break;
1475
1476                 default:
1477                     UnknownOption (Arg);
1478             }
1479         } else {
1480
1481             /* Remember the first file name */
1482             if (FirstInput == 0) {
1483                 FirstInput = Arg;
1484             }
1485
1486             /* Determine the file type by the extension */
1487             switch (GetFileType (Arg)) {
1488
1489                 case FILETYPE_C:
1490                     /* Compile the file */
1491                     Compile (Arg);
1492                     break;
1493
1494                 case FILETYPE_ASM:
1495                     /* Assemble the file */
1496                     if (DoAssemble) {
1497                         Assemble (Arg);
1498                     }
1499                     break;
1500
1501                 case FILETYPE_OBJ:
1502                 case FILETYPE_LIB:
1503                     /* Add to the linker files */
1504                     CmdAddFile (&LD65, Arg);
1505                     break;
1506
1507                 case FILETYPE_GR:
1508                     /* Add to the resource compiler files */
1509                     CompileRes (Arg);
1510                     break;
1511
1512                 case FILETYPE_O65:
1513                     /* Add the the object file converter files */
1514                     ConvertO65 (Arg);
1515                     break;
1516
1517                 default:
1518                     Error ("Don't know what to do with `%s'", Arg);
1519
1520             }
1521
1522         }
1523
1524         /* Next argument */
1525         ++I;
1526     }
1527
1528     /* Check if we had any input files */
1529     if (FirstInput == 0) {
1530         Warning ("No input files");
1531     }
1532
1533     /* Link the given files if requested and if we have any */
1534     if (DoLink && LD65.FileCount > 0) {
1535         Link ();
1536     }
1537
1538     /* Return an apropriate exit code */
1539     return EXIT_SUCCESS;
1540 }