/* */
/* */
/* */
-/* (C) 1998 Ullrich von Bassewitz */
-/* Wacholderweg 14 */
-/* D-70597 Stuttgart */
-/* EMail: uz@musoftware.de */
-/* */
-/* */
+/* (C) 1998-2001 Ullrich von Bassewitz */
+/* Wacholderweg 14 */
+/* D-70597 Stuttgart */
+/* EMail: uz@musoftware.de */
+/* */
+/* */
/* This software is provided 'as-is', without any expressed or implied */
/* warranty. In no event will the authors be held liable for any damages */
/* arising from the use of this software. */
-/* */
+/* */
/* Permission is granted to anyone to use this software for any purpose, */
/* including commercial applications, and to alter it and redistribute it */
/* freely, subject to the following restrictions: */
-/* */
+/* */
/* 1. The origin of this software must not be misrepresented; you must not */
/* claim that you wrote the original software. If you use this software */
/* in a product, an acknowledgment in the product documentation would be */
/* be misrepresented as being the original software. */
/* 3. This notice may not be removed or altered from any source */
/* distribution. */
-/* */
+/* */
/*****************************************************************************/
#include <string.h>
#include <time.h>
-#include "../common/cmdline.h"
-#include "../common/version.h"
+/* common */
+#include "cmdline.h"
+#include "version.h"
#include "global.h"
#include "add.h"
int I;
/* Initialize the cmdline module */
- InitCmdLine (argc, argv, "ar65");
+ InitCmdLine (&argc, &argv, "ar65");
/* We must have a file name */
- if (argc < 2) {
+ if (ArgCount < 2) {
Usage ();
}
/* Check the parameters */
I = 1;
- while (I < argc) {
+ while (I < ArgCount) {
/* Get the argument */
- const char* Arg = argv [I];
+ const char* Arg = ArgVec [I];
/* Check for an option */
if (strlen (Arg) != 1) {
switch (Arg [0]) {
case 'a':
- AddObjFiles (argc - I - 1, &argv [I+1]);
+ AddObjFiles (ArgCount - I - 1, &ArgVec[I+1]);
break;
case 'd':
- DelObjFiles (argc - I - 1, &argv [I+1]);
+ DelObjFiles (ArgCount - I - 1, &ArgVec [I+1]);
break;
case 'l':
- ListObjFiles (argc - I - 1, &argv [I+1]);
+ ListObjFiles (ArgCount - I - 1, &ArgVec [I+1]);
break;
case 'v':
break;
case 'x':
- ExtractObjFiles (argc - I - 1, &argv [I+1]);
+ ExtractObjFiles (ArgCount - I - 1, &ArgVec [I+1]);
break;
case 'V':
int I;
/* Initialize the cmdline module */
- InitCmdLine (argc, argv, "ca65");
+ InitCmdLine (&argc, &argv, "ca65");
/* Enter the base lexical level. We must do that here, since we may
* define symbols using -D.
/* Check the parameters */
I = 1;
- while (I < argc) {
+ while (I < ArgCount) {
/* Get the argument */
- const char* Arg = argv [I];
+ const char* Arg = ArgVec [I];
/* Check for an option */
if (Arg [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] == '-') {
int I;
/* Initialize the cmdline module */
- InitCmdLine (argc, argv, "cl65");
+ InitCmdLine (&argc, &argv, "cl65");
/* Initialize the command descriptors */
CmdInit (&CC65, "cc65");
/* Our default target is the C64 instead of "none" */
Target = TGT_C64;
-
+
/* Check the parameters */
I = 1;
- while (I < argc) {
+ while (I < ArgCount) {
/* Get the argument */
- const char* Arg = argv [I];
+ const char* Arg = ArgVec[I];
/* Check for an option */
if (Arg [0] == '-') {
+int IsSpace (char C)
+/* Check for any white space characters */
+{
+ return (C == ' ' || C == '\n' || C == '\r' || C == '\t' || C == '\v' || C == '\f');
+}
+
+
+
int IsDigit (char C)
/* Check for a digit */
{
int IsBlank (char C);
/* Check for a space or tab */
+int IsSpace (char C);
+/* Check for any white space characters */
+
int IsDigit (char C);
/* Check for a digit */
+#include <stdio.h>
#include <string.h>
+#include <errno.h>
+/* common */
#include "abend.h"
+#include "chartype.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 */
+{
+ 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)
+/* 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++] = xstrdup (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, B);
+
+ }
+
+ /* Close the file, ignore errors here since we had the file open for
+ * reading only.
+ */
+ (void) fclose (F);
+}
-void InitCmdLine (unsigned aArgCount, char* aArgVec[], const char* aProgName)
+void InitCmdLine (unsigned* 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;
+ unsigned 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;
+ /* 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;
+ ++ProgName;
+ break;
+ }
+ }
+ 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;
}
/* Program name - is set after call to InitCmdLine */
extern const char* ProgName;
+/* The program argument vector */
+extern char** ArgVec;
+extern unsigned ArgCount;
+
/* Structure defining a long option */
typedef struct LongOpt LongOpt;
struct LongOpt {
-void InitCmdLine (unsigned aArgCount, char* aArgVec[], const char* aProgName);
+void InitCmdLine (unsigned* 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.
/* End of cmdline.h */
#endif
-
+
char* xstrdup (const char* S)
/* Duplicate a string on the heap. The function checks for out of memory */
{
- /* Get the length of the string */
- unsigned Len = strlen (S) + 1;
+ /* Allow dup'ing of NULL strings */
+ if (S) {
- /* Allocate memory and return a copy */
- return memcpy (xmalloc (Len), S, Len);
+ /* Get the length of the string */
+ unsigned Len = strlen (S) + 1;
+
+ /* Allocate memory and return a copy */
+ return memcpy (xmalloc (Len), S, Len);
+
+ } else {
+
+ /* Return a NULL pointer */
+ return 0;
+
+ }
}
/* Program long options */
static const LongOpt OptTab[] = {
{ "--cpu", 1, OptCPU },
- { "--formfeeds", 0, OptFormFeeds },
- { "--help", 0, OptHelp },
+ { "--formfeeds", 0, OptFormFeeds },
+ { "--help", 0, OptHelp },
{ "--pagelength", 1, OptPageLength },
- { "--start-addr", 1, OptStartAddr },
+ { "--start-addr", 1, OptStartAddr },
{ "--verbose", 0, OptVerbose },
{ "--version", 0, OptVersion },
};
int I;
/* Initialize the cmdline module */
- InitCmdLine (argc, argv, "da65");
+ InitCmdLine (&argc, &argv, "da65");
/* Check the parameters */
I = 1;
- while (I < argc) {
+ while (I < ArgCount) {
/* Get the argument */
- const char* Arg = argv [I];
+ const char* Arg = ArgVec[I];
/* Check for an option */
if (Arg [0] == '-') {
int I;
/* Initialize the cmdline module */
- InitCmdLine (argc, argv, "ld65");
+ InitCmdLine (&argc, &argv, "ld65");
/* Evaluate the CC65_LIB environment variable */
LibPath = getenv ("CC65_LIB");
/* Check the parameters */
I = 1;
- while (I < argc) {
+ while (I < ArgCount) {
/* Get the argument */
- const char* Arg = argv [I];
+ const char* Arg = ArgVec[I];
/* Check for an option */
if (Arg [0] == '-') {
" -V\t\t\tPrint the version number and exit\n"
"\n"
"Long options:\n"
- " --dump-all\t\tDump all object file information\n"
+ " --dump-all\t\tDump all object file information\n"
" --dump-dbgsyms\tDump debug symbols\n"
" --dump-exports\tDump exported symbols\n"
" --dump-files\t\tDump the source files\n"
/* Dump debug symbols contained in the object file */
{
What |= D_DBGSYMS;
-}
+}
int I;
/* Initialize the cmdline module */
- InitCmdLine (argc, argv, "od65");
+ InitCmdLine (&argc, &argv, "od65");
/* Check the parameters */
I = 1;
- while (I < argc) {
+ while (I < ArgCount) {
/* Get the argument */
- const char* Arg = argv [I];
+ const char* Arg = ArgVec[I];
/* Check for an option */
if (Arg [0] == '-') {