]> git.sur5r.net Git - cc65/blobdiff - src/co65/main.c
Move the version numbers from the interface of the version module into a new
[cc65] / src / co65 / main.c
index a206f56d5cb66f3daea3a4694486f58b26ac8e65..fe7ba8c7acb1aff14dc07ed82b194b052482cb24 100644 (file)
@@ -6,10 +6,10 @@
 /*                                                                           */
 /*                                                                           */
 /*                                                                           */
-/* (C) 2003      Ullrich von Bassewitz                                       */
-/*               Römerstrasse 52                                             */
-/*               D-70794 Filderstadt                                         */
-/* EMail:        uz@cc65.org                                                 */
+/* (C) 2003-2009, Ullrich von Bassewitz                                      */
+/*                Roemerstrasse 52                                           */
+/*                D-70794 Filderstadt                                        */
+/* EMail:         uz@cc65.org                                                */
 /*                                                                           */
 /*                                                                           */
 /* This software is provided 'as-is', without any expressed or implied       */
@@ -40,7 +40,9 @@
 #include <time.h>
 
 /* common */
+#include "chartype.h"
 #include "cmdline.h"
+#include "debugflag.h"
 #include "fname.h"
 #include "print.h"
 #include "segnames.h"
 #include "xsprintf.h"
 
 /* co65 */
+#include "convert.h"
 #include "error.h"
 #include "global.h"
+#include "model.h"
 #include "o65.h"
 
 
 static void Usage (void)
 /* Print usage information and exit */
 {
-    fprintf (stderr,
-            "Usage: %s [options] file\n"
-            "Short options:\n"
-                    "  -V\t\t\tPrint the version number\n"
-                    "  -g\t\t\tAdd debug info to object file\n"
-                    "  -h\t\t\tHelp (this text)\n"
-                    "  -o name\t\tName the output file\n"
-                    "  -v\t\t\tIncrease verbosity\n"
-            "\n"
-            "Long options:\n"
-            "  --bss-name seg\tSet the name of the BSS segment\n"
-                    "  --code-name seg\tSet the name of the CODE segment\n"
-                    "  --data-name seg\tSet the name of the DATA segment\n"
-                    "  --debug-info\t\tAdd debug info to object file\n"
-            "  --help\t\tHelp (this text)\n"
-                    "  --verbose\t\tIncrease verbosity\n"
-                    "  --version\t\tPrint the version number\n"
-                    "  --zeropage-name seg\tSet the name of the ZEROPAGE segment\n",
-            ProgName);
+    printf ("Usage: %s [options] file\n"
+            "Short options:\n"
+            "  -V\t\t\tPrint the version number\n"
+            "  -g\t\t\tAdd debug info to object file\n"
+            "  -h\t\t\tHelp (this text)\n"
+            "  -m model\t\tOverride the o65 model\n"
+            "  -n\t\t\tDon't generate an output file\n"
+            "  -o name\t\tName the output file\n"
+            "  -v\t\t\tIncrease verbosity\n"
+            "\n"
+            "Long options:\n"
+            "  --bss-label name\tDefine and export a BSS segment label\n"
+            "  --bss-name seg\tSet the name of the BSS segment\n"
+            "  --code-label name\tDefine and export a CODE segment label\n"
+            "  --code-name seg\tSet the name of the CODE segment\n"
+            "  --data-label name\tDefine and export a DATA segment label\n"
+            "  --data-name seg\tSet the name of the DATA segment\n"
+            "  --debug-info\t\tAdd debug info to object file\n"
+            "  --help\t\tHelp (this text)\n"
+            "  --no-output\t\tDon't generate an output file\n"
+            "  --o65-model model\tOverride the o65 model\n"
+            "  --verbose\t\tIncrease verbosity\n"
+            "  --version\t\tPrint the version number\n"
+            "  --zeropage-label name\tDefine and export a ZEROPAGE segment label\n"
+            "  --zeropage-name seg\tSet the name of the ZEROPAGE segment\n",
+            ProgName);
+}
+
+
+
+static void CheckLabelName (const char* Label)
+/* Check if the given label is a valid label name */
+{
+    const char* L = Label;
+
+    if (strlen (L) < 256 && (IsAlpha (*L) || *L== '_')) {
+        while (*++L) {
+            if (!IsAlNum (*L) && *L != '_') {
+                break;
+            }
+        }
+    }
+
+    if (*L) {
+        Error ("Label name `%s' is invalid", Label);
+    }
 }
 
 
