]> git.sur5r.net Git - cc65/blobdiff - src/cc65/main.c
Move the Debug flag into a new module "debugflag" in the common directory.
[cc65] / src / cc65 / main.c
index b8ecc4fd8ec55edaa42d95396160ff9d0923fb27..8b1dc23b1147a423d3bdf0772c0682951e84fc7e 100644 (file)
@@ -6,10 +6,10 @@
 /*                                                                           */
 /*                                                                           */
 /*                                                                           */
-/* (C) 2000      Ullrich von Bassewitz                                       */
+/* (C) 2000-2002 Ullrich von Bassewitz                                       */
 /*               Wacholderweg 14                                             */
 /*               D-70597 Stuttgart                                           */
-/* EMail:        uz@musoftware.de                                            */
+/* EMail:        uz@cc65.org                                                 */
 /*                                                                           */
 /*                                                                           */
 /* This software is provided 'as-is', without any expressed or implied       */
 #include <stdio.h>
 #include <string.h>
 #include <stdlib.h>
-#include <ctype.h>
 #include <errno.h>
 
 /* common */
 #include "abend.h"
+#include "chartype.h"
 #include "cmdline.h"
+#include "debugflag.h"
 #include "fname.h"
+#include "print.h"
+#include "segdefs.h"
 #include "target.h"
+#include "tgttrans.h"
 #include "version.h"
 #include "xmalloc.h"
 
 /* cc65 */
 #include "asmcode.h"
 #include "compile.h"
+#include "codeopt.h"
 #include "cpu.h"
 #include "error.h"
 #include "global.h"
 #include "incpath.h"
 #include "input.h"
 #include "macrotab.h"
-#include "optimize.h"
 #include "scanner.h"
-#include "segname.h"
+#include "segments.h"
 
 
 
