]> git.sur5r.net Git - cc65/blob - cl65/main.c
Fixed _textcolor definition.
[cc65] / 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-2000 Ullrich von Bassewitz                                       */
10 /*               Wacholderweg 14                                             */
11 /*               D-70597 Stuttgart                                           */
12 /* EMail:        uz@musoftware.de                                            */
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 #include <stdio.h>
37 #include <stdlib.h>
38 #include <string.h>
39 #include <ctype.h>
40 #include <errno.h>
41 #ifdef __WATCOMC__
42 #  include <process.h>          /* DOS, OS/2 and Windows */
43 #else
44 #  include "spawn.h"            /* All others */
45 #endif
46
47 #include "../common/version.h"
48
49 #include "global.h"
50 #include "error.h"
51 #include "mem.h"
52
53
54
55 /*****************************************************************************/
56 /*                                   Data                                    */
57 /*****************************************************************************/
58
59
60
61 /* Struct that describes a command */
62 typedef struct CmdDesc_ CmdDesc;
63 struct CmdDesc_ {
64     char*       Name;           /* The command name */
65
66     unsigned    ArgCount;       /* Count of arguments */
67     unsigned    ArgMax;         /* Maximum count of arguments */
68     char**      Args;           /* The arguments */
69
70     unsigned    FileCount;      /* Count of files to translate */
71     unsigned    FileMax;        /* Maximum count of files */
72     char**      Files;          /* The files */
73 };
74
75 /* Command descriptors for the different programs */
76 static CmdDesc CC65 = { 0, 0, 0, 0, 0, 0, 0 };
77 static CmdDesc CA65 = { 0, 0, 0, 0, 0, 0, 0 };
78 static CmdDesc LD65 = { 0, 0, 0, 0, 0, 0, 0 };
79
80 /* File types */
81 enum {
82     FILETYPE_UNKNOWN,
83     FILETYPE_C,
84     FILETYPE_ASM,
85     FILETYPE_OBJ,
86     FILETYPE_LIB
87 };
88
89 /* Default file type, used if type unknown */
90 static unsigned DefaultFileType = FILETYPE_UNKNOWN;
91
92 /* Variables controlling the steps we're doing */
93 static int DontLink     = 0;
94 static int DontAssemble = 0;
95
96 /* The name of the output file, NULL if none given */
97 static const char* OutputName = 0;
98
99 /* The name of the linker configuration file if given */
100 static const char* LinkerConfig = 0;
101
102 /* The name of the first input file. This will be used to construct the
103  * executable file name if no explicit name is given.
104  */
105 static const char* FirstInput = 0;
106
107 /* The target system */
108 enum {
109     TGT_UNKNOWN = -1,
110     TGT_NONE,
111     TGT_FIRSTREAL,
112     TGT_ATARI = TGT_FIRSTREAL,
113     TGT_C64,
114     TGT_C128,
115     TGT_ACE,
116     TGT_PLUS4,
117     TGT_CBM610,
118     TGT_PET,
119     TGT_NES,
120     TGT_APPLE2,
121     TGT_GEOS,
122     TGT_COUNT
123 } Target = TGT_UNKNOWN;
124
125 /* Names of the target systems sorted by target name */
126 static const char* TargetNames [] = {
127     "none",
128     "atari",
129     "c64",
130     "c128",
131     "ace",
132     "plus4",
133     "cbm610",
134     "pet",
135     "nes",
136     "apple2",
137     "geos",
138 };
139
140 /* Name of the crt0 object file and the runtime library */
141 static char* TargetCRT0 = 0;
142 static char* TargetLib  = 0;
143
144
145
146 /*****************************************************************************/
147 /*                              String handling                              */
148 /*****************************************************************************/
149
150
151
152 static const char* FindExt (const char* Name)
153 /* Return a pointer to the file extension in Name or NULL if there is none */
154 {
155     const char* S;
156
157     /* Get the length of the name */
158     unsigned Len = strlen (Name);
159     if (Len < 2) {
160         return 0;
161     }
162
163     /* Get a pointer to the last character */
164     S = Name + Len - 1;
165
166     /* Search for the dot, beware of subdirectories */
167     while (S >= Name && *S != '.' && *S != '\\' && *S != '/') {
168         --S;
169     }
170
171     /* Did we find an extension? */
172     if (*S == '.') {
173         return S;
174     } else {
175         return 0;
176     }
177 }
178
179
180
181 static char* ForceExt (const char* Name, const char* Ext)
182 /* Return a new filename with the new extension */
183 {
184     char* Out;
185     const char* P = FindExt (Name);
186     if (P == 0) {
187         /* No dot, add the extension */
188         Out = Xmalloc (strlen (Name) + strlen (Ext) + 1);
189         strcpy (Out, Name);
190         strcat (Out, Ext);
191     } else {
192         Out = Xmalloc (P - Name + strlen (Ext) + 1);
193         memcpy (Out, Name, P - Name);
194         strcpy (Out + (P - Name), Ext);
195     }
196     return Out;
197 }
198
199
200
201 /*****************************************************************************/
202 /*                           Determine a file type                           */
203 /*****************************************************************************/
204
205
206
207 static unsigned GetFileType (const char* File)
208 /* Determine the type of the given file */
209 {
210     /* Table mapping extensions to file types */
211     static const struct {
212         const char*     Ext;
213         unsigned        Type;
214     } FileTypes [] = {
215         {   ".c",       FILETYPE_C      },
216         {   ".s",       FILETYPE_ASM    },
217         {   ".asm",     FILETYPE_ASM    },
218         {   ".o",       FILETYPE_OBJ    },
219         {   ".obj",     FILETYPE_OBJ    },
220         {   ".a",       FILETYPE_LIB    },
221         {   ".lib",     FILETYPE_LIB    },
222     };
223
224     unsigned I;
225
226     /* Determine the file type by the extension */
227     const char* Ext = FindExt (File);
228
229     /* Do we have an extension? */
230     if (Ext == 0) {
231         return DefaultFileType;
232     }
233
234     /* Check for known extensions */
235     for (I = 0; I < sizeof (FileTypes) / sizeof (FileTypes [0]); ++I) {
236         if (strcmp (FileTypes [I].Ext, Ext) == 0) {
237             /* Found */
238             return FileTypes [I].Type;
239         }
240     }
241
242     /* Not found, return the default */
243     return DefaultFileType;
244 }
245
246
247
248 /*****************************************************************************/
249 /*                        Command structure handling                         */
250 /*****************************************************************************/
251
252
253
254 static void CmdAddArg (CmdDesc* Cmd, const char* Arg)
255 /* Add a new argument to the command */
256 {
257     /* Expand the argument vector if needed */
258     if (Cmd->ArgCount == Cmd->ArgMax) {
259         unsigned NewMax  = Cmd->ArgMax + 10;
260         char**   NewArgs = Xmalloc (NewMax * sizeof (char*));
261         memcpy (NewArgs, Cmd->Args, Cmd->ArgMax * sizeof (char*));
262         Xfree (Cmd->Args);
263         Cmd->Args   = NewArgs;
264         Cmd->ArgMax = NewMax;
265     }
266
267     /* Add a copy of the new argument, allow a NULL pointer */
268     if (Arg) {
269         Cmd->Args [Cmd->ArgCount++] = StrDup (Arg);
270     } else {
271         Cmd->Args [Cmd->ArgCount++] = 0;
272     }
273 }
274
275
276
277 static void CmdDelArgs (CmdDesc* Cmd, unsigned LastValid)
278 /* Remove all arguments with an index greater than LastValid */
279 {
280     while (Cmd->ArgCount > LastValid) {
281         Cmd->ArgCount--;
282         Xfree (Cmd->Args [Cmd->ArgCount]);
283         Cmd->Args [Cmd->ArgCount] = 0;
284     }
285 }
286
287
288
289 static void CmdAddFile (CmdDesc* Cmd, const char* File)
290 /* Add a new file to the command */
291 {
292     /* Expand the file vector if needed */
293     if (Cmd->FileCount == Cmd->FileMax) {
294         unsigned NewMax   = Cmd->FileMax + 10;
295         char**   NewFiles = Xmalloc (NewMax * sizeof (char*));
296         memcpy (NewFiles, Cmd->Files, Cmd->FileMax * sizeof (char*));
297         Xfree (Cmd->Files);
298         Cmd->Files   = NewFiles;
299         Cmd->FileMax = NewMax;
300     }
301
302     /* Add a copy of the file name, allow a NULL pointer */
303     if (File) {
304         Cmd->Files [Cmd->FileCount++] = StrDup (File);
305     } else {
306         Cmd->Files [Cmd->FileCount++] = 0;
307     }
308 }
309
310
311
312 static void CmdInit (CmdDesc* Cmd, const char* Path)
313 /* Initialize the command using the given path to the executable */
314 {
315     /* Remember the command */
316     Cmd->Name = StrDup (Path);
317
318     /* Use the command name as first argument */
319     CmdAddArg (Cmd, Path);
320 }
321
322
323
324 static void CmdSetOutput (CmdDesc* Cmd, const char* File)
325 /* Set the output file in a command desc */
326 {
327     CmdAddArg (Cmd, "-o");
328     CmdAddArg (Cmd, File);
329 }
330
331
332
333 static void CmdSetTarget (CmdDesc* Cmd, int Target)
334 /* Set the output file in a command desc */
335 {
336     if (Target == TGT_UNKNOWN) {
337         /* Use C64 as default */
338         Target = TGT_C64;
339     }
340
341     if (Target != TGT_NONE) {
342         CmdAddArg (Cmd, "-t");
343         CmdAddArg (Cmd, TargetNames[Target]);
344     }
345 }
346
347
348
349 /*****************************************************************************/
350 /*                              Target handling                              */
351 /*****************************************************************************/
352
353
354
355 static int MapTarget (const char* Name)
356 /* Map a target name to a system code. Abort on errors */
357 {
358     int I;
359
360     /* Check for a numeric target */
361     if (isdigit (*Name)) {
362         int Target = atoi (Name);
363         if (Target >= 0 && Target < TGT_COUNT) {
364             return Target;
365         }
366     }
367
368     /* Check for a target string */
369     for (I = 0; I < TGT_COUNT; ++I) {
370         if (strcmp (TargetNames [I], Name) == 0) {
371             return I;
372         }
373     }
374
375     /* Not found */
376     Error ("No such target system: `%s'", Name);
377     return -1;  /* Not reached */
378 }
379
380
381
382 static void SetTargetFiles (void)
383 /* Set the target system files */
384 {
385     /* Determine the names of the default startup and library file */
386     if (Target >= TGT_FIRSTREAL) {
387
388         /* Get a pointer to the system name and its length */
389         const char* TargetName = TargetNames [Target];
390         unsigned    TargetNameLen = strlen (TargetName);
391
392         /* Set the startup file */
393         TargetCRT0 = Xmalloc (TargetNameLen + 2 + 1);
394         strcpy (TargetCRT0, TargetName);
395         strcat (TargetCRT0, ".o");
396
397         /* Set the library file */
398         TargetLib = Xmalloc (TargetNameLen + 4 + 1);
399         strcpy (TargetLib, TargetName);
400         strcat (TargetLib, ".lib");
401
402     }
403 }
404
405
406
407 static void SetTargetByName (const char* Name)
408 /* Set the target system by name */
409 {
410     Target = MapTarget (Name);
411     SetTargetFiles ();
412 }
413
414
415
416 /*****************************************************************************/
417 /*                               Subprocesses                                */
418 /*****************************************************************************/
419
420
421
422 static void ExecProgram (CmdDesc* Cmd)
423 /* Execute a subprocess with the given name/parameters. Exit on errors. */
424 {
425     /* Call the program */
426     int Status = spawnvp (P_WAIT, Cmd->Name, Cmd->Args);
427
428     /* Check the result code */
429     if (Status < 0) {
430         /* Error executing the program */
431         Error ("Cannot execute `%s': %s", Cmd->Name, strerror (errno));
432     } else if (Status != 0) {
433         /* Called program had an error */
434         exit (Status);
435     }
436 }
437
438
439
440 static void Link (void)
441 /* Link the resulting executable */
442 {
443     unsigned I;
444
445     /* If we have a linker config file given, set the linker config file.
446      * Otherwise set the target system.
447      */
448     if (LinkerConfig) {
449         CmdAddArg (&LD65, "-C");
450         CmdAddArg (&LD65, LinkerConfig);
451     } else {
452         if (Target == TGT_UNKNOWN) {
453             /* Use c64 instead */
454             Target = TGT_C64;
455         }
456         SetTargetFiles ();
457         CmdSetTarget (&LD65, Target);
458     }
459
460     /* Since linking is always the final step, if we have an output file name
461      * given, set it here. If we don't have an explicit output name given,
462      * try to build one from the name of the first input file.
463      */
464     if (OutputName) {
465
466         CmdAddArg (&LD65, "-o");
467         CmdAddArg (&LD65, OutputName);
468
469     } else if (FirstInput && FindExt (FirstInput)) {  /* Only if ext present! */
470
471         char* Output = ForceExt (FirstInput, "");
472         CmdAddArg (&LD65, "-o");
473         CmdAddArg (&LD65, Output);
474         Xfree (Output);
475
476     }
477
478     /* If we have a startup file, add its name as a parameter */
479     if (TargetCRT0) {
480         CmdAddArg (&LD65, TargetCRT0);
481     }
482
483     /* Add all object files as parameters */
484     for (I = 0; I < LD65.FileCount; ++I) {
485         CmdAddArg (&LD65, LD65.Files [I]);
486     }
487
488     /* Add the system runtime library */
489     if (TargetLib) {
490         CmdAddArg (&LD65, TargetLib);
491     }
492
493     /* Terminate the argument list with a NULL pointer */
494     CmdAddArg (&LD65, 0);
495
496     /* Call the linker */
497     ExecProgram (&LD65);
498 }
499
500
501
502 static void Assemble (const char* File)
503 /* Assemble the given file */
504 {
505     /* Remember the current assembler argument count */
506     unsigned ArgCount = CA65.ArgCount;
507
508     /* If we won't link, this is the final step. In this case, set the
509      * output name.
510      */
511     if (DontLink && OutputName) {
512         CmdSetOutput (&CA65, OutputName);
513     } else {
514         /* The object file name will be the name of the source file
515          * with .s replaced by ".o". Add this file to the list of
516          * linker files.
517          */
518         char* ObjName = ForceExt (File, ".o");
519         CmdAddFile (&LD65, ObjName);
520         Xfree (ObjName);
521     }
522
523     /* Add the file as argument for the assembler */
524     CmdAddArg (&CA65, File);
525
526     /* Add a NULL pointer to terminate the argument list */
527     CmdAddArg (&CA65, 0);
528
529     /* Run the assembler */
530     ExecProgram (&CA65);
531
532     /* Remove the excess arguments */
533     CmdDelArgs (&CA65, ArgCount);
534 }
535
536
537
538 static void Compile (const char* File)
539 /* Compile the given file */
540 {
541     char* AsmName = 0;
542
543     /* Remember the current assembler argument count */
544     unsigned ArgCount = CC65.ArgCount;
545
546     /* Set the target system */
547     CmdSetTarget (&CC65, Target);
548
549     /* If we won't link, this is the final step. In this case, set the
550      * output name.
551      */
552     if (DontAssemble && OutputName) {
553         CmdSetOutput (&CC65, OutputName);
554     } else {
555         /* The assembler file name will be the name of the source file
556          * with .c replaced by ".s".
557          */
558         AsmName = ForceExt (File, ".s");
559     }
560
561     /* Add the file as argument for the compiler */
562     CmdAddArg (&CC65, File);
563
564     /* Add a NULL pointer to terminate the argument list */
565     CmdAddArg (&CC65, 0);
566
567     /* Run the compiler */
568     ExecProgram (&CC65);
569
570     /* Remove the excess arguments */
571     CmdDelArgs (&CC65, ArgCount);
572
573     /* If this is not the final step, assemble the generated file, then
574      * remove it
575      */
576     if (!DontAssemble) {
577         Assemble (AsmName);
578         if (remove (AsmName) < 0) {
579             Warning ("Cannot remove temporary file `%s': %s",
580                      AsmName, strerror (errno));
581         }
582         Xfree (AsmName);
583     }
584 }
585
586
587
588 /*****************************************************************************/
589 /*                                   Code                                    */
590 /*****************************************************************************/
591
592
593
594 static void Usage (void)
595 /* Print usage information and exit */
596 {
597     fprintf (stderr,
598              "Usage: %s [options] file\n"
599              "Short options:\n"
600              "  -A\t\t\tStrict ANSI mode\n"
601              "  -C name\t\tUse linker config file\n"
602              "  -Cl\t\t\tMake local variables static\n"
603              "  -D sym[=defn]\t\tDefine a preprocessor symbol\n"
604              "  -I dir\t\tSet a compiler include directory path\n"
605              "  -Ln name\t\tCreate a VICE label file\n"
606              "  -O\t\t\tOptimize code\n"
607              "  -Oi\t\t\tOptimize code, inline functions\n"
608              "  -Or\t\t\tOptimize code, honour the register keyword\n"
609              "  -Os\t\t\tOptimize code, inline known C funtions\n"
610              "  -S\t\t\tCompile but don't assemble and link\n"
611              "  -V\t\t\tPrint the version number\n"
612              "  -W\t\t\tSuppress warnings\n"
613              "  -c\t\t\tCompiler and assemble but don't link\n"
614              "  -d\t\t\tDebug mode\n"
615              "  -g\t\t\tAdd debug info\n"
616              "  -h\t\t\tHelp (this text)\n"
617              "  -m name\t\tCreate a map file\n"
618              "  -o name\t\tName the output file\n"
619              "  -t sys\t\tSet the target system\n"
620              "  -v\t\t\tVerbose mode\n"
621              "  -vm\t\t\tVerbose map file\n"
622              "\n"
623              "Long options:\n"
624              "  --ansi\t\tStrict ANSI mode\n"
625              "  --asm-include-dir dir\tSet an assembler include directory\n"
626              "  --debug\t\tDebug mode\n"
627              "  --debug-info\t\tAdd debug info\n"
628              "  --help\t\tHelp (this text)\n"
629              "  --include-dir dir\tSet a compiler include directory path\n"
630              "  --version\t\tPrint the version number\n"
631              "  --target sys\t\tSet the target system\n"
632              "  --verbose\t\tVerbose mode\n",
633              ProgName);
634 }
635
636
637
638 static const char* GetArg (int* ArgNum, char* argv [], unsigned Len)
639 /* Get an option argument */
640 {
641     const char* Arg = argv [*ArgNum];
642     if (Arg [Len] != '\0') {
643         /* Argument appended */
644         return Arg + Len;
645     } else {
646         /* Separate argument */
647         Arg = argv [*ArgNum + 1];
648         if (Arg == 0) {
649             /* End of arguments */
650             fprintf (stderr, "Option requires an argument: %s\n", argv [*ArgNum]);
651             exit (EXIT_FAILURE);
652         }
653         ++(*ArgNum);
654         return Arg;
655     }
656 }
657
658
659
660 static void UnknownOption (const char* Arg)
661 /* Print an error about a wrong argument */
662 {
663     Error ("Unknown option: `%s', use -h for help", Arg);
664 }
665
666
667
668 static void NeedArg (const char* Arg)
669 /* Print an error about a missing option argument and exit. */
670 {
671     Error ("Option requires an argument: %s\n", Arg);
672 }
673
674
675
676 static void OptAnsi (const char* Opt)
677 /* Strict ANSI mode (compiler) */
678 {
679     CmdAddArg (&CC65, "-A");
680 }
681
682
683
684 static void OptAsmIncludeDir (const char* Opt, const char* Arg)
685 /* Include directory (assembler) */
686 {
687     if (Arg == 0) {
688         NeedArg (Opt);
689     }
690     CmdAddArg (&CA65, "-I");
691     CmdAddArg (&CA65, Arg);
692 }
693
694
695
696 static void OptDebug (const char* Opt)
697 /* Debug mode (compiler) */
698 {
699     CmdAddArg (&CC65, "-d");
700 }
701
702
703
704 static void OptDebugInfo (const char* Opt)
705 /* Debug Info - add to compiler and assembler */
706 {
707     CmdAddArg (&CC65, "-g");
708     CmdAddArg (&CA65, "-g");
709 }
710
711
712
713 static void OptHelp (const char* Opt)
714 /* Print help - cl65 */
715 {
716     Usage ();
717     exit (EXIT_SUCCESS);
718 }
719
720
721
722 static void OptIncludeDir (const char* Opt, const char* Arg)
723 /* Include directory (compiler) */
724 {
725     if (Arg == 0) {
726         NeedArg (Opt);
727     }
728     CmdAddArg (&CC65, "-I");
729     CmdAddArg (&CC65, Arg);
730 }
731
732
733
734 static void OptTarget (const char* Opt, const char* Arg)
735 /* Set the target system */
736 {
737     if (Arg == 0) {
738         NeedArg (Opt);
739     }
740     SetTargetByName (Arg);
741 }
742
743
744
745 static void OptVerbose (const char* Opt)
746 /* Verbose mode (compiler, assembler, linker) */
747 {
748     CmdAddArg (&CC65, "-v");
749     CmdAddArg (&CA65, "-v");
750     CmdAddArg (&LD65, "-v");
751 }
752
753
754
755 static void OptVersion (const char* Opt)
756 /* Print version number */
757 {
758     fprintf (stderr,
759              "cl65 V%u.%u.%u - (C) Copyright 1998-2000 Ullrich von Bassewitz\n",
760              VER_MAJOR, VER_MINOR, VER_PATCH);
761 }
762
763
764
765 static void LongOption (int* ArgNum, char* argv [])
766 /* Handle a long command line option */
767 {
768     const char* Opt = argv [*ArgNum];
769     const char* Arg = argv [*ArgNum+1];
770
771     if (strcmp (Opt, "--ansi") == 0) {
772         OptAnsi (Opt);
773     } else if (strcmp (Opt, "--asm-include-dir") == 0) {
774         OptAsmIncludeDir (Opt, Arg);
775         ++(*ArgNum);
776     } else if (strcmp (Opt, "--debug") == 0) {
777         OptDebug (Opt);
778     } else if (strcmp (Opt, "--debug-info") == 0) {
779         OptDebugInfo (Opt);
780     } else if (strcmp (Opt, "--help") == 0) {
781         OptHelp (Opt);
782     } else if (strcmp (Opt, "--include-dir") == 0) {
783         OptIncludeDir (Opt, Arg);
784         ++(*ArgNum);
785     } else if (strcmp (Opt, "--target") == 0) {
786         OptTarget (Opt, Arg);
787         ++(*ArgNum);
788     } else if (strcmp (Opt, "--verbose") == 0) {
789         OptVerbose (Opt);
790     } else if (strcmp (Opt, "--version") == 0) {
791         OptVersion (Opt);
792     } else {
793         UnknownOption (Opt);
794     }
795 }
796
797
798
799 int main (int argc, char* argv [])
800 /* Utility main program */
801 {
802     int I;
803
804     /* Initialize the command descriptors */
805     CmdInit (&CC65, "cc65");
806     CmdInit (&CA65, "ca65");
807     CmdInit (&LD65, "ld65");
808
809     /* Check the parameters */
810     I = 1;
811     while (I < argc) {
812
813         /* Get the argument */
814         const char* Arg = argv [I];
815
816         /* Check for an option */
817         if (Arg [0] == '-') {
818
819             switch (Arg [1]) {
820
821                 case '-':
822                     LongOption (&I, argv);
823                     break;
824
825                 case 'A':
826                     /* Strict ANSI mode (compiler) */
827                     OptAnsi (Arg);
828                     break;
829
830                 case 'C':
831                     if (Arg[2] == 'l' && Arg[3] == '\0') {
832                         /* Make local variables static */
833                         CmdAddArg (&CC65, "-Cl");
834                     } else {
835                         /* Specify linker config file */
836                         LinkerConfig = GetArg (&I, argv, 2);
837                     }
838                     break;
839
840                 case 'D':
841                     /* Define a preprocessor symbol (compiler) */
842                     CmdAddArg (&CC65, "-D");
843                     CmdAddArg (&CC65, GetArg (&I, argv, 2));
844                     break;
845
846                 case 'I':
847                     /* Include directory (compiler) */
848                     OptIncludeDir (Arg, GetArg (&I, argv, 2));
849                     break;
850
851                 case 'L':
852                     if (Arg[2] == 'n') {
853                         /* VICE label file (linker) */
854                         CmdAddArg (&LD65, "-Ln");
855                         CmdAddArg (&LD65, GetArg (&I, argv, 3));
856                     } else {
857                         UnknownOption (Arg);
858                     }
859                     break;
860
861                 case 'O':
862                     /* Optimize code (compiler, also covers -Oi and others) */
863                     CmdAddArg (&CC65, Arg);
864                     break;
865
866                 case 'S':
867                     /* Dont assemble and link the created files */
868                     DontLink = DontAssemble = 1;
869                     break;
870
871                 case 'T':
872                     /* Include source as comment (compiler) */
873                     CmdAddArg (&CC65, "-T");
874                     break;
875
876                 case 'V':
877                     /* Print version number */
878                     OptVersion (Arg);
879                     break;
880
881                 case 'W':
882                     /* Suppress warnings - compiler and assembler */
883                     CmdAddArg (&CC65, "-W");
884                     CmdAddArg (&CA65, "-W");
885                     CmdAddArg (&CA65, "0");
886                     break;
887
888                 case 'c':
889                     /* Don't link the resulting files */
890                     DontLink = 1;
891                     break;
892
893                 case 'd':
894                     /* Debug mode (compiler) */
895                     OptDebug (Arg);
896                     break;
897
898                 case 'g':
899                     /* Debugging - add to compiler and assembler */
900                     OptDebugInfo (Arg);
901                     break;
902
903                 case 'h':
904                 case '?':
905                     /* Print help - cl65 */
906                     OptHelp (Arg);
907                     break;
908
909                 case 'm':
910                     /* Create a map file (linker) */
911                     CmdAddArg (&LD65, "-m");
912                     CmdAddArg (&LD65, GetArg (&I, argv, 2));
913                     break;
914
915                 case 'o':
916                     /* Name the output file */
917                     OutputName = GetArg (&I, argv, 2);
918                     break;
919
920                 case 't':
921                     /* Set target system - compiler and linker */
922                     OptTarget (Arg, GetArg (&I, argv, 2));
923                     break;
924
925                 case 'v':
926                     if (Arg [2] == 'm') {
927                         /* Verbose map file (linker) */
928                         CmdAddArg (&LD65, "-vm");
929                     } else {
930                         /* Verbose mode (compiler, assembler, linker) */
931                         OptVerbose (Arg);
932                     }
933                     break;
934
935                 default:
936                     UnknownOption (Arg);
937             }
938         } else {
939
940             /* Remember the first file name */
941             if (FirstInput == 0) {
942                 FirstInput = Arg;
943             }
944
945             /* Determine the file type by the extension */
946             switch (GetFileType (Arg)) {
947
948                 case FILETYPE_C:
949                     /* Compile the file */
950                     Compile (Arg);
951                     break;
952
953                 case FILETYPE_ASM:
954                     /* Assemble the file */
955                     if (!DontAssemble) {
956                         Assemble (Arg);
957                     }
958                     break;
959
960                 case FILETYPE_OBJ:
961                 case FILETYPE_LIB:
962                     /* Add to the linker files */
963                     CmdAddFile (&LD65, Arg);
964                     break;
965
966                 default:
967                     Error ("Don't know what to do with `%s'", Arg);
968
969             }
970
971         }
972
973         /* Next argument */
974         ++I;
975     }
976
977     /* Check if we had any input files */
978     if (FirstInput == 0) {
979         Warning ("No input files");
980     }
981
982     /* Link the given files if requested and if we have any */
983     if (DontLink == 0 && LD65.FileCount > 0) {
984         Link ();
985     }
986
987     /* Return an apropriate exit code */
988     return EXIT_SUCCESS;
989 }
990
991
992