@@ -98,6 +129,18 @@ static void CheckSegName (const char* Seg)
 
 
 
+static void OptBssLabel (const char* Opt attribute ((unused)), const char* Arg)
+/* Handle the --bss-label option */
+{
+    /* Check for a label name */
+    CheckLabelName (Arg);
+
+    /* Set the label */
+    BssLabel = xstrdup (Arg);
+}
+
+
+
 static void OptBssName (const char* Opt attribute ((unused)), const char* Arg)
 /* Handle the --bss-name option */
 {
@@ -110,6 +153,18 @@ static void OptBssName (const char* Opt attribute ((unused)), const char* Arg)
 
 
 
+static void OptCodeLabel (const char* Opt attribute ((unused)), const char* Arg)
+/* Handle the --code-label option */
+{
+    /* Check for a label name */
+    CheckLabelName (Arg);
+
+    /* Set the label */
+    CodeLabel = xstrdup (Arg);
+}
+
+
+
 static void OptCodeName (const char* Opt attribute ((unused)), const char* Arg)
 /* Handle the --code-name option */
 {
@@ -122,6 +177,18 @@ static void OptCodeName (const char* Opt attribute ((unused)), const char* Arg)
 
 
 
+static void OptDataLabel (const char* Opt attribute ((unused)), const char* Arg)
+/* Handle the --data-label option */
+{
+    /* Check for a label name */
+    CheckLabelName (Arg);
+
+    /* Set the label */
+    DataLabel = xstrdup (Arg);
+}
+
+
+
 static void OptDataName (const char* Opt attribute ((unused)), const char* Arg)
 /* Handle the --data-name option */
 {
@@ -134,6 +201,15 @@ static void OptDataName (const char* Opt attribute ((unused)), const char* Arg)
 
 
 
+static void OptDebug (const char* Opt attribute ((unused)),
+                     const char* Arg attribute ((unused)))
+/* Enable debugging code */
+{
+    ++Debug;
+}
+
+
+
 static void OptDebugInfo (const char* Opt attribute ((unused)),
                          const char* Arg attribute ((unused)))
 /* Add debug info to the object file */
@@ -153,245 +229,83 @@ static void OptHelp (const char* Opt attribute ((unused)),
 
 
 
-static void OptVerbose (const char* Opt attribute ((unused)),
-                       const char* Arg attribute ((unused)))
-/* Increase verbosity */
+static void OptNoOutput (const char* Opt attribute ((unused)),
+                        const char* Arg attribute ((unused)))
+/* Handle the --no-output option */
 {
-    ++Verbosity;
+    NoOutput = 1;
 }
 
 
 
-static void OptVersion (const char* Opt attribute ((unused)),
-                       const char* Arg attribute ((unused)))
-/* Print the assembler version */
+static void OptO65Model (const char* Opt attribute ((unused)), const char* Arg)
+/* Handle the --o65-model option */
 {
-    fprintf (stderr,
-                    "co65 V%u.%u.%u - (C) Copyright 1998-2003 Ullrich von Bassewitz\n",
-                    VER_MAJOR, VER_MINOR, VER_PATCH);
+    /* Search for the model name */
+    Model = FindModel (Arg);
+    if (Model == O65_MODEL_INVALID) {
+        Error ("Unknown o65 model `%s'", Arg);
+    }
 }
 
 
 
-static void OptZeropageName (const char* Opt attribute ((unused)), const char* Arg)
-/* Handle the --zeropage-name option */
+static void OptVerbose (const char* Opt attribute ((unused)),
+                       const char* Arg attribute ((unused)))
+/* Increase verbosity */
 {
-    /* Check for a valid name */
-    CheckSegName (Arg);
-
-    /* Set the name */
-    ZeropageSeg = xstrdup (Arg);
+    ++Verbosity;
 }
 
 
 
-static const char* SegReloc (const O65Data* D, const O65Reloc* R, unsigned long Val)
+static void OptVersion (const char* Opt attribute ((unused)),
+                       const char* Arg attribute ((unused)))
+/* Print the assembler version */
 {
-    static char Buf[256];
-    const O65Import* Import;
-
-    switch (R->SegID) {
-
-        case O65_SEGID_UNDEF:
-            if (R->SymIdx >= CollCount (&D->Imports)) {
-                Error ("Import index out of range (input file corrupt)");
-            }
-            Import = CollConstAt (&D->Imports, R->SymIdx);
-            xsprintf (Buf, sizeof (Buf), "%s%+ld", Import->Name, (long) Val);
-            break;
-
-        case O65_SEGID_TEXT:
-            xsprintf (Buf, sizeof (Buf), "%s%+ld", CodeSeg, (long) (Val - D->Header.tbase));
-            break;
-
-        case O65_SEGID_DATA:
-            xsprintf (Buf, sizeof (Buf), "%s%+ld", DataSeg, (long) (Val - D->Header.dbase));
-            break;
-
-        case O65_SEGID_BSS:
-            xsprintf (Buf, sizeof (Buf), "%s%+ld", BssSeg, (long) (Val - D->Header.bbase));
-            break;
-
-        case O65_SEGID_ZP:
-            xsprintf (Buf, sizeof (Buf), "%s%+ld", ZeropageSeg, (long) Val - D->Header.zbase);
-            break;
-
-        case O65_SEGID_ABS:
-            Error ("Relocation entry contains O65_SEGID_ABS");
-            break;
-
-        default:
-            Internal ("Cannot handle this segment reference in reloc entry");
-    }
-
-    return Buf;
+    fprintf (stderr,
+                    "co65 V%s - (C) Copyright 1998-2009 Ullrich von Bassewitz\n",
+                    GetVersionAsString ());
 }
 
 
 
-static void ConvertSeg (FILE* F, const O65Data* D, const Collection* Relocs,
-                        const unsigned char* Data, unsigned long Size)
-/* Convert one segment */
+static void OptZeropageLabel (const char* Opt attribute ((unused)), const char* Arg)
+/* Handle the --zeropage-label option */
 {
-    const O65Reloc* R;
-    unsigned        RIdx;
-    unsigned long   Byte;
-
-    /* Get the pointer to the first relocation entry if there are any */
-    R = (CollCount (Relocs) > 0)? CollConstAt (Relocs, 0) : 0;
-
-    /* Initialize for the loop */
-    RIdx = 0;
-    Byte = 0;
-
-    /* Walk over the segment data */
-    while (Byte < Size) {
-
-        if (R && R->Offs == Byte) {
-            /* We've reached an entry that must be relocated */
-            unsigned long Val;
-            switch (R->Type) {
-
-                case O65_RTYPE_WORD:
-                    if (Byte >= Size - 1) {
-                        Error ("Found WORD relocation, but not enough bytes left");
-                    } else {
-                        Val = (Data[Byte+1] << 8) + Data[Byte];
-                        Byte += 2;
-                        fprintf (F, "\t.word\t%s\n", SegReloc (D, R, Val));
-                    }
-                    break;
+    /* Check for a label name */
+    CheckLabelName (Arg);
 
-                case O65_RTYPE_HIGH:
-                    Val = (Data[Byte++] << 8) + R->Val;
-                    fprintf (F, "\t.byte\t>(%s)\n", SegReloc (D, R, Val));
-                    break;
+    /* Set the label */
+    ZeropageLabel = xstrdup (Arg);
+}
 
-                case O65_RTYPE_LOW:
-                    Val = Data[Byte++];
-                    fprintf (F, "\t.byte\t<(%s)\n", SegReloc (D, R, Val));
-                    break;
 
-                case O65_RTYPE_SEGADDR:
-                    if (Byte >= Size - 2) {
-                        Error ("Found SEGADDR relocation, but not enough bytes left");
-                    } else {
-                        Val = (((unsigned long) Data[Byte+2]) << 16) +
-                              (((unsigned long) Data[Byte+1]) <<  8) +
-                              (((unsigned long) Data[Byte+0]) <<  0) +
-                              R->Val;
-                        Byte += 3;
-                        fprintf (F, "\t.faraddr\t%s\n", SegReloc (D, R, Val));
-                    }
-                    break;
-                case O65_RTYPE_SEG:
-                default:
-                    Internal ("Invalid relocation type at %lu", Byte);
-            }
-
-            /* Get the next relocation entry */
-            if (++RIdx < CollCount (Relocs)) {
-                R = CollConstAt (Relocs, RIdx);
-            } else {
-                R = 0;
-            }
 
-        } else {
-            /* Just a constant value */
-            fprintf (F, "\t.byte\t$%02X\n", Data[Byte++]);
-        }
-    }
+static void OptZeropageName (const char* Opt attribute ((unused)), const char* Arg)
+/* Handle the --zeropage-name option */
+{
+    /* Check for a valid name */
+    CheckSegName (Arg);
 
-    fprintf (F, "\n");
+    /* Set the name */
+    ZeropageSeg = xstrdup (Arg);
 }
 
 
 
-static void Convert (void)
+static void DoConversion (void)
 /* Do file conversion */
 {
-    FILE* F;
-    unsigned  I;
-
     /* Read the o65 file into memory */
-    O65Data* D = ReadO65File (InFilename);
-
-    /* For now, we do only accept o65 files generated by the ld65 linker which
-     * have a specific format.
-     */
-    if (D->Header.mode != O65_MODE_CC65) {
-        Error ("Cannot convert o65 files of this type");
-    }
-
-    printf ("Textsize:   %lu\n", D->Header.tlen);
-    printf ("Datasize:   %lu\n", D->Header.dlen);
-    printf ("Imports:    %u\n", CollCount (&D->Imports));
-    printf ("Exports:    %u\n", CollCount (&D->Exports));
-    printf ("Textrelocs: %u\n", CollCount (&D->TextReloc));
-    printf ("Datarelocs: %u\n", CollCount (&D->DataReloc));
-
-    /* Open the output file */
-    F = fopen (OutFilename, "wb");
-    if (F == 0) {
-        Error ("Cannot open `%s': %s", OutFilename, strerror (errno));
-    }
-
-    /* Create a header */
-    if ((D->Header.mode & O65_CPU_MASK) == O65_CPU_65816) {
-       fprintf (F, "\t.p816\n");
-    }
-    fprintf (F, ";\n; File generated by co65 v %u.%u.%u\n;\n",
-             VER_MAJOR, VER_MINOR, VER_PATCH);
-    fprintf (F, "\t.fopt\t\tcompiler,\"co65 v %u.%u.%u\"\n",
-             VER_MAJOR, VER_MINOR, VER_PATCH);
-    fprintf (F, "\t.case\t\ton\n");
-    fprintf (F, "\t.debuginfo\t%s\n", (DebugInfo != 0)? "on" : "off");
-    fprintf (F, "\n");
-
-    /* Imported identifiers */
-    if (CollCount (&D->Imports) > 0) {
-        for (I = 0; I < CollCount (&D->Imports); ++I) {
-
-            /* Get the next import */
-            O65Import* Import = CollAtUnchecked (&D->Imports, I);
-
-            /* Import it by name */
-            fprintf (F, "\t.import\t%s\n", Import->Name);
-        }
-        fprintf (F, "\n");
-    }
-
-    /* Exported identifiers */
-    if (CollCount (&D->Exports) > 0) {
-        for (I = 0; I < CollCount (&D->Exports); ++I) {
-
-            /* Get the next import */
-            O65Export* Export = CollAtUnchecked (&D->Exports, I);
-
-            /* Import it by name */
-            fprintf (F, "\t.export\t%s\n", Export->Name);
-        }
-        fprintf (F, "\n");
-    }
+    O65Data* D = ReadO65File (InputName);
 
-    /* Code segment */
-    fprintf (F, ".segment\t\"%s\"\n", CodeSeg);
-    fprintf (F, "%s:\n", CodeSeg);
-    ConvertSeg (F, D, &D->TextReloc, D->Text, D->Header.tlen);
-
-    /* Data segment */
-    fprintf (F, ".segment\t\"%s\"\n", DataSeg);
-    fprintf (F, "%s:\n", DataSeg);
-    ConvertSeg (F, D, &D->DataReloc, D->Data, D->Header.dlen);
+    /* Do the conversion */
+    Convert (D);
 
-    /* BSS segment */
-    fprintf (F, ".segment\t\"%s\"\n", BssSeg);
-    fprintf (F, "%s:\n", BssSeg);
-    fprintf (F, "\t.res\t%lu\n", D->Header.blen);
-    fprintf (F, "\n");
+    /* Free the o65 module data */
+    /* ### */
 
-    fprintf (F, "\t.end\n");
-    fclose (F);
 }
 
 
@@ -401,13 +315,20 @@ int main (int argc, char* argv [])
 {
     /* Program long options */
     static const LongOpt OptTab[] = {
+               { "--bss-label",        1,      OptBssLabel             },
        { "--bss-name",         1,      OptBssName              },
+               { "--code-label",       1,      OptCodeLabel            },
        { "--code-name",        1,      OptCodeName             },
+               { "--data-label",       1,      OptDataLabel            },
        { "--data-name",        1,      OptDataName             },
+               { "--debug",            0,      OptDebug                },
        { "--debug-info",       0,      OptDebugInfo            },
-       { "--help",             0,      OptHelp                 },
+       { "--help",             0,      OptHelp                 },
+               { "--no-output",        0,      OptNoOutput             },
+        { "--o65-model",        1,      OptO65Model             },
        { "--verbose",          0,      OptVerbose              },
        { "--version",          0,      OptVersion              },
+               { "--zeropage-label",   1,      OptZeropageLabel        },
                { "--zeropage-name",    1,      OptZeropageName         },
     };
 
@@ -439,8 +360,16 @@ int main (int argc, char* argv [])
                    OptHelp (Arg, 0);
                    break;
 
+                case 'm':
+                    OptO65Model (Arg, GetArg (&I, 2));
+                    break;
+
+                case 'n':
+                    OptNoOutput (Arg, 0);
+                    break;
+
                        case 'o':
-                           OutFilename = GetArg (&I, 2);
+                           OutputName = GetArg (&I, 2);
                            break;
 
                        case 'v':
@@ -458,10 +387,10 @@ int main (int argc, char* argv [])
            }
                } else {
            /* Filename. Check if we already had one */
-           if (InFilename) {
+           if (InputName) {
                Error ("Don't know what to do with `%s'\n", Arg);
            } else {
-               InFilename = Arg;
+               InputName = Arg;
            }
        }
 
@@ -470,17 +399,17 @@ int main (int argc, char* argv [])
     }
 
     /* Do we have an input file? */
-    if (InFilename == 0) {
+    if (InputName == 0) {
                Error ("No input file\n");
     }
 
     /* Generate the name of the output file if none was specified */
-    if (OutFilename == 0) {
-        OutFilename = MakeFilename (InFilename, AsmExt);
+    if (OutputName == 0) {
+        OutputName = MakeFilename (InputName, AsmExt);
     }
 
     /* Do the conversion */
-    Convert ();
+    DoConversion ();
 
     /* Return an apropriate exit code */
     return EXIT_SUCCESS;