]> git.sur5r.net Git - cc65/blobdiff - src/common/cmdline.c
Added the lynx target
[cc65] / src / common / cmdline.c
index 3403cdd7cb2980edebe961b40e187913891fce7f..81d01863a192a326b9c97d4d297ad37db1a7f114 100644 (file)
 
 
 
+#include <stdio.h>
 #include <string.h>
+#include <errno.h>
 
+/* common */
 #include "abend.h"
+#include "chartype.h"
+#include "fname.h"
+#include "xmalloc.h"
 #include "cmdline.h"
 
 
 const char* ProgName;
 
 /* The program argument vector */
-static char** ArgVec     = 0;
-static unsigned ArgCount = 0;
+char** ArgVec     = 0;
+unsigned ArgCount = 0;
+
+/* Struct to pass the command line */
+typedef struct {
+    char**      Vec;            /* The argument vector */
+    unsigned           Count;          /* Actual number of arguments */
+    unsigned           Size;           /* Number of argument allocated */
+} CmdLine;
+
+
+
+/*****************************************************************************/
+/*                            Helper functions                              */
+/*****************************************************************************/
+
+
+
+static void NewCmdLine (CmdLine* L)
+/* Initialize a CmdLine struct */
+{
+    /* Initialize the struct */
+    L->Size    = 8;
+    L->Count   = 0;
+    L->Vec     = xmalloc (L->Size * sizeof (L->Vec[0]));
+}
+
+
+
+static void AddArg (CmdLine* L, char* Arg)
+/* Add one argument to the list */
+{
+    if (L->Size <= L->Count) {
+       /* No space left, reallocate */
+       unsigned NewSize = L->Size * 2;
+       char**   NewVec  = xmalloc (NewSize * sizeof (L->Vec[0]));
+       memcpy (NewVec, L->Vec, L->Count * sizeof (L->Vec[0]));
+       xfree (L->Vec);
+       L->Vec  = NewVec;
+       L->Size = NewSize;
+    }
+
+    /* We have space left, add a copy of the argument */
+    L->Vec[L->Count++] = Arg;
+}
+
+    
+
+static void ExpandFile (CmdLine* L, const char* Name)
+/* Add the contents of a file to the command line. Each line is a separate
+ * argument with leading and trailing whitespace removed.
+ */
+{
+    char Buf [256];
+
+    /* Try to open the file for reading */
+    FILE* F = fopen (Name, "r");
+    if (F == 0) {
+       AbEnd ("Cannot open \"%s\": %s", Name, strerror (errno));
+    }
+
+    /* File is open, read all lines */
+    while (fgets (Buf, sizeof (Buf), F) != 0) {
+
+       /* Get a pointer to the buffer */
+       const char* B = Buf;
+
+       /* Skip trailing whitespace (this will also kill the newline that is
+        * appended by fgets().
+        */
+       unsigned Len = strlen (Buf);
+       while (Len > 0 && IsSpace (Buf [Len-1])) {
+           --Len;
+       }
+       Buf [Len] = '\0';
+
+       /* Skip leading spaces */
+       while (IsSpace (*B)) {
+           ++B;
+       }
+
+       /* Skip empty lines to work around problems with some editors */
+       if (*B == '\0') {
+           continue;
+       }
+
+       /* Add anything not empty to the command line */
+       AddArg (L, xstrdup (B));
+
+    }
+
+    /* Close the file, ignore errors here since we had the file open for
+     * reading only.
+     */
+    (void) fclose (F);
+}
 
 
 
@@ -61,43 +161,69 @@ static unsigned ArgCount = 0;
 
 
 
