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