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