-void InitCmdLine (unsigned aArgCount, char* aArgVec[], const char* aProgName)
+void InitCmdLine (int* aArgCount, char** aArgVec[], const char* aProgName)
 /* Initialize command line parsing. aArgVec is the argument array terminated by
  * a NULL pointer (as usual), ArgCount is the number of valid arguments in the
  * array. Both arguments are remembered in static storage.
  */
 {
-    /* Remember the argument vector */
-    ArgCount = aArgCount;
-    ArgVec   = aArgVec;
+    CmdLine    L;
+    int         I;
 
     /* Get the program name from argv[0] but strip a path */
-    if (ArgVec[0] == 0) {
-       /* Use the default name given */
-       ProgName = aProgName;
+    if (*(aArgVec)[0] == 0) {
+       /* Use the default name given */
+       ProgName = aProgName;
     } else {
-       /* Strip a path */
-       ProgName = strchr (ArgVec[0], '\0');
-       while (ProgName > ArgVec[0]) {
-           --ProgName;
-                   if (*ProgName == '/' || *ProgName == '\\') {
-               ++ProgName;
-               break;
-           }
-       }
-       if (ProgName[0] == '\0') {
-           /* Use the default */
-           ProgName = aProgName;
-       }
+       /* Strip a path */
+               ProgName = FindName ((*aArgVec)[0]);
+       if (ProgName[0] == '\0') {
+           /* Use the default */
+           ProgName = aProgName;
+       }
     }
+
+    /* Make a CmdLine struct */
+    NewCmdLine (&L);
+
+    /* Walk over the parameters and add them to the CmdLine struct. Add a
+     * special handling for arguments preceeded by the '@' sign - these are
+     * actually files containing arguments.
+     */
+    for (I = 0; I < *aArgCount; ++I) {
+
+       /* Get the next argument */
+       char* Arg = (*aArgVec)[I];
+
+       /* Is this a file argument? */
+       if (Arg && Arg[0] == '@') {
+
+           /* Expand the file */
+           ExpandFile (&L, Arg+1);
+
+       } else {
+
+           /* No file, just add a copy */
+           AddArg (&L, Arg);
+
+       }
+    }
+
+    /* Store the new argument list in a safe place... */
+    ArgCount = L.Count;
+    ArgVec   = L.Vec;
+
+    /* ...and pass back the changed data also */
+    *aArgCount = L.Count;
+    *aArgVec   = L.Vec;
 }
 
 
 
 void UnknownOption (const char* Opt)
-/* Print an error about an unknown option. */
+/* Print an error about an unknown option and die. */
 {
-    AbEnd ("Unknown option: %s\n", Opt);
+    AbEnd ("Unknown option: %s", Opt);
 }
 
 
@@ -105,7 +231,7 @@ void UnknownOption (const char* Opt)
 void NeedArg (const char* Opt)
 /* Print an error about a missing option argument and exit. */
 {
-    AbEnd ("Option requires an argument: %s\n", Opt);
+    AbEnd ("Option requires an argument: %s", Opt);
 }
 
 
@@ -113,12 +239,12 @@ void NeedArg (const char* Opt)
 void InvDef (const char* Def)
 /* Print an error about an invalid definition and die */
 {
-    AbEnd ("Invalid definition: `%s'\n", Def);
+    AbEnd ("Invalid definition: `%s'", Def);
 }
 
 
 
-const char* GetArg (int* ArgNum, unsigned Len)
+const char* GetArg (unsigned* ArgNum, unsigned Len)
 /* Get an argument for a short option. The argument may be appended to the
  * option itself or may be separate. Len is the length of the option string.
  */
@@ -141,7 +267,7 @@ const char* GetArg (int* ArgNum, unsigned Len)
 
 
 
-void LongOption (int* ArgNum, const LongOpt* OptTab, unsigned OptCount)
+void LongOption (unsigned* ArgNum, const LongOpt* OptTab, unsigned OptCount)
 /* Handle a long command line option */
 {
     /* Get the option and the argument (which may be zero) */
@@ -152,7 +278,12 @@ void LongOption (int* ArgNum, const LongOpt* OptTab, unsigned OptCount)
        if (strcmp (Opt, OptTab->Option) == 0) {
            /* Found, call the function */
            if (OptTab->ArgCount > 0) {
-               OptTab->Func (Opt, ArgVec[++(*ArgNum)]);
+               /* We need an argument, check if we have one */
+               const char* Arg = ArgVec[++(*ArgNum)];
+               if (Arg == 0) {
+                   NeedArg (Opt);
+               }
+               OptTab->Func (Opt, Arg);
            } else {
                OptTab->Func (Opt, 0);
            }
@@ -171,3 +302,4 @@ void LongOption (int* ArgNum, const LongOpt* OptTab, unsigned OptCount)
 
 
 
+