commit 0abcb12fbbf199fa561da03794326e242b94018d
Author: Fabian Greffrath <fabian@greffrath.com>
AuthorDate: Fri May 24 14:24:21 2019 +0200
Commit: Fabian Greffrath <fabian@greffrath.com>
CommitDate: Fri May 24 14:24:21 2019 +0200
allow for loading WAD files and DEHACKED patches by drag-and-drop (take 3)
Compose a proper command line from loose file paths passed as
arguments. This allows for loading WAD files and DEHACKED patches by
dragging them onto the game executable in e.g. Windows Explorer.
Completely new implementation turned into a sorting problem and
extended with some heuristics to make sure the command line only
consists of fully-qualified path names.
Fixes #1161.
---
src/Makefile.am | 3 ++
src/d_iwad.c | 15 ++++++
src/d_iwad.h | 1 +
src/i_main.c | 6 +++
src/m_argv.c | 149 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++
src/m_argv.h | 1 +
6 files changed, 175 insertions(+)
diff --git a/src/Makefile.am b/src/Makefile.am
index 4c29e90f..e54aeead 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -35,8 +35,11 @@ m_misc.c m_misc.h
DEDSERV_FILES=\
d_dedicated.c \
+d_iwad.c d_iwad.h \
d_mode.c d_mode.h \
+deh_str.c deh_str.h \
i_timer.c i_timer.h \
+m_config.c m_config.h \
net_common.c net_common.h \
net_dedicated.c net_dedicated.h \
net_io.c net_io.h \
diff --git a/src/d_iwad.c b/src/d_iwad.c
index 75ae0bab..5d68b2f6 100644
--- a/src/d_iwad.c
+++ b/src/d_iwad.c
@@ -50,6 +50,21 @@ static const iwad_t iwads[] =
{ "strife1.wad", strife, commercial, "Strife" },
};
+boolean D_IsIWADName(const char *name)
+{
+ int i;
+
+ for (i = 0; i < arrlen(iwads); i++)
+ {
+ if (!strcasecmp(name, iwads[i].name))
+ {
+ return true;
+ }
+ }
+
+ return false;
+}
+
// Array of locations to search for IWAD files
//
// "128 IWAD search directories should be enough for anybody".
diff --git a/src/d_iwad.h b/src/d_iwad.h
index 2f68fe66..7aba9d66 100644
--- a/src/d_iwad.h
+++ b/src/d_iwad.h
@@ -39,6 +39,7 @@ typedef struct
const char *description;
} iwad_t;
+boolean D_IsIWADName(const char *name);
char *D_FindWADByName(const char *filename);
char *D_TryFindWADByName(const char *filename);
char *D_FindIWAD(int mask, GameMission_t *mission);
diff --git a/src/i_main.c b/src/i_main.c
index 22c46180..4afad7d0 100644
--- a/src/i_main.c
+++ b/src/i_main.c
@@ -49,6 +49,12 @@ int main(int argc, char **argv)
exit(0);
}
+#if defined(_WIN32)
+ // compose a proper command line from loose file paths passed as arguments
+ // to allow for loading WADs and DEHACKED patches by drag-and-drop
+ M_AddLooseFiles();
+#endif
+
M_FindResponseFile();
#ifdef SDL_HINT_NO_SIGNAL_HANDLERS
diff --git a/src/m_argv.c b/src/m_argv.c
index 00462db0..992d5cfb 100644
--- a/src/m_argv.c
+++ b/src/m_argv.c
@@ -21,7 +21,10 @@
#include <stdlib.h>
#include <string.h>
+#include "SDL_stdinc.h"
+
#include "doomtype.h"
+#include "d_iwad.h"
#include "i_system.h"
#include "m_misc.h"
#include "m_argv.h" // haleyjd 20110212: warning fix
@@ -261,6 +264,152 @@ void M_FindResponseFile(void)
}
}
+#if defined(_WIN32)
+enum
+{
+ FILETYPE_UNKNOWN = 0x0,
+ FILETYPE_IWAD = 0x2,
+ FILETYPE_PWAD = 0x4,
+ FILETYPE_DEH = 0x8,
+};
+
+static int GuessFileType(const char *name)
+{
+ int ret = FILETYPE_UNKNOWN;
+ const char *base;
+ char *lower;
+ static boolean iwad_found = false;
+
+ base = M_BaseName(name);
+ lower = M_StringDuplicate(base);
+ M_ForceLowercase(lower);
+
+ // only ever add one argument to the -iwad parameter
+
+ if (iwad_found == false && D_IsIWADName(lower))
+ {
+ ret = FILETYPE_IWAD;
+ iwad_found = true;
+ }
+ else if (M_StringEndsWith(lower, ".wad") ||
+ M_StringEndsWith(lower, ".lmp"))
+ {
+ ret = FILETYPE_PWAD;
+ }
+ else if (M_StringEndsWith(lower, ".deh") ||
+// M_StringEndsWith(lower, ".bex") ||
+ M_StringEndsWith(lower, ".hhe") ||
+ M_StringEndsWith(lower, ".seh"))
+ {
+ ret = FILETYPE_DEH;
+ }
+
+ free(lower);
+
+ return ret;
+}
+
+typedef struct
+{
+ char *str;
+ int type, stable;
+} argument_t;
+
+static int CompareByFileType(const void *a, const void *b)
+{
+ const argument_t *arg_a = (const argument_t *) a;
+ const argument_t *arg_b = (const argument_t *) b;
+
+ const int ret = arg_a->type - arg_b->type;
+
+ return ret ? ret : (arg_a->stable - arg_b->stable);
+}
+
+void M_AddLooseFiles(void)
+{
+ int i, types = 0;
+ char **newargv;
+ argument_t *arguments;
+
+ if (myargc < 2)
+ {
+ return;
+ }
+
+ // allocate space for up to three additional regular parameters
+
+ arguments = malloc((myargc + 3) * sizeof(*arguments));
+ memset(arguments, 0, (myargc + 3) * sizeof(*arguments));
+
+ // check the command line and make sure it does not already
+ // contain any regular parameters or response files
+ // but only fully-qualified LFS or UNC file paths
+
+ for (i = 1; i < myargc; i++)
+ {
+ char *arg = myargv[i];
+ int type;
+
+ if (strlen(arg) < 3 ||
+ arg[0] == '-' ||
+ arg[0] == '@' ||
+ ((!isalpha(arg[0]) || arg[1] != ':' || arg[2] != '\\') &&
+ (arg[0] != '\\' || arg[1] != '\\')))
+ {
+ free(arguments);
+ return;
+ }
+
+ type = GuessFileType(arg);
+ arguments[i].str = arg;
+ arguments[i].type = type;
+ arguments[i].stable = i;
+ types |= type;
+ }
+
+ // add space for one additional regular parameter
+ // for each discovered file type in the new argument list
+ // and sort parameters right before their corresponding file paths
+
+ if (types & FILETYPE_IWAD)
+ {
+ arguments[myargc].str = M_StringDuplicate("-iwad");
+ arguments[myargc].type = FILETYPE_IWAD - 1;
+ myargc++;
+ }
+ if (types & FILETYPE_PWAD)
+ {
+ arguments[myargc].str = M_StringDuplicate("-merge");
+ arguments[myargc].type = FILETYPE_PWAD - 1;
+ myargc++;
+ }
+ if (types & FILETYPE_DEH)
+ {
+ arguments[myargc].str = M_StringDuplicate("-deh");
+ arguments[myargc].type = FILETYPE_DEH - 1;
+ myargc++;
+ }
+
+ newargv = malloc(myargc * sizeof(*newargv));
+
+ // sort the argument list by file type, except for the zeroth argument
+ // which is the executable invocation itself
+
+ SDL_qsort(arguments + 1, myargc - 1, sizeof(*arguments), CompareByFileType);
+
+ newargv[0] = myargv[0];
+
+ for (i = 1; i < myargc; i++)
+ {
+ newargv[i] = arguments[i].str;
+ }
+
+ free(arguments);
+
+ myargv = newargv;
+}
+#endif
+
// Return the name of the executable used to start the program:
const char *M_GetExecutableName(void)
diff --git a/src/m_argv.h b/src/m_argv.h
index 6c364ec9..482f29a2 100644
--- a/src/m_argv.h
+++ b/src/m_argv.h
@@ -37,6 +37,7 @@ int M_CheckParm (const char* check);
int M_CheckParmWithArgs(const char *check, int num_args);
void M_FindResponseFile(void);
+void M_AddLooseFiles(void);
// Parameter has been specified?