/*****************************************************************************/
/* */
-/* cmdline.c */
+/* cmdline.c */
/* */
-/* Helper functions for command line parsing */
+/* Helper functions for command line parsing */
/* */
/* */
/* */
-/* (C) 2000 Ullrich von Bassewitz */
-/* Wacholderweg 14 */
-/* D-70597 Stuttgart */
-/* EMail: uz@musoftware.de */
+/* (C) 2000-2009, Ullrich von Bassewitz */
+/* Roemerstrasse 52 */
+/* D-70794 Filderstadt */
+/* EMail: uz@cc65.org */
/* */
/* */
/* This software is provided 'as-is', without any expressed or implied */
/* common */
#include "abend.h"
#include "chartype.h"
+#include "fname.h"
#include "xmalloc.h"
#include "cmdline.h"
/*****************************************************************************/
-/* Data */
+/* Data */
/*****************************************************************************/
/* 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 */
+ char** Vec; /* The argument vector */
+ unsigned Count; /* Actual number of arguments */
+ unsigned Size; /* Number of argument allocated */
} CmdLine;
/*****************************************************************************/
-/* Helper functions */
+/* Helper functions */
/*****************************************************************************/
static void NewCmdLine (CmdLine* L)
/* Initialize a CmdLine struct */
{
- unsigned I;
-
/* Initialize the struct */
L->Size = 8;
L->Count = 0;
L->Vec = xmalloc (L->Size * sizeof (L->Vec[0]));
-
- /* Copy the arguments. We have to allocate them on free store, otherwise
- * we would have to keep track which one is on free store and which not,
- * which is a lot more overhead.
- */
- for (I = 0; I < L->Count; ++I) {
- L->Vec[I] = xstrdup (ArgVec[I]);
- }
}
-static void AddArg (CmdLine* L, const char* Arg)
+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;
+ /* 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++] = xstrdup (Arg);
+ 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.
- */
+** 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));
+ 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;
+ /* 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 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 leading spaces */
+ while (IsSpace (*B)) {
+ ++B;
+ }
- /* Skip empty lines to work around problems with some editors */
- if (*B == '\0') {
- continue;
- }
+ /* Skip empty lines to work around problems with some editors */
+ if (*B == '\0') {
+ continue;
+ }
- /* Add anything not empty to the command line */
- AddArg (L, B);
+ /* 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.
- */
+ ** reading only.
+ */
(void) fclose (F);
}
/*****************************************************************************/
-/* Code */
+/* Code */
/*****************************************************************************/
-void InitCmdLine (int* 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.
- */
+** a NULL pointer (as usual), ArgCount is the number of valid arguments in the
+** array. Both arguments are remembered in static storage.
+*/
{
- CmdLine L;
+ CmdLine L;
int I;
/* Get the program name from argv[0] but strip a path */
- if (*(aArgVec)[0] == 0) {
- /* Use the default name given */
- ProgName = aProgName;
+ if ((*aArgVec)[0] == 0) {
+ /* Use the default name given */
+ ProgName = aProgName;
} else {
- /* Strip a path */
- const char* FirstArg = (*aArgVec)[0];
- ProgName = strchr (FirstArg, '\0');
- while (ProgName > FirstArg) {
- --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) {
+ ** 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];
+ /* Get the next argument */
+ char* Arg = (*aArgVec)[I];
- /* Is this a file argument? */
- if (Arg && Arg[0] == '@') {
+ /* Is this a file argument? */
+ if (Arg && Arg[0] == '@') {
- /* Expand the file */
- ExpandFile (&L, Arg+1);
+ /* Expand the file */
+ ExpandFile (&L, Arg+1);
- } else {
+ } else {
- /* No file, just add a copy */
- AddArg (&L, Arg);
+ /* No file, just add a copy */
+ AddArg (&L, Arg);
- }
+ }
}
/* Store the new argument list in a safe place... */
- ArgCount = L.Count;
+ ArgCount = L.Count - 1;
ArgVec = L.Vec;
/* ...and pass back the changed data also */
- *aArgCount = L.Count;
+ *aArgCount = L.Count - 1;
*aArgVec = L.Vec;
}
void UnknownOption (const char* Opt)
/* Print an error about an unknown option and die. */
{
- AbEnd ("Unknown option: %s\n", Opt);
+ AbEnd ("Unknown option: %s", 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);
+}
+
+
+
+void InvArg (const char* Opt, const char* Arg)
+/* Print an error about an invalid option argument and exit. */
+{
+ AbEnd ("Invalid argument for %s: `%s'", Opt, Arg);
}
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 (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.
- */
+** option itself or may be separate. Len is the length of the option string.
+*/
{
const char* Arg = ArgVec[*ArgNum];
if (Arg[Len] != '\0') {
- /* Argument appended */
- return Arg + Len;
+ /* Argument appended */
+ return Arg + Len;
} else {
- /* Separate argument */
- Arg = ArgVec[*ArgNum + 1];
- if (Arg == 0) {
- /* End of arguments */
- NeedArg (ArgVec[*ArgNum]);
- }
- ++(*ArgNum);
- return Arg;
+ /* Separate argument */
+ Arg = ArgVec[*ArgNum + 1];
+ if (Arg == 0) {
+ /* End of arguments */
+ NeedArg (ArgVec[*ArgNum]);
+ }
+ ++(*ArgNum);
+ return Arg;
}
}
/* Search the table for a match */
while (OptCount) {
- if (strcmp (Opt, OptTab->Option) == 0) {
- /* Found, call the function */
- if (OptTab->ArgCount > 0) {
- /* 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);
- }
- /* Done */
- return;
- }
-
- /* Next table entry */
- --OptCount;
- ++OptTab;
+ if (strcmp (Opt, OptTab->Option) == 0) {
+ /* Found, call the function */
+ if (OptTab->ArgCount > 0) {
+ /* 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);
+ }
+ /* Done */
+ return;
+ }
+
+ /* Next table entry */
+ --OptCount;
+ ++OptTab;
}
/* Invalid option */
UnknownOption (Opt);
}
-
-
-