@@ -73,13 +77,6 @@ static void Usage (void)
     fprintf (stderr,
             "Usage: %s [options] file\n"
             "Short options:\n"
-                    "  -d\t\t\tDebug mode\n"
-                    "  -g\t\t\tAdd debug info to object file\n"
-                    "  -h\t\t\tHelp (this text)\n"
-                    "  -j\t\t\tDefault characters are signed\n"
-                    "  -o name\t\tName the output file\n"
-                    "  -t sys\t\tSet the target system\n"
-                    "  -v\t\t\tIncrease verbosity\n"
                     "  -A\t\t\tStrict ANSI mode\n"
                     "  -Cl\t\t\tMake local variables static\n"
                     "  -Dsym[=defn]\t\tDefine a symbol\n"
@@ -91,17 +88,35 @@ static void Usage (void)
                     "  -T\t\t\tInclude source as comment\n"
                     "  -V\t\t\tPrint the compiler version number\n"
                     "  -W\t\t\tSuppress warnings\n"
+                    "  -d\t\t\tDebug mode\n"
+                    "  -g\t\t\tAdd debug info to object file\n"
+                    "  -h\t\t\tHelp (this text)\n"
+                    "  -j\t\t\tDefault characters are signed\n"
+                    "  -o name\t\tName the output file\n"
+             "  -r\t\t\tEnable register variables\n"
+                    "  -t sys\t\tSet the target system\n"
+                    "  -v\t\t\tIncrease verbosity\n"
             "\n"
             "Long options:\n"
+                    "  --add-source\t\tInclude source as comment\n"
                     "  --ansi\t\tStrict ANSI mode\n"
             "  --bss-name seg\tSet the name of the BSS segment\n"
+                    "  --check-stack\t\tGenerate stack overflow checks\n"
                     "  --code-name seg\tSet the name of the CODE segment\n"
+            "  --codesize x\t\tAccept larger code by factor x\n"
                     "  --cpu type\t\tSet cpu type\n"
+            "  --create-dep\t\tCreate a make dependency file\n"
                     "  --data-name seg\tSet the name of the DATA segment\n"
                     "  --debug\t\tDebug mode\n"
                     "  --debug-info\t\tAdd debug info to object file\n"
+            "  --debug-opt name\tDebug optimization steps\n"
+            "  --disable-opt name\tDisable an optimization step\n"
+                    "  --enable-opt name\tEnable an optimization step\n"
             "  --help\t\tHelp (this text)\n"
                     "  --include-dir dir\tSet an include directory search path\n"
+            "  --list-opt-steps\tList all optimizer steps and exit\n"
+             "  --register-space b\tSet space available for register variables\n"
+             "  --register-vars\tEnable register variables\n"
                     "  --rodata-name seg\tSet the name of the RODATA segment\n"
                     "  --signed-chars\tDefault characters are signed\n"
                     "  --static-locals\tMake local variables static\n"
@@ -116,8 +131,8 @@ static void Usage (void)
 static void cbmsys (const char* sys)
 /* Define a CBM system */
 {
-    AddNumericMacro ("__CBM__", 1);
-    AddNumericMacro (sys, 1);
+    DefineNumericMacro ("__CBM__", 1);
+    DefineNumericMacro (sys, 1);
 }
 
 
@@ -130,14 +145,26 @@ static void SetSys (const char* Sys)
        case TGT_NONE:
            break;
 
+        case TGT_MODULE:
+            AbEnd ("Cannot use `module' as a target for the compiler");
+            break;
+
        case TGT_ATARI:
-           AddNumericMacro ("__ATARI__", 1);
+           DefineNumericMacro ("__ATARI__", 1);
+           break;
+
+       case TGT_C16:
+           cbmsys ("__C16__");
            break;
 
        case TGT_C64:
            cbmsys ("__C64__");
            break;
 
+       case TGT_VIC20:
+           cbmsys ("__VIC20__");
+           break;
+
        case TGT_C128:
            cbmsys ("__C128__");
            break;
@@ -150,6 +177,10 @@ static void SetSys (const char* Sys)
            cbmsys ("__PLUS4__");
            break;
 
+       case TGT_CBM510:
+           cbmsys ("__CBM510__");
+           break;
+
        case TGT_CBM610:
            cbmsys ("__CBM610__");
            break;
@@ -158,22 +189,60 @@ static void SetSys (const char* Sys)
            cbmsys ("__PET__");
            break;
 
-       case TGT_NES:
-           AddNumericMacro ("__NES__", 1);
+       case TGT_BBC:
+           DefineNumericMacro ("__BBC__", 1);
            break;
 
        case TGT_APPLE2:
-           AddNumericMacro ("__APPLE2__", 1);
+           DefineNumericMacro ("__APPLE2__", 1);
            break;
 
        case TGT_GEOS:
            /* Do not handle as a CBM system */
-           AddNumericMacro ("__GEOS__", 1);
+           DefineNumericMacro ("__GEOS__", 1);
            break;
 
+       case TGT_LUNIX:
+           DefineNumericMacro ("__LUNIX__", 1);
+           break;
+
+        case TGT_ATMOS:
+            DefineNumericMacro ("__ATMOS__", 1);
+            break;
+
        default:
                    AbEnd ("Unknown target system type");
     }
+
+    /* Initialize the translation tables for the target system */
+    TgtTranslateInit ();
+}
+
+
+
+static void DoCreateDep (const char* OutputName)
+/* Create the dependency file */
+{
+    /* Make the dependency file name from the output file name */
+    char* DepName = MakeFilename (OutputName, ".u");
+
+    /* Open the file */
+    FILE* F = fopen (DepName, "w");
+    if (F == 0) {
+       Fatal ("Cannot open dependency file `%s': %s", DepName, strerror (errno));
+    }
+
+    /* Write the dependencies to the file */
+    WriteDependencies (F, OutputName);
+
+    /* Close the file, check for errors */
+    if (fclose (F) != 0) {
+       remove (DepName);
+       Fatal ("Cannot write to dependeny file (disk full?)");
+    }
+
+    /* Free the name */
+    xfree (DepName);
 }
 
 
@@ -184,12 +253,12 @@ static void DefineSym (const char* Def)
     const char* P = Def;
 
     /* The symbol must start with a character or underline */
