]> git.sur5r.net Git - cc65/blob - src/cl65/main.c
Add more co65 options
[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-2003 Ullrich von Bassewitz                                       */
10 /*               Römerstrasse 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(__WATCOMC__) || defined(_MSC_VER) || defined(__MINGW32__) || defined(__DJGPP__)
40 #  define HAVE_SPAWN    1
41 #else
42 #  define NEED_SPAWN   1
43 #endif
44
45
46
47 #include <stdio.h>
48 #include <stdlib.h>
49 #include <string.h>
50 #include <ctype.h>
51 #include <errno.h>
52 #ifdef HAVE_SPAWN
53 #  include <process.h>
54 #endif
55
56 /* common */
57 #include "attrib.h"
58 #include "cmdline.h"
59 #include "fname.h"
60 #include "strbuf.h"
61 #include "target.h"
62 #include "version.h"
63 #include "xmalloc.h"
64
65 /* cl65 */
66 #include "global.h"
67 #include "error.h"
68
69
70
71 /*****************************************************************************/
72 /*                                   Data                                    */
73 /*****************************************************************************/
74
75
76
77 /* Struct that describes a command */
78 typedef struct CmdDesc CmdDesc;
79 struct CmdDesc {
80     char*       Name;           /* The command name */
81
82     unsigned    ArgCount;       /* Count of arguments */
83     unsigned    ArgMax;         /* Maximum count of arguments */
84     char**      Args;           /* The arguments */
85
86     unsigned    FileCount;      /* Count of files to translate */
87     unsigned    FileMax;        /* Maximum count of files */
88     char**      Files;          /* The files */
89 };
90
91 /* Command descriptors for the different programs */
92 static CmdDesc CC65 = { 0, 0, 0, 0, 0, 0, 0 };
93 static CmdDesc CA65 = { 0, 0, 0, 0, 0, 0, 0 };
94 static CmdDesc CO65 = { 0, 0, 0, 0, 0, 0, 0 };
95 static CmdDesc LD65 = { 0, 0, 0, 0, 0, 0, 0 };
96 static CmdDesc GRC  = { 0, 0, 0, 0, 0, 0, 0 };
97
98 /* File types */
99 enum {
100     FILETYPE_UNKNOWN,
101     FILETYPE_C,
102     FILETYPE_ASM,
103     FILETYPE_OBJ,
104     FILETYPE_LIB,
105     FILETYPE_GR,                /* GEOS resource file */
106     FILETYPE_O65                /* O65 object file */
107 };
108
109 /* Default file type, used if type unknown */
110 static unsigned DefaultFileType = FILETYPE_UNKNOWN;
111
112 /* Variables controlling the steps we're doing */
113 static int DontLink     = 0;
114 static int DontAssemble = 0;
115
116 /* The name of the output file, NULL if none given */
117 static const char* OutputName = 0;
118
119 /* The name of the linker configuration file if given */
120 static const char* LinkerConfig = 0;
121
122 /* The name of the first input file. This will be used to construct the
123  * executable file name if no explicit name is given.
124  */
125 static const char* FirstInput = 0;
126
127 /* Remember if we should link a module */
128 static int Module = 0;
129
130 /* Extension used for a module */
131 #define MODULE_EXT      ".o65"
132
133 /* Name of the crt0 object file and the runtime library */
134 static char* TargetCRT0 = 0;
135 static char* TargetLib  = 0;
136
137
138
139 /*****************************************************************************/
140 /*                Include the system specific spawn function                 */
141 /*****************************************************************************/
142
143
144
145 #if defined(NEED_SPAWN)
146 #  if defined(SPAWN_UNIX)
147 #    include "spawn-unix.inc"
148 #  elif defined(SPAWN_AMIGA)
149 #    include "spawn-amiga.inc"
150 #  else
151 #    error "Don't know which spawn module to include!"
152 #  endif
153 #endif
154
155
156
157 /*****************************************************************************/
158 /*                           Determine a file type                           */
159 /*****************************************************************************/
160
161
162
163 static unsigned GetFileType (const char* File)
164 /* Determine the type of the given file */
165 {
166     /* Table mapping extensions to file types */
167     static const struct {
168         const char*     Ext;
169         unsigned        Type;
170     } FileTypes [] = {
171         {   ".c",       FILETYPE_C      },
172         {   ".s",       FILETYPE_ASM    },
173         {   ".asm",     FILETYPE_ASM    },
174         {   ".a65",     FILETYPE_ASM    },
175         {   ".o",       FILETYPE_OBJ    },
176         {   ".obj",     FILETYPE_OBJ    },
177         {   ".a",       FILETYPE_LIB    },
178         {   ".lib",     FILETYPE_LIB    },
179         {   ".grc",     FILETYPE_GR     },
180         {   ".o65",     FILETYPE_O65    },
181         {   ".emd",     FILETYPE_O65    },
182         {   ".joy",     FILETYPE_O65    },
183         {   ".tgi",     FILETYPE_O65    },
184     };
185
186     unsigned I;
187
188     /* Determine the file type by the extension */
189     const char* Ext = FindExt (File);
190
191     /* Do we have an extension? */
192     if (Ext == 0) {
193         return DefaultFileType;
194     }
195
196     /* Check for known extensions */
197     for (I = 0; I < sizeof (FileTypes) / sizeof (FileTypes [0]); ++I) {
198         if (strcmp (FileTypes [I].Ext, Ext) == 0) {
199             /* Found */
200             return FileTypes [I].Type;
201         }
202     }
203
204     /* Not found, return the default */
205     return DefaultFileType;
206 }
207
208
209
210 /*****************************************************************************/
211 /*                        Command structure handling                         */
212 /*****************************************************************************/
213
214
215
216 static void CmdAddArg (CmdDesc* Cmd, const char* Arg)
217 /* Add a new argument to the command */
218 {
219     /* Expand the argument vector if needed */
220     if (Cmd->ArgCount == Cmd->ArgMax) {
221         unsigned NewMax  = Cmd->ArgMax + 10;
222         char**   NewArgs = xmalloc (NewMax * sizeof (char*));
223         memcpy (NewArgs, Cmd->Args, Cmd->ArgMax * sizeof (char*));
224         xfree (Cmd->Args);
225         Cmd->Args   = NewArgs;
226         Cmd->ArgMax = NewMax;
227     }
228
229     /* Add a copy of the new argument, allow a NULL pointer */
230     if (Arg) {
231         Cmd->Args [Cmd->ArgCount++] = xstrdup (Arg);
232     } else {
233         Cmd->Args [Cmd->ArgCount++] = 0;
234     }
235 }
236
237
238
239 static void CmdAddArg2 (CmdDesc* Cmd, const char* Arg1, const char* Arg2)
240 /* Add a new argument pair to the command */
241 {
242     CmdAddArg (Cmd, Arg1);
243     CmdAddArg (Cmd, Arg2);
244 }
245
246
247
248 static void CmdDelArgs (CmdDesc* Cmd, unsigned LastValid)
249 /* Remove all arguments with an index greater than LastValid */
250 {
251     while (Cmd->ArgCount > LastValid) {
252         Cmd->ArgCount--;
253         xfree (Cmd->Args [Cmd->ArgCount]);
254         Cmd->Args [Cmd->ArgCount] = 0;
255     }
256 }
257
258
259
260 static void CmdAddFile (CmdDesc* Cmd, const char* File)
261 /* Add a new file to the command */
262 {
263     /* Expand the file vector if needed */
264     if (Cmd->FileCount == Cmd->FileMax) {
265         unsigned NewMax   = Cmd->FileMax + 10;
266         char**   NewFiles = xmalloc (NewMax * sizeof (char*));
267         memcpy (NewFiles, Cmd->Files, Cmd->FileMax * sizeof (char*));
268         xfree (Cmd->Files);
269         Cmd->Files   = NewFiles;
270         Cmd->FileMax = NewMax;
271     }
272
273     /* If the file name is not NULL (which is legal and is used to terminate
274      * the file list), check if the file name does already exist in the file
275      * list and print a warning if so. Regardless of the search result, add
276      * the file.
277      */
278     if (File) {
279         unsigned I;
280         for (I = 0; I < Cmd->FileCount; ++I) {
281             if (strcmp (Cmd->Files[I], File) == 0) {
282                 /* Duplicate file */
283                 Warning ("Duplicate file in argument list: `%s'", File);
284                 /* No need to search further */
285                 break;
286             }
287         }
288
289         /* Add the file */
290         Cmd->Files [Cmd->FileCount++] = xstrdup (File);
291     } else {
292         /* Add a NULL pointer */
293         Cmd->Files [Cmd->FileCount++] = 0;
294     }
295 }
296
297
298
299 static void CmdInit (CmdDesc* Cmd, const char* Path)
300 /* Initialize the command using the given path to the executable */
301 {
302     /* Remember the command */
303     Cmd->Name = xstrdup (Path);
304
305     /* Use the command name as first argument */
306     CmdAddArg (Cmd, Path);
307 }
308
309
310
311 static void CmdSetOutput (CmdDesc* Cmd, const char* File)
312 /* Set the output file in a command desc */
313 {
314     CmdAddArg2 (Cmd, "-o", File);
315 }
316
317
318
319 static void CmdSetTarget (CmdDesc* Cmd, target_t Target)
320 /* Set the output file in a command desc */
321 {
322     CmdAddArg2 (Cmd, "-t", TargetNames[Target]);
323 }
324
325
326
327 static void CmdPrint (CmdDesc* Cmd, FILE* F)
328 /* Output the command line encoded in the command desc */
329 {
330     unsigned I;
331     for (I = 0; I < Cmd->ArgCount && Cmd->Args[I] != 0; ++I) {
332         fprintf (F, "%s ", Cmd->Args[I]);
333     }
334 }
335
336
337
338 /*****************************************************************************/
339 /*                              Target handling                              */
340 /*****************************************************************************/
341
342
343
344 static void SetTargetFiles (void)
345 /* Set the target system files */
346 {
347     /* Determine the names of the default startup and library file */
348     if (Target != TGT_NONE) {
349
350         /* Get a pointer to the system name and its length */
351         const char* TargetName = TargetNames [Target];
352         unsigned    TargetNameLen = strlen (TargetName);
353
354         /* Set the startup file */
355         TargetCRT0 = xmalloc (TargetNameLen + 2 + 1);
356         strcpy (TargetCRT0, TargetName);
357         strcat (TargetCRT0, ".o");
358
359         /* Set the library file */
360         TargetLib = xmalloc (TargetNameLen + 4 + 1);
361         strcpy (TargetLib, TargetName);
362         strcat (TargetLib, ".lib");
363
364     }
365 }
366
367
368
369 /*****************************************************************************/
370 /*                               Subprocesses                                */
371 /*****************************************************************************/
372
373
374
375 static void ExecProgram (CmdDesc* Cmd)
376 /* Execute a subprocess with the given name/parameters. Exit on errors. */
377 {
378     int Status;
379
380     /* If in debug mode, output the command line we will execute */
381     if (Debug) {
382         printf ("Executing: ");
383         CmdPrint (Cmd, stdout);
384         printf ("\n");
385     }
386
387     /* Call the program */
388     Status = spawnvp (P_WAIT, Cmd->Name, Cmd->Args);
389
390     /* Check the result code */
391     if (Status < 0) {
392         /* Error executing the program */
393         Error ("Cannot execute `%s': %s", Cmd->Name, strerror (errno));
394     } else if (Status != 0) {
395         /* Called program had an error */
396         exit (Status);
397     }
398 }
399
400
401
402 static void Link (void)
403 /* Link the resulting executable */
404 {
405     unsigned I;
406
407     /* If we have a linker config file given, add it to the command line.
408      * Otherwise pass the target to the linker if we have one.
409      */
410     if (LinkerConfig) {
411         if (Module) {
412             Error ("Cannot use -C and --module together");
413         }
414         CmdAddArg2 (&LD65, "-C", LinkerConfig);
415     } else if (Module) {
416         CmdSetTarget (&LD65, TGT_MODULE);
417     } else if (Target != TGT_NONE) {
418         CmdSetTarget (&LD65, Target);
419     }
420
421     /* Determine which target libraries are needed */
422     SetTargetFiles ();
423
424     /* Since linking is always the final step, if we have an output file name
425      * given, set it here. If we don't have an explicit output name given,
426      * try to build one from the name of the first input file.
427      */
428     if (OutputName) {
429
430         CmdSetOutput (&LD65, OutputName);
431
432     } else if (FirstInput && FindExt (FirstInput)) {  /* Only if ext present! */
433
434         const char* Extension = Module? MODULE_EXT : "";
435         char* Output = MakeFilename (FirstInput, Extension);
436         CmdSetOutput (&LD65, Output);
437         xfree (Output);
438
439     }
440
441     /* If we have a startup file and if we are not linking a module, add its
442      * name as a parameter
443      */
444     if (TargetCRT0 && !Module) {
445         CmdAddArg (&LD65, TargetCRT0);
446     }
447
448     /* Add all object files as parameters */
449     for (I = 0; I < LD65.FileCount; ++I) {
450         CmdAddArg (&LD65, LD65.Files [I]);
451     }
452
453     /* Add the system runtime library */
454     if (TargetLib) {
455         CmdAddArg (&LD65, TargetLib);
456     }
457
458     /* Terminate the argument list with a NULL pointer */
459     CmdAddArg (&LD65, 0);
460
461     /* Call the linker */
462     ExecProgram (&LD65);
463 }
464
465
466
467 static void Assemble (const char* File)
468 /* Assemble the given file */
469 {
470     /* Remember the current assembler argument count */
471     unsigned ArgCount = CA65.ArgCount;
472
473     /* Set the target system */
474     CmdSetTarget (&CA65, Target);
475
476     /* If we won't link, this is the final step. In this case, set the
477      * output name.
478      */
479     if (DontLink && OutputName) {
480         CmdSetOutput (&CA65, OutputName);
481     } else {
482         /* The object file name will be the name of the source file
483          * with .s replaced by ".o". Add this file to the list of
484          * linker files.
485          */
486         char* ObjName = MakeFilename (File, ".o");
487         CmdAddFile (&LD65, ObjName);
488         xfree (ObjName);
489     }
490
491     /* Add the file as argument for the assembler */
492     CmdAddArg (&CA65, File);
493
494     /* Add a NULL pointer to terminate the argument list */
495     CmdAddArg (&CA65, 0);
496
497     /* Run the assembler */
498     ExecProgram (&CA65);
499
500     /* Remove the excess arguments */
501     CmdDelArgs (&CA65, ArgCount);
502 }
503
504
505
506 static void Compile (const char* File)
507 /* Compile the given file */
508 {
509     char* AsmName = 0;
510
511     /* Remember the current compiler argument count */
512     unsigned ArgCount = CC65.ArgCount;
513
514     /* Set the target system */
515     CmdSetTarget (&CC65, Target);
516
517     /* If we won't link, this is the final step. In this case, set the
518      * output name.
519      */
520     if (DontAssemble && OutputName) {
521         CmdSetOutput (&CC65, OutputName);
522     } else {
523         /* The assembler file name will be the name of the source file
524          * with .c replaced by ".s".
525          */
526         AsmName = MakeFilename (File, ".s");
527     }
528
529     /* Add the file as argument for the compiler */
530     CmdAddArg (&CC65, File);
531
532     /* Add a NULL pointer to terminate the argument list */
533     CmdAddArg (&CC65, 0);
534
535     /* Run the compiler */
536     ExecProgram (&CC65);
537
538     /* Remove the excess arguments */
539     CmdDelArgs (&CC65, ArgCount);
540
541     /* If this is not the final step, assemble the generated file, then
542      * remove it
543      */
544     if (!DontAssemble) {
545         Assemble (AsmName);
546         if (remove (AsmName) < 0) {
547             Warning ("Cannot remove temporary file `%s': %s",
548                      AsmName, strerror (errno));
549         }
550         xfree (AsmName);
551     }
552 }
553
554
555
556 static void CompileRes (const char* File)
557 /* Compile the given geos resource file */
558 {
559     char* AsmName = 0;
560
561     /* Remember the current assembler argument count */
562     unsigned ArgCount = GRC.ArgCount;
563
564     /* The assembler file name will be the name of the source file
565      * with .grc replaced by ".s".
566      */
567     AsmName = MakeFilename (File, ".s");
568
569     /* Add the file as argument for the resource compiler */
570     CmdAddArg (&GRC, File);
571
572     /* Add a NULL pointer to terminate the argument list */
573     CmdAddArg (&GRC, 0);
574
575     /* Run the compiler */
576     ExecProgram (&GRC);
577
578     /* Remove the excess arguments */
579     CmdDelArgs (&GRC, ArgCount);
580
581     /* If this is not the final step, assemble the generated file, then
582      * remove it
583      */
584     if (!DontAssemble) {
585         Assemble (AsmName);
586         if (remove (AsmName) < 0) {
587             Warning ("Cannot remove temporary file `%s': %s",
588                      AsmName, strerror (errno));
589         }
590     }
591
592     /* Free the assembler file name which was allocated from the heap */
593     xfree (AsmName);
594 }
595
596
597
598 static void ConvertO65 (const char* File)
599 /* Convert an o65 object file into an assembler file */
600 {
601     char* AsmName = 0;
602
603     /* Remember the current converter argument count */
604     unsigned ArgCount = CO65.ArgCount;
605
606     /* If we won't link, this is the final step. In this case, set the
607      * output name.
608      */
609     if (DontAssemble && OutputName) {
610         CmdSetOutput (&CO65, OutputName);
611     } else {
612         /* The assembler file name will be the name of the source file
613          * with .c replaced by ".s".
614          */
615         AsmName = MakeFilename (File, ".s");
616     }
617
618     /* Add the file as argument for the object file converter */
619     CmdAddArg (&CO65, File);
620
621     /* Add a NULL pointer to terminate the argument list */
622     CmdAddArg (&CO65, 0);
623
624     /* Run the converter */
625     ExecProgram (&CO65);
626
627     /* Remove the excess arguments */
628     CmdDelArgs (&CO65, ArgCount);
629
630     /* If this is not the final step, assemble the generated file, then
631      * remove it
632      */
633     if (!DontAssemble) {
634         Assemble (AsmName);
635         if (remove (AsmName) < 0) {
636             Warning ("Cannot remove temporary file `%s': %s",
637                      AsmName, strerror (errno));
638         }
639     }
640
641     /* Free the assembler file name which was allocated from the heap */
642     xfree (AsmName);
643 }
644
645
646
647 /*****************************************************************************/
648 /*                                   Code                                    */
649 /*****************************************************************************/
650
651
652
653 static void Usage (void)
654 /* Print usage information and exit */
655 {
656     fprintf (stderr,
657              "Usage: %s [options] file [...]\n"
658              "Short options:\n"
659              "  -c\t\t\tCompile and assemble but don't link\n"
660              "  -d\t\t\tDebug mode\n"
661              "  -g\t\t\tAdd debug info\n"
662              "  -h\t\t\tHelp (this text)\n"
663              "  -l\t\t\tCreate an assembler listing\n"
664              "  -m name\t\tCreate a map file\n"
665              "  -o name\t\tName the output file\n"
666              "  -r\t\t\tEnable register variables\n"
667              "  -t sys\t\tSet the target system\n"
668              "  -v\t\t\tVerbose mode\n"
669              "  -vm\t\t\tVerbose map file\n"
670              "  -A\t\t\tStrict ANSI mode\n"
671              "  -C name\t\tUse linker config file\n"
672              "  -Cl\t\t\tMake local variables static\n"
673              "  -D sym[=defn]\t\tDefine a preprocessor symbol\n"
674              "  -I dir\t\tSet a compiler include directory path\n"
675              "  -Ln name\t\tCreate a VICE label file\n"
676              "  -O\t\t\tOptimize code\n"
677              "  -Oi\t\t\tOptimize code, inline functions\n"
678              "  -Or\t\t\tOptimize code, honour the register keyword\n"
679              "  -Os\t\t\tOptimize code, inline known C funtions\n"
680              "  -S\t\t\tCompile but don't assemble and link\n"
681              "  -T\t\t\tInclude source as comment\n"
682              "  -V\t\t\tPrint the version number\n"
683              "  -W\t\t\tSuppress warnings\n"
684              "\n"
685              "Long options:\n"
686              "  --add-source\t\tInclude source as comment\n"
687              "  --ansi\t\tStrict ANSI mode\n"
688              "  --asm-include-dir dir\tSet an assembler include directory\n"
689              "  --bss-label name\tDefine and export a BSS segment label\n"
690              "  --bss-name seg\tSet the name of the BSS segment\n"
691              "  --check-stack\t\tGenerate stack overflow checks\n"
692              "  --code-label name\tDefine and export a CODE segment label\n"
693              "  --code-name seg\tSet the name of the CODE segment\n"
694              "  --codesize x\t\tAccept larger code by factor x\n"
695              "  --cpu type\t\tSet cpu type\n"
696              "  --create-dep\t\tCreate a make dependency file\n"
697              "  --data-label name\tDefine and export a DATA segment label\n"
698              "  --data-name seg\tSet the name of the DATA segment\n"
699              "  --debug\t\tDebug mode\n"
700              "  --debug-info\t\tAdd debug info\n"
701              "  --feature name\tSet an emulation feature\n"
702              "  --help\t\tHelp (this text)\n"
703              "  --include-dir dir\tSet a compiler include directory path\n"
704              "  --listing\t\tCreate an assembler listing\n"
705              "  --mapfile name\tCreate a map file\n"
706              "  --module\t\tLink as a module\n"
707              "  --module-id id\tSpecify a module id for the linker\n"
708              "  --o65-model model\tOverride the o65 model\n"
709              "  --register-space b\tSet space available for register variables\n"
710              "  --register-vars\tEnable register variables\n"
711              "  --rodata-name seg\tSet the name of the RODATA segment\n"
712              "  --signed-chars\tDefault characters are signed\n"
713              "  --start-addr addr\tSet the default start address\n"
714              "  --static-locals\tMake local variables static\n"
715              "  --target sys\t\tSet the target system\n"
716              "  --version\t\tPrint the version number\n"
717              "  --verbose\t\tVerbose mode\n"
718              "  --zeropage-label name\tDefine and export a ZEROPAGE segment label\n"
719              "  --zeropage-name seg\tSet the name of the ZEROPAGE segment\n",
720              ProgName);
721 }
722
723
724
725 static void OptAddSource (const char* Opt attribute ((unused)),
726                           const char* Arg attribute ((unused)))
727 /* Strict source code as comments to the generated asm code */
728 {
729     CmdAddArg (&CC65, "-T");
730 }
731
732
733
734 static void OptAnsi (const char* Opt attribute ((unused)),
735                      const char* Arg attribute ((unused)))
736 /* Strict ANSI mode (compiler) */
737 {
738     CmdAddArg (&CC65, "-A");
739 }
740
741
742
743 static void OptAsmIncludeDir (const char* Opt attribute ((unused)), const char* Arg)
744 /* Include directory (assembler) */
745 {
746     CmdAddArg2 (&CA65, "-I", Arg);
747 }
748
749
750
751 static void OptBssLabel (const char* Opt attribute ((unused)), const char* Arg)
752 /* Handle the --bss-label option */
753 {
754     CmdAddArg2 (&CO65, "--bss-label", Arg);
755 }
756
757
758
759 static void OptBssName (const char* Opt attribute ((unused)), const char* Arg)
760 /* Handle the --bss-name option */
761 {
762     CmdAddArg2 (&CC65, "--bss-name", Arg);
763     CmdAddArg2 (&CO65, "--bss-name", Arg);
764 }
765
766
767
768 static void OptCheckStack (const char* Opt attribute ((unused)),
769                            const char* Arg attribute ((unused)))
770 /* Handle the --check-stack option */
771 {
772     CmdAddArg (&CC65, "--check-stack");
773 }
774
775
776
777 static void OptCodeLabel (const char* Opt attribute ((unused)), const char* Arg)
778 /* Handle the --code-label option */
779 {
780     CmdAddArg2 (&CO65, "--code-label", Arg);
781 }
782
783
784
785 static void OptCodeName (const char* Opt attribute ((unused)), const char* Arg)
786 /* Handle the --code-name option */
787 {
788     CmdAddArg2 (&CC65, "--code-name", Arg);
789     CmdAddArg2 (&CO65, "--code-name", Arg);
790 }
791
792
793
794 static void OptCodeSize (const char* Opt attribute ((unused)), const char* Arg)
795 /* Handle the --codesize option */
796 {
797     CmdAddArg2 (&CC65, "--codesize", Arg);
798 }
799
800
801
802 static void OptCPU (const char* Opt attribute ((unused)), const char* Arg)
803 /* Handle the --cpu option */
804 {
805     /* Add the cpu type to the assembler and compiler */
806     CmdAddArg2 (&CA65, "--cpu", Arg);
807     CmdAddArg2 (&CC65, "--cpu", Arg);
808 }
809
810
811
812 static void OptCreateDep (const char* Opt attribute ((unused)),
813                           const char* Arg attribute ((unused)))
814 /* Handle the --create-dep option */
815 {
816     CmdAddArg (&CC65, "--create-dep");
817 }
818
819
820
821 static void OptDataLabel (const char* Opt attribute ((unused)), const char* Arg)
822 /* Handle the --data-label option */
823 {
824     CmdAddArg2 (&CO65, "--data-label", Arg);
825 }
826
827
828
829 static void OptDataName (const char* Opt attribute ((unused)), const char* Arg)
830 /* Handle the --data-name option */
831 {
832     CmdAddArg2 (&CC65, "--data-name", Arg);
833     CmdAddArg2 (&CO65, "--data-name", Arg);
834 }
835
836
837
838 static void OptDebug (const char* Opt attribute ((unused)),
839                       const char* Arg attribute ((unused)))
840 /* Debug mode (compiler and cl65 utility) */
841 {
842     CmdAddArg (&CC65, "-d");
843     CmdAddArg (&CO65, "-d");
844     Debug = 1;
845 }
846
847
848
849 static void OptDebugInfo (const char* Opt attribute ((unused)),
850                           const char* Arg attribute ((unused)))
851 /* Debug Info - add to compiler and assembler */
852 {
853     CmdAddArg (&CC65, "-g");
854     CmdAddArg (&CA65, "-g");
855     CmdAddArg (&CO65, "-g");
856 }
857
858
859
860 static void OptFeature (const char* Opt attribute ((unused)), const char* Arg)
861 /* Emulation features for the assembler */
862 {
863     CmdAddArg2 (&CA65, "--feature", Arg);
864 }
865
866
867
868 static void OptHelp (const char* Opt attribute ((unused)),
869                      const char* Arg attribute ((unused)))
870 /* Print help - cl65 */
871 {
872     Usage ();
873     exit (EXIT_SUCCESS);
874 }
875
876
877
878 static void OptIncludeDir (const char* Opt attribute ((unused)), const char* Arg)
879 /* Include directory (compiler) */
880 {
881     CmdAddArg2 (&CC65, "-I", Arg);
882 }
883
884
885
886 static void OptListing (const char* Opt attribute ((unused)),
887                         const char* Arg attribute ((unused)))
888 /* Create an assembler listing */
889 {
890     CmdAddArg (&CA65, "-l");
891 }
892
893
894
895 static void OptMapFile (const char* Opt attribute ((unused)), const char* Arg)
896 /* Create a map file */
897 {
898     /* Create a map file (linker) */
899     CmdAddArg2 (&LD65, "-m", Arg);
900 }
901
902
903
904 static void OptModule (const char* Opt attribute ((unused)),
905                        const char* Arg attribute ((unused)))
906 /* Link as a module */
907 {
908     Module = 1;
909 }
910
911
912
913 static void OptModuleId (const char* Opt attribute ((unused)), const char* Arg)
914 /* Specify a module if for the linker */
915 {
916     /* Pass it straight to the linker */
917     CmdAddArg2 (&LD65, "--module-id", Arg);
918 }
919
920
921
922 static void OptO65Model (const char* Opt attribute ((unused)), const char* Arg)
923 /* Handle the --o65-model option */
924 {
925     CmdAddArg2 (&CO65, "-m", Arg);
926 }
927
928
929
930 static void OptRegisterSpace (const char* Opt attribute ((unused)), const char* Arg)
931 /* Handle the --register-space option */
932 {
933     CmdAddArg2 (&CC65, "--register-space", Arg);
934 }
935
936
937
938 static void OptRegisterVars (const char* Opt attribute ((unused)),
939                              const char* Arg attribute ((unused)))
940 /* Handle the --register-vars option */
941 {
942     CmdAddArg (&CC65, "-r");
943 }
944
945
946
947 static void OptRodataName (const char* Opt attribute ((unused)), const char* Arg)
948 /* Handle the --rodata-name option */
949 {
950     CmdAddArg2 (&CC65, "--rodata-name", Arg);
951 }
952
953
954
955 static void OptSignedChars (const char* Opt attribute ((unused)),
956                             const char* Arg attribute ((unused)))
957 /* Make default characters signed */
958 {
959     CmdAddArg (&CC65, "-j");
960 }
961
962
963
964 static void OptStartAddr (const char* Opt attribute ((unused)), const char* Arg)
965 /* Set the default start address */
966 {
967     CmdAddArg2 (&LD65, "-S", Arg);
968 }
969
970
971
972 static void OptStaticLocals (const char* Opt attribute ((unused)),
973                              const char* Arg attribute ((unused)))
974 /* Place local variables in static storage */
975 {
976     CmdAddArg (&CC65, "-Cl");
977 }
978
979
980
981 static void OptTarget (const char* Opt attribute ((unused)), const char* Arg)
982 /* Set the target system */
983 {
984     Target = FindTarget (Arg);
985     if (Target == TGT_UNKNOWN) {
986         Error ("No such target system: `%s'", Arg);
987     } else if (Target == TGT_MODULE) {
988         Error ("Cannot use `module' as target, use --module instead");
989     }
990 }
991
992
993
994 static void OptVerbose (const char* Opt attribute ((unused)),
995                         const char* Arg attribute ((unused)))
996 /* Verbose mode (compiler, assembler, linker) */
997 {
998     CmdAddArg (&CC65, "-v");
999     CmdAddArg (&CA65, "-v");
1000     CmdAddArg (&CO65, "-v");
1001     CmdAddArg (&LD65, "-v");
1002 }
1003
1004
1005
1006 static void OptVersion (const char* Opt attribute ((unused)),
1007                         const char* Arg attribute ((unused)))
1008 /* Print version number */
1009 {
1010     fprintf (stderr,
1011              "cl65 V%u.%u.%u - (C) Copyright 1998-2003 Ullrich von Bassewitz\n",
1012              VER_MAJOR, VER_MINOR, VER_PATCH);
1013 }
1014
1015
1016
1017 static void OptZeropageLabel (const char* Opt attribute ((unused)), const char* Arg)
1018 /* Handle the --zeropage-label option */
1019 {
1020     CmdAddArg2 (&CO65, "--zeropage-label", Arg);
1021 }
1022
1023
1024
1025 static void OptZeropageName (const char* Opt attribute ((unused)), const char* Arg)
1026 /* Handle the --zeropage-name option */
1027 {
1028     CmdAddArg2 (&CO65, "--zeropage-name", Arg);
1029 }
1030
1031
1032
1033 int main (int argc, char* argv [])
1034 /* Utility main program */
1035 {
1036     /* Program long options */
1037     static const LongOpt OptTab[] = {
1038         { "--add-source",       0,      OptAddSource            },
1039         { "--ansi",             0,      OptAnsi                 },
1040         { "--asm-include-dir",  1,      OptAsmIncludeDir        },
1041         { "--bss-label",        1,      OptBssLabel             },
1042         { "--bss-name",         1,      OptBssName              },
1043         { "--check-stack",      0,      OptCheckStack           },
1044         { "--code-label",       1,      OptCodeLabel            },
1045         { "--code-name",        1,      OptCodeName             },
1046         { "--codesize",         1,      OptCodeSize             },
1047         { "--cpu",              1,      OptCPU                  },
1048         { "--create-dep",       0,      OptCreateDep            },
1049         { "--data-label",       1,      OptDataLabel            },
1050         { "--data-name",        1,      OptDataName             },
1051         { "--debug",            0,      OptDebug                },
1052         { "--debug-info",       0,      OptDebugInfo            },
1053         { "--feature",          1,      OptFeature              },
1054         { "--help",             0,      OptHelp                 },
1055         { "--include-dir",      1,      OptIncludeDir           },
1056         { "--listing",          0,      OptListing              },
1057         { "--mapfile",          1,      OptMapFile              },
1058         { "--module",           0,      OptModule               },
1059         { "--module-id",        1,      OptModuleId             },
1060         { "--o65-model",        1,      OptO65Model             },
1061         { "--register-space",   1,      OptRegisterSpace        },
1062         { "--register-vars",    0,      OptRegisterVars         },
1063         { "--rodata-name",      1,      OptRodataName           },
1064         { "--signed-chars",     0,      OptSignedChars          },
1065         { "--start-addr",       1,      OptStartAddr            },
1066         { "--static-locals",    0,      OptStaticLocals         },
1067         { "--target",           1,      OptTarget               },
1068         { "--verbose",          0,      OptVerbose              },
1069         { "--version",          0,      OptVersion              },
1070         { "--zeropage-label",   1,      OptZeropageLabel        },
1071         { "--zeropage-name",    1,      OptZeropageName         },
1072     };
1073
1074     unsigned I;
1075
1076     /* Initialize the cmdline module */
1077     InitCmdLine (&argc, &argv, "cl65");
1078
1079     /* Initialize the command descriptors */
1080     CmdInit (&CC65, "cc65");
1081     CmdInit (&CA65, "ca65");
1082     CmdInit (&CO65, "co65");
1083     CmdInit (&LD65, "ld65");
1084     CmdInit (&GRC,  "grc");
1085
1086     /* Our default target is the C64 instead of "none" */
1087     Target = TGT_C64;
1088
1089     /* Check the parameters */
1090     I = 1;
1091     while (I < ArgCount) {
1092
1093         /* Get the argument */
1094         const char* Arg = ArgVec[I];
1095
1096         /* Check for an option */
1097         if (Arg [0] == '-') {
1098
1099             switch (Arg [1]) {
1100
1101                 case '-':
1102                     LongOption (&I, OptTab, sizeof(OptTab)/sizeof(OptTab[0]));
1103                     break;
1104
1105                 case 'A':
1106                     /* Strict ANSI mode (compiler) */
1107                     OptAnsi (Arg, 0);
1108                     break;
1109
1110                 case 'C':
1111                     if (Arg[2] == 'l' && Arg[3] == '\0') {
1112                         /* Make local variables static */
1113                         OptStaticLocals (Arg, 0);
1114                     } else {
1115                         /* Specify linker config file */
1116                         LinkerConfig = GetArg (&I, 2);
1117                     }
1118                     break;
1119
1120                 case 'D':
1121                     /* Define a preprocessor symbol (compiler) */
1122                     CmdAddArg2 (&CC65, "-D", GetArg (&I, 2));
1123                     break;
1124
1125                 case 'I':
1126                     /* Include directory (compiler) */
1127                     OptIncludeDir (Arg, GetArg (&I, 2));
1128                     break;
1129
1130                 case 'L':
1131                     if (Arg[2] == 'n') {
1132                         /* VICE label file (linker) */
1133                         CmdAddArg2 (&LD65, "-Ln", GetArg (&I, 3));
1134                     } else {
1135                         UnknownOption (Arg);
1136                     }
1137                     break;
1138
1139                 case 'O':
1140                     /* Optimize code (compiler, also covers -Oi and others) */
1141                     CmdAddArg (&CC65, Arg);
1142                     break;
1143
1144                 case 'S':
1145                     /* Dont assemble and link the created files */
1146                     DontLink = DontAssemble = 1;
1147                     break;
1148
1149                 case 'T':
1150                     /* Include source as comment (compiler) */
1151                     OptAddSource (Arg, 0);
1152                     break;
1153
1154                 case 'V':
1155                     /* Print version number */
1156                     OptVersion (Arg, 0);
1157                     break;
1158
1159                 case 'W':
1160                     /* Suppress warnings - compiler and assembler */
1161                     CmdAddArg (&CC65, "-W");
1162                     CmdAddArg2 (&CA65, "-W", "0");
1163                     break;
1164
1165                 case 'c':
1166                     /* Don't link the resulting files */
1167                     DontLink = 1;
1168                     break;
1169
1170                 case 'd':
1171                     /* Debug mode (compiler) */
1172                     OptDebug (Arg, 0);
1173                     break;
1174
1175                 case 'g':
1176                     /* Debugging - add to compiler and assembler */
1177                     OptDebugInfo (Arg, 0);
1178                     break;
1179
1180                 case 'h':
1181                 case '?':
1182                     /* Print help - cl65 */
1183                     OptHelp (Arg, 0);
1184                     break;
1185
1186                 case 'j':
1187                     /* Default characters are signed */
1188                     OptSignedChars (Arg, 0);
1189                     break;
1190
1191                 case 'l':
1192                     /* Create an assembler listing */
1193                     OptListing (Arg, 0);
1194                     break;
1195
1196                 case 'm':
1197                     /* Create a map file (linker) */
1198                     OptMapFile (Arg, GetArg (&I, 2));
1199                     break;
1200
1201                 case 'o':
1202                     /* Name the output file */
1203                     OutputName = GetArg (&I, 2);
1204                     break;
1205
1206                 case 'r':
1207                     /* Enable register variables */
1208                     OptRegisterVars (Arg, 0);
1209                     break;
1210
1211                 case 't':
1212                     /* Set target system - compiler, assembler and linker */
1213                     OptTarget (Arg, GetArg (&I, 2));
1214                     break;
1215
1216                 case 'v':
1217                     if (Arg [2] == 'm') {
1218                         /* Verbose map file (linker) */
1219                         CmdAddArg (&LD65, "-vm");
1220                     } else {
1221                         /* Verbose mode (compiler, assembler, linker) */
1222                         OptVerbose (Arg, 0);
1223                     }
1224                     break;
1225
1226                 default:
1227                     UnknownOption (Arg);
1228             }
1229         } else {
1230
1231             /* Remember the first file name */
1232             if (FirstInput == 0) {
1233                 FirstInput = Arg;
1234             }
1235
1236             /* Determine the file type by the extension */
1237             switch (GetFileType (Arg)) {
1238
1239                 case FILETYPE_C:
1240                     /* Compile the file */
1241                     Compile (Arg);
1242                     break;
1243
1244                 case FILETYPE_ASM:
1245                     /* Assemble the file */
1246                     if (!DontAssemble) {
1247                         Assemble (Arg);
1248                     }
1249                     break;
1250
1251                 case FILETYPE_OBJ:
1252                 case FILETYPE_LIB:
1253                     /* Add to the linker files */
1254                     CmdAddFile (&LD65, Arg);
1255                     break;
1256
1257                 case FILETYPE_GR:
1258                     /* Add to the resource compiler files */
1259                     CompileRes (Arg);
1260                     break;
1261
1262                 case FILETYPE_O65:
1263                     /* Add the the object file converter files */
1264                     ConvertO65 (Arg);
1265                     break;
1266
1267                 default:
1268                     Error ("Don't know what to do with `%s'", Arg);
1269
1270             }
1271
1272         }
1273
1274         /* Next argument */
1275         ++I;
1276     }
1277
1278     /* Check if we had any input files */
1279     if (FirstInput == 0) {
1280         Warning ("No input files");
1281     }
1282
1283     /* Link the given files if requested and if we have any */
1284     if (DontLink == 0 && LD65.FileCount > 0) {
1285         Link ();
1286     }
1287
1288     /* Return an apropriate exit code */
1289     return EXIT_SUCCESS;
1290 }
1291
1292
1293