-    if (Def [0] != '_' && !isalpha (Def [0])) {
+    if (Def [0] != '_' && !IsAlpha (Def [0])) {
        InvDef (Def);
     }
 
     /* Check the symbol name */
-    while (isalnum (*P) || *P == '_') {
+    while (IsAlNum (*P) || *P == '_') {
        ++P;
     }
 
@@ -199,7 +268,7 @@ static void DefineSym (const char* Def)
            InvDef (Def);
        }
        /* No value given. Define the macro with the value 1 */
-       AddNumericMacro (Def, 1);
+       DefineNumericMacro (Def, 1);
     } else {
        /* We have a value, P points to the '=' character. Since the argument
         * is const, create a copy and replace the '=' in the copy by a zero
@@ -207,13 +276,13 @@ static void DefineSym (const char* Def)
                 */
        char* Q;
        unsigned Len = strlen (Def)+1;
-       char* S = xmalloc (Len);
+       char* S = (char*) xmalloc (Len);
        memcpy (S, Def, Len);
        Q = S + (P - Def);
        *Q++ = '\0';
 
        /* Define this as a macro */
-       AddTextMacro (S, Q);
+       DefineTextMacro (S, Q);
 
        /* Release the allocated memory */
        xfree (S);
@@ -233,7 +302,8 @@ static void CheckSegName (const char* Seg)
 
 
 
-static void OptAddSource (const char* Opt, const char* Arg)
+static void OptAddSource (const char* Opt attribute ((unused)),
+                         const char* Arg attribute ((unused)))
 /* Add source lines as comments in generated assembler file */
 {
     AddSource = 1;
@@ -241,7 +311,8 @@ static void OptAddSource (const char* Opt, const char* Arg)
 
 
 
-static void OptAnsi (const char* Opt, const char* Arg)
+static void OptAnsi (const char* Opt attribute ((unused)),
+                    const char* Arg attribute ((unused)))
 /* Compile in strict ANSI mode */
 {
     ANSI = 1;
@@ -249,14 +320,9 @@ static void OptAnsi (const char* Opt, const char* Arg)
 
 
 
-static void OptBssName (const char* Opt, const char* Arg)
+static void OptBssName (const char* Opt attribute ((unused)), const char* Arg)
 /* Handle the --bss-name option */
 {
-    /* Must have a segment name */
-    if (Arg == 0) {
-       NeedArg (Opt);
-    }
-
     /* Check for a valid name */
     CheckSegName (Arg);
 
@@ -266,14 +332,18 @@ static void OptBssName (const char* Opt, const char* Arg)
 
 
 
-static void OptCodeName (const char* Opt, const char* Arg)
-/* Handle the --code-name option */
+static void OptCheckStack (const char* Opt attribute ((unused)),
+                          const char* Arg attribute ((unused)))
+/* Handle the --check-stack option */
 {
-    /* Must have a segment name */
-    if (Arg == 0) {
-       NeedArg (Opt);
-    }
+    CheckStack = 1;
+}
+
 
+
+static void OptCodeName (const char* Opt attribute ((unused)), const char* Arg)
+/* Handle the --code-name option */
+{
     /* Check for a valid name */
     CheckSegName (Arg);
 
@@ -283,31 +353,45 @@ static void OptCodeName (const char* Opt, const char* Arg)
 
 
 
+static void OptCodeSize (const char* Opt, const char* Arg)
+/* Handle the --codesize option */
+{
+    /* Numeric argument expected */
+    if (sscanf (Arg, "%u", &CodeSizeFactor) != 1 ||
+       CodeSizeFactor < 100 ||
+               CodeSizeFactor > 1000) {
+       AbEnd ("Argument for %s is invalid", Opt);
+    }
+}
+
+
+
+static void OptCreateDep (const char* Opt attribute ((unused)),
+                         const char* Arg attribute ((unused)))
+/* Handle the --create-dep option */
+{
+    CreateDep = 1;
+}
+
+
+
 static void OptCPU (const char* Opt, const char* Arg)
 /* Handle the --cpu option */
 {
-    if (Arg == 0) {
-       NeedArg (Opt);
-    }
     if (strcmp (Arg, "6502") == 0) {
                CPU = CPU_6502;
     } else if (strcmp (Arg, "65C02") == 0) {
        CPU = CPU_65C02;
     } else {
-       AbEnd ("Invalid CPU: `%s'", Arg);
+               AbEnd ("Invalid argument for %s: `%s'", Opt, Arg);
     }
 }
 
 
 
-static void OptDataName (const char* Opt, const char* Arg)
-/* Handle the --code-name option */
+static void OptDataName (const char* Opt attribute ((unused)), const char* Arg)
+/* Handle the --data-name option */
 {
-    /* Must have a segment name */
-    if (Arg == 0) {
-       NeedArg (Opt);
-    }
-
     /* Check for a valid name */
     CheckSegName (Arg);
 
@@ -317,15 +401,17 @@ static void OptDataName (const char* Opt, const char* Arg)
 
 
 
-static void OptDebug (const char* Opt, const char* Arg)
+static void OptDebug (const char* Opt attribute ((unused)),
+                     const char* Arg attribute ((unused)))
 /* Compiler debug mode */
 {
-    Debug = 1;
+    ++Debug; 
 }
 
 
 
-static void OptDebugInfo (const char* Opt, const char* Arg)
+static void OptDebugInfo (const char* Opt attribute ((unused)),
+                         const char* Arg attribute ((unused)))
 /* Add debug info to the object file */
 {
     DebugInfo = 1;
@@ -333,7 +419,91 @@ static void OptDebugInfo (const char* Opt, const char* Arg)
 
 
 
-static void OptHelp (const char* Opt, const char* Arg)
+static void OptDebugOpt (const char* Opt attribute ((unused)), const char* Arg)
+/* Debug optimization steps */
+{
+    char Buf [128];
+    char* Line;
+
+    /* Open the file */
+    FILE* F = fopen (Arg, "r");
+    if (F == 0) {
+               AbEnd ("Cannot open `%s': %s", Arg, strerror (errno));
+    }
+
+    /* Read line by line, ignore empty lines and switch optimization
+     * steps on/off.
+     */
+    while (fgets (Buf, sizeof (Buf), F) != 0) {
+
+       /* Remove trailing control chars. This will also remove the
+        * trailing newline.
+        */
+       unsigned Len = strlen (Buf);
+       while (Len > 0 && IsControl (Buf[Len-1])) {
+           --Len;
+       }
+       Buf[Len] = '\0';
+
+       /* Get a pointer to the buffer and remove leading white space */
+       Line = Buf;
+       while (IsBlank (*Line)) {
+           ++Line;
+       }
+
+       /* Check the first character and enable/disable the step or
+        * ignore the line
+        */
+       switch (*Line) {
+
+           case '\0':
+           case '#':
+           case ';':
+               /* Empty or comment line */
+               continue;
+
+           case '-':
+               DisableOpt (Line+1);
+               break;
+
+           case '+':
+               ++Line;
+               /* FALLTHROUGH */
+
+           default:
+               EnableOpt (Line);
+               break;
+
+       }
+
+    }
+
+    /* Close the file, no error check here since we were just reading and
+     * this is only a debug function.
+     */
+    (void) fclose (F);
+}
+
+
+
+static void OptDisableOpt (const char* Opt attribute ((unused)), const char* Arg)
+/* Disable an optimization step */
+{
+    DisableOpt (Arg);
+}
+
+
+
+static void OptEnableOpt (const char* Opt attribute ((unused)), const char* Arg)
+/* Enable an optimization step */
+{
+    EnableOpt (Arg);
+}
+
+
+
+static void OptHelp (const char* Opt attribute ((unused)),
+                    const char* Arg attribute ((unused)))
 /* Print usage information and exit */
 {
     Usage ();
@@ -342,25 +512,50 @@ static void OptHelp (const char* Opt, const char* Arg)
 
 
 
-static void OptIncludeDir (const char* Opt, const char* Arg)
+static void OptIncludeDir (const char* Opt attribute ((unused)), const char* Arg)
 /* Add an include search path */
 {
-    if (Arg == 0) {
-       NeedArg (Opt);
-    }
     AddIncludePath (Arg, INC_SYS | INC_USER);
 }
 
 
 
-static void OptRodataName (const char* Opt, const char* Arg)
-/* Handle the --rodata-name option */
+static void OptListOptSteps (const char* Opt attribute ((unused)),
+                            const char* Arg attribute ((unused)))
+/* List all optimizer steps */
 {
-    /* Must have a segment name */
-    if (Arg == 0) {
-       NeedArg (Opt);
+    /* List the optimizer steps */
+    ListOptSteps (stdout);
+
+    /* Terminate */
+    exit (EXIT_SUCCESS);
+}
+
+
+
+static void OptRegisterSpace (const char* Opt, const char* Arg)
+/* Handle the --register-space option */
+{
+    /* Numeric argument expected */
+    if (sscanf (Arg, "%u", &RegisterSpace) != 1 || RegisterSpace > 256) {
+               AbEnd ("Argument for option %s is invalid", Opt);
     }
+}
+
 
+
+static void OptRegisterVars (const char* Opt attribute ((unused)),
+                             const char* Arg attribute ((unused)))
+/* Handle the --register-vars option */
+{
+    EnableRegVars = 1;
+}
+
+
+
+static void OptRodataName (const char* Opt attribute ((unused)), const char* Arg)
+/* Handle the --rodata-name option */
+{
     /* Check for a valid name */
     CheckSegName (Arg);
 
@@ -370,7 +565,8 @@ static void OptRodataName (const char* Opt, const char* Arg)
 
 
 
-static void OptSignedChars (const char* Opt, const char* Arg)
+static void OptSignedChars (const char* Opt attribute ((unused)),
+                           const char* Arg attribute ((unused)))
 /* Make default characters signed */
 {
     SignedChars = 1;
@@ -378,7 +574,8 @@ static void OptSignedChars (const char* Opt, const char* Arg)
 
 
 
-static void OptStaticLocals (const char* Opt, const char* Arg)
+static void OptStaticLocals (const char* Opt attribute ((unused)),
+                            const char* Arg attribute ((unused)))
 /* Place local variables in static storage */
 {
     StaticLocals = 1;
@@ -386,26 +583,25 @@ static void OptStaticLocals (const char* Opt, const char* Arg)
 
 
 
-static void OptTarget (const char* Opt, const char* Arg)
+static void OptTarget (const char* Opt attribute ((unused)), const char* Arg)
 /* Set the target system */
 {
-    if (Arg == 0) {
-       NeedArg (Opt);
-    }
     SetSys (Arg);
 }
 
 
 
-static void OptVerbose (const char* Opt, const char* Arg)
+static void OptVerbose (const char* Opt attribute ((unused)),
+                       const char* Arg attribute ((unused)))
 /* Increase verbosity */
 {
-    ++Verbose;
+    ++Verbosity;
 }
 
 
 
-static void OptVersion (const char* Opt, const char* Arg)
+static void OptVersion (const char* Opt attribute ((unused)),
+                       const char* Arg attribute ((unused)))
 /* Print the assembler version */
 {
     fprintf (stderr,
@@ -419,44 +615,53 @@ int main (int argc, char* argv[])
 {
     /* Program long options */
     static const LongOpt OptTab[] = {
-       { "--add-source",       0,      OptAddSource            },
-       { "--ansi",             0,      OptAnsi                 },
-       { "--bss-name",         1,      OptBssName              },
-       { "--code-name",        1,      OptCodeName             },
-        { "--cpu",                     1,      OptCPU                  },
-       { "--data-name",        1,      OptDataName             },
-               { "--debug",            0,      OptDebug                },
-       { "--debug-info",       0,      OptDebugInfo            },
-       { "--help",             0,      OptHelp                 },
+       { "--add-source",       0,      OptAddSource            },
+       { "--ansi",             0,      OptAnsi                 },
+       { "--bss-name",         1,      OptBssName              },
+               { "--check-stack",      0,      OptCheckStack           },
+       { "--code-name",        1,      OptCodeName             },
+       { "--codesize",         1,      OptCodeSize             },
+        { "--cpu",                     1,      OptCPU                  },
+       { "--create-dep",       0,      OptCreateDep            },
+       { "--data-name",        1,      OptDataName             },
+               { "--debug",            0,      OptDebug                },
+       { "--debug-info",       0,      OptDebugInfo            },
+        { "--debug-opt",        1,      OptDebugOpt             },
+       { "--disable-opt",      1,      OptDisableOpt           },
+       { "--enable-opt",       1,      OptEnableOpt,           },
+       { "--help",             0,      OptHelp                 },
        { "--include-dir",      1,      OptIncludeDir           },
-       { "--rodata-name",      1,      OptRodataName           },
-       { "--signed-chars",     0,      OptSignedChars          },
-               { "--static-locals",    0,      OptStaticLocals         },
-       { "--target",           1,      OptTarget               },
-       { "--verbose",          0,      OptVerbose              },
-       { "--version",          0,      OptVersion              },
+       { "--list-opt-steps",   0,      OptListOptSteps         },
+        { "--register-space",   1,      OptRegisterSpace        },
+        { "--register-vars",    0,      OptRegisterVars         },
+       { "--rodata-name",      1,      OptRodataName           },
+       { "--signed-chars",     0,      OptSignedChars          },
+               { "--static-locals",    0,      OptStaticLocals         },
+       { "--target",           1,      OptTarget               },
+       { "--verbose",          0,      OptVerbose              },
+       { "--version",          0,      OptVersion              },
     };
 
-    int I;
+    unsigned I;
 
     /* Initialize the output file name */
     const char* OutputFile = 0;
     const char* InputFile  = 0;
 
     /* Initialize the cmdline module */
-    InitCmdLine (argc, argv, "cc65");
+    InitCmdLine (&argc, &argv, "cc65");
 
     /* Initialize the default segment names */
     InitSegNames ();
 
     /* Parse the command line */
     I = 1;
-    while (I < argc) {
+    while (I < ArgCount) {
 
        const char* P;
 
                /* Get the argument */
-               const char* Arg = argv [I];
+               const char* Arg = ArgVec[I];
 
                /* Check for an option */
                if (Arg [0] == '-') {
@@ -488,10 +693,18 @@ int main (int argc, char* argv[])
                    OutputFile = GetArg (&I, 2);
                    break;
 
+                case 'r':
+                    OptRegisterVars (Arg, 0);
+                    break;
+
                case 't':
                    OptTarget (Arg, GetArg (&I, 2));
                    break;
 
+               case 'u':
+                   OptCreateDep (Arg, 0);
+                   break;
+
                case 'v':
                    OptVerbose (Arg, 0);
                    break;
@@ -507,9 +720,9 @@ int main (int argc, char* argv[])
                            case 'l':
                                OptStaticLocals (Arg, 0);
                                break;
-                           default:
-                               UnknownOption (Arg);
-                               break;
+                           default:
+                               UnknownOption (Arg);
+                               break;
                        }
                    }
                    break;
@@ -524,21 +737,22 @@ int main (int argc, char* argv[])
 
                case 'O':
                    Optimize = 1;
-                   P = Arg + 2;
+                   P = Arg + 2;
                    while (*P) {
                        switch (*P++) {
-                           case 'f':
-                               sscanf (P, "%lx", (long*) &OptDisable);
+                           case 'f':
+                               sscanf (P, "%lx", (long*) &OptDisable);
                                break;
                            case 'i':
                                FavourSize = 0;
+                               CodeSizeFactor = 200;
                                break;
                            case 'r':
-                               EnableRegVars = 1;
-                               break;
+                               EnableRegVars = 1;
+                               break;
                            case 's':
                                InlineStdFuncs = 1;
-                               break;
+                               break;
                        }
                    }
                    break;
@@ -576,31 +790,30 @@ int main (int argc, char* argv[])
        AbEnd ("No input files");
     }
 
-    /* Open the input file */
-    OpenMainFile (InputFile);
-
     /* Create the output file name if it was not explicitly given */
     if (OutputFile == 0) {
        OutputFile = MakeFilename (InputFile, ".s");
     }
 
     /* Go! */
-    Compile ();
+    Compile (InputFile);
 
     /* Create the output file if we didn't had any errors */
     if (ErrorCount == 0 || Debug) {
 
        FILE* F;
 
-       /* Optimize the output if requested */
-       if (Optimize) {
-           OptDoOpt ();
-       }
+#if 0
+       /* Optimize the output if requested */
+       if (Optimize) {
+           OptDoOpt ();
+       }
+#endif
 
        /* Open the file */
        F = fopen (OutputFile, "w");
        if (F == 0) {
-           Fatal (FAT_CANNOT_OPEN_OUTPUT, strerror (errno));
+           Fatal ("Cannot open output file `%s': %s", OutputFile, strerror (errno));
        }
 
        /* Write the output to the file */
@@ -609,8 +822,14 @@ int main (int argc, char* argv[])
        /* Close the file, check for errors */
        if (fclose (F) != 0) {
            remove (OutputFile);
-           Fatal (FAT_CANNOT_WRITE_OUTPUT);
+           Fatal ("Cannot write to output file (disk full?)");
        }
+
+       /* Create dependencies if requested */
+       if (CreateDep) {
+           DoCreateDep (OutputFile);
+       }
+
     }
 
     /* Return an apropriate exit code */