shithub: choc

Download patch

ref: 8cae6e48779beb3dc8e95a5c32b422b2504b5722
parent: 84552e7da9b4babc1c885d38088509faa733e7bb
author: Simon Howard <[email protected]>
date: Tue Sep 30 18:50:24 EDT 2008

Move d_iwad.c into common code and update Heretic to use it on startup
to locate the IWAD file.

Subversion-branch: /branches/raven-branch
Subversion-revision: 1308

--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -32,6 +32,7 @@
                      doomkeys.h            \
                      doomfeatures.h        \
                      doomtype.h            \
+d_iwad.c             d_iwad.h              \
 d_mode.c             d_mode.h              \
                      d_ticcmd.h            \
 i_cdmus.c            i_cdmus.h             \
--- /dev/null
+++ b/src/d_iwad.c
@@ -1,0 +1,637 @@
+// Emacs style mode select   -*- C++ -*- 
+//-----------------------------------------------------------------------------
+//
+// Copyright(C) 2006 Simon Howard
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// as published by the Free Software Foundation; either version 2
+// of the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+// 02111-1307, USA.
+//
+// DESCRIPTION:
+//     Search for and locate an IWAD file, and initialise according
+//     to the IWAD type.
+//
+//-----------------------------------------------------------------------------
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <ctype.h>
+#include <string.h>
+
+#include "deh_str.h"
+#include "doomkeys.h"
+#include "d_iwad.h"
+#include "i_system.h"
+#include "m_argv.h"
+#include "m_config.h"
+#include "m_misc.h"
+#include "w_wad.h"
+#include "z_zone.h"
+
+// Array of locations to search for IWAD files
+//
+// "128 IWAD search directories should be enough for anybody".
+
+#define MAX_IWAD_DIRS 128
+
+static boolean iwad_dirs_built = false;
+static char *iwad_dirs[MAX_IWAD_DIRS];
+static int num_iwad_dirs = 0;
+
+static void AddIWADDir(char *dir)
+{
+    if (num_iwad_dirs < MAX_IWAD_DIRS)
+    {
+        iwad_dirs[num_iwad_dirs] = dir;
+        ++num_iwad_dirs;
+    }
+}
+
+// This is Windows-specific code that automatically finds the location
+// of installed IWAD files.  The registry is inspected to find special
+// keys installed by the Windows installers for various CD versions
+// of Doom.  From these keys we can deduce where to find an IWAD.
+
+#ifdef _WIN32
+
+#define WIN32_LEAN_AND_MEAN
+#include <windows.h>
+
+typedef struct 
+{
+    HKEY root;
+    char *path;
+    char *value;
+} registry_value_t;
+
+#define UNINSTALLER_STRING "\\uninstl.exe /S "
+
+// Keys installed by the various CD editions.  These are actually the 
+// commands to invoke the uninstaller and look like this:
+//
+// C:\Program Files\Path\uninstl.exe /S C:\Program Files\Path
+//
+// With some munging we can find where Doom was installed.
+
+static registry_value_t uninstall_values[] = 
+{
+    // Ultimate Doom, CD version (Depths of Doom trilogy)
+
+    {
+        HKEY_LOCAL_MACHINE, 
+        "Software\\Microsoft\\Windows\\CurrentVersion\\"
+            "Uninstall\\Ultimate Doom for Windows 95",
+        "UninstallString",
+    },
+
+    // Doom II, CD version (Depths of Doom trilogy)
+
+    {
+        HKEY_LOCAL_MACHINE, 
+        "Software\\Microsoft\\Windows\\CurrentVersion\\"
+            "Uninstall\\Doom II for Windows 95",
+        "UninstallString",
+    },
+
+    // Final Doom
+
+    {
+        HKEY_LOCAL_MACHINE, 
+        "Software\\Microsoft\\Windows\\CurrentVersion\\"
+            "Uninstall\\Final Doom for Windows 95",
+        "UninstallString",
+    },
+
+    // Shareware version
+
+    {
+        HKEY_LOCAL_MACHINE, 
+        "Software\\Microsoft\\Windows\\CurrentVersion\\"
+            "Uninstall\\Doom Shareware for Windows 95",
+        "UninstallString",
+    },
+};
+
+// Value installed by the Collector's Edition when it is installed
+
+static registry_value_t collectors_edition_value =
+{
+    HKEY_LOCAL_MACHINE,
+    "Software\\Activision\\DOOM Collector's Edition\\v1.0",
+    "INSTALLPATH",
+};
+
+// Subdirectories of the above install path, where IWADs are installed.
+
+static char *collectors_edition_subdirs[] = 
+{
+    "Doom2",
+    "Final Doom",
+    "Ultimate Doom",
+};
+
+// Location where Steam is installed
+
+static registry_value_t steam_install_location =
+{
+    HKEY_LOCAL_MACHINE,
+    "Software\\Valve\\Steam",
+    "InstallPath",
+};
+
+// Subdirs of the steam install directory where IWADs are found
+
+static char *steam_install_subdirs[] =
+{
+    "steamapps\\common\\doom 2\\base",
+    "steamapps\\common\\final doom\\base",
+    "steamapps\\common\\ultimate doom\\base",
+};
+
+static char *GetRegistryString(registry_value_t *reg_val)
+{
+    HKEY key;
+    DWORD len;
+    DWORD valtype;
+    char *result;
+
+    // Open the key (directory where the value is stored)
+
+    if (RegOpenKeyEx(reg_val->root, reg_val->path, 0, KEY_READ, &key) 
+          != ERROR_SUCCESS)
+    {
+        return NULL;
+    }
+
+    // Find the type and length of the string
+
+    if (RegQueryValueEx(key, reg_val->value, NULL, &valtype, NULL, &len) 
+          != ERROR_SUCCESS)
+    {
+        return NULL;
+    }
+
+    // Only accept strings
+
+    if (valtype != REG_SZ)
+    {
+        return NULL;
+    }
+
+    // Allocate a buffer for the value and read the value
+
+    result = malloc(len);
+
+    if (RegQueryValueEx(key, reg_val->value, NULL, &valtype, (unsigned char *) result, &len) 
+          != ERROR_SUCCESS)
+    {
+        free(result);
+        return NULL;
+    }
+
+    // Close the key
+        
+    RegCloseKey(key);
+
+    return result;
+}
+
+// Check for the uninstall strings from the CD versions
+
+static void CheckUninstallStrings(void)
+{
+    unsigned int i;
+
+    for (i=0; i<arrlen(uninstall_values); ++i)
+    {
+        char *val;
+        char *path;
+        char *unstr;
+
+        val = GetRegistryString(&uninstall_values[i]);
+
+        if (val == NULL)
+        {
+            continue;
+        }
+
+        unstr = strstr(val, UNINSTALLER_STRING);
+
+        if (unstr == NULL)
+        {
+            free(val);
+        }
+        else
+        {
+            path = unstr + strlen(UNINSTALLER_STRING);
+
+            AddIWADDir(path);
+        }
+    }
+}
+
+// Check for Doom: Collector's Edition
+
+static void CheckCollectorsEdition(void)
+{
+    char *install_path;
+    char *subpath;
+    unsigned int i;
+
+    install_path = GetRegistryString(&collectors_edition_value);
+
+    if (install_path == NULL)
+    {
+        return;
+    }
+
+    for (i=0; i<arrlen(collectors_edition_subdirs); ++i)
+    {
+        subpath = malloc(strlen(install_path)
+                         + strlen(collectors_edition_subdirs[i])
+                         + 5);
+
+        sprintf(subpath, "%s\\%s", install_path, collectors_edition_subdirs[i]);
+
+        AddIWADDir(subpath);
+    }
+
+    free(install_path);
+}
+
+
+// Check for Doom downloaded via Steam
+
+static void CheckSteamEdition(void)
+{
+    char *install_path;
+    char *subpath;
+    size_t i;
+
+    install_path = GetRegistryString(&steam_install_location);
+
+    if (install_path == NULL)
+    {
+        return;
+    }
+
+    for (i=0; i<arrlen(steam_install_subdirs); ++i)
+    {
+        subpath = malloc(strlen(install_path) 
+                         + strlen(steam_install_subdirs[i]) + 5);
+
+        sprintf(subpath, "%s\\%s", install_path, steam_install_subdirs[i]);
+
+        AddIWADDir(subpath);
+    }
+}
+
+// Default install directories for DOS Doom
+
+static void CheckDOSDefaults(void)
+{
+    // These are the default install directories used by the deice
+    // installer program:
+
+    AddIWADDir("\\doom2");              // Doom II
+    AddIWADDir("\\plutonia");           // Final Doom
+    AddIWADDir("\\tnt");
+    AddIWADDir("\\doom_se");            // Ultimate Doom
+    AddIWADDir("\\doom");               // Shareware / Registered Doom
+    AddIWADDir("\\dooms");              // Shareware versions
+    AddIWADDir("\\doomsw");
+}
+
+#endif
+
+// Search a directory to try to find an IWAD
+// Returns the location of the IWAD if found, otherwise NULL.
+
+static char *SearchDirectoryForIWAD(char *dir, iwad_t *iwads,
+                                    GameMission_t *mission)
+{
+    size_t i;
+
+    for (i=0; iwads[i].name != NULL; ++i) 
+    {
+        char *filename; 
+        char *iwadname;
+
+        iwadname = DEH_String(iwads[i].name);
+        
+        filename = malloc(strlen(dir) + strlen(iwadname) + 3);
+
+        if (!strcmp(dir, "."))
+        {
+            strcpy(filename, iwadname);
+        }
+        else
+        {
+            sprintf(filename, "%s%c%s", dir, DIR_SEPARATOR, iwadname);
+        }
+
+        if (M_FileExists(filename))
+        {
+            *mission = iwads[i].mission;
+
+            return filename;
+        }
+
+        free(filename);
+    }
+
+    return NULL;
+}
+
+// When given an IWAD with the '-iwad' parameter,
+// attempt to identify it by its name.
+
+static GameMission_t IdentifyIWADByName(char *name, iwad_t *iwads)
+{
+    size_t i;
+    GameMission_t mission;
+
+    mission = none;
+    
+    for (i=0; iwads[i].name != NULL; ++i)
+    {
+        char *iwadname;
+
+        iwadname = DEH_String(iwads[i].name);
+
+        if (strlen(name) < strlen(iwadname))
+            continue;
+
+        // Check if it ends in this IWAD name.
+
+        if (!strcasecmp(name + strlen(name) - strlen(iwadname), 
+                        iwadname))
+        {
+            mission = iwads[i].mission;
+            break;
+        }
+    }
+
+    return mission;
+}
+
+//
+// Add directories from the list in the DOOMWADPATH environment variable.
+// 
+
+static void AddDoomWadPath(void)
+{
+    char *doomwadpath;
+    char *p;
+
+    // Check the DOOMWADPATH environment variable.
+
+    doomwadpath = getenv("DOOMWADPATH");
+
+    if (doomwadpath == NULL)
+    {
+        return;
+    }
+
+    doomwadpath = strdup(doomwadpath);
+
+    // Add the initial directory
+
+    AddIWADDir(doomwadpath);
+
+    // Split into individual dirs within the list.
+
+    p = doomwadpath;
+
+    for (;;)
+    {
+        p = strchr(p, PATH_SEPARATOR);
+
+        if (p != NULL)
+        {
+            // Break at the separator and store the right hand side
+            // as another iwad dir
+  
+            *p = '\0';
+            p += 1;
+
+            AddIWADDir(p);
+        }
+        else
+        {
+            break;
+        }
+    }
+}
+
+
+//
+// Build a list of IWAD files
+//
+
+static void BuildIWADDirList(void)
+{
+    char *doomwaddir;
+
+    if (iwad_dirs_built)
+    {
+        return;
+    }
+
+    // Look in the current directory.  Doom always does this.
+
+    AddIWADDir(".");
+
+    // Add DOOMWADDIR if it is in the environment
+
+    doomwaddir = getenv("DOOMWADDIR");
+
+    if (doomwaddir != NULL)
+    {
+        AddIWADDir(doomwaddir);
+    }        
+
+    // Add dirs from DOOMWADPATH
+
+    AddDoomWadPath();
+
+#ifdef _WIN32
+
+    // Search the registry and find where IWADs have been installed.
+
+    CheckUninstallStrings();
+    CheckCollectorsEdition();
+    CheckSteamEdition();
+    CheckDOSDefaults();
+
+#else
+
+    // Standard places where IWAD files are installed under Unix.
+
+    AddIWADDir("/usr/share/games/doom");
+    AddIWADDir("/usr/local/share/games/doom");
+
+#endif
+
+    // Don't run this function again.
+
+    iwad_dirs_built = true;
+}
+
+//
+// Searches WAD search paths for an WAD with a specific filename.
+// 
+
+char *D_FindWADByName(char *name)
+{
+    char *buf;
+    int i;
+    boolean exists;
+    
+    // Absolute path?
+
+    if (M_FileExists(name))
+    {
+        return name;
+    }
+
+    BuildIWADDirList();
+    
+    // Search through all IWAD paths for a file with the given name.
+
+    for (i=0; i<num_iwad_dirs; ++i)
+    {
+        // Construct a string for the full path
+
+        buf = malloc(strlen(iwad_dirs[i]) + strlen(name) + 5);
+        sprintf(buf, "%s%c%s", iwad_dirs[i], DIR_SEPARATOR, name);
+
+        exists = M_FileExists(buf);
+
+        if (exists)
+        {
+            return buf;
+        }
+
+        free(buf);
+    }
+
+    // File not found
+
+    return NULL;
+}
+
+//
+// D_TryWADByName
+//
+// Searches for a WAD by its filename, or passes through the filename
+// if not found.
+//
+
+char *D_TryFindWADByName(char *filename)
+{
+    char *result;
+
+    result = D_FindWADByName(filename);
+
+    if (result != NULL)
+    {
+        return result;
+    }
+    else
+    {
+        return filename;
+    }
+}
+
+//
+// FindIWAD
+// Checks availability of IWAD files by name,
+// to determine whether registered/commercial features
+// should be executed (notably loading PWADs).
+//
+
+char *D_FindIWAD(iwad_t *iwads, GameMission_t *mission)
+{
+    char *result;
+    char *iwadfile;
+    int iwadparm;
+    int i;
+
+    // Check for the -iwad parameter
+
+    //!
+    // Specify an IWAD file to use.
+    //
+    // @arg <file>
+    //
+
+    iwadparm = M_CheckParm("-iwad");
+
+    if (iwadparm)
+    {
+        // Search through IWAD dirs for an IWAD with the given name.
+
+        iwadfile = myargv[iwadparm + 1];
+
+        result = D_FindWADByName(iwadfile);
+
+        if (result == NULL)
+        {
+            I_Error("IWAD file '%s' not found!", iwadfile);
+        }
+        
+        *mission = IdentifyIWADByName(result, iwads);
+    }
+    else
+    {
+        // Search through the list and look for an IWAD
+
+        result = NULL;
+
+        BuildIWADDirList();
+    
+        for (i=0; result == NULL && i<num_iwad_dirs; ++i)
+        {
+            result = SearchDirectoryForIWAD(iwad_dirs[i], iwads, mission);
+        }
+    }
+
+    return result;
+}
+
+// Clever hack: Setup can invoke Doom to determine which IWADs are installed.
+// Doom searches install paths and exits with the return code being a 
+// bitmask of the installed IWAD files.
+
+void D_FindInstalledIWADs(iwad_t *iwads)
+{
+    unsigned int i;
+    int result;
+
+    BuildIWADDirList();
+
+    result = 0;
+
+    for (i=0; i<arrlen(iwads); ++i)
+    {
+        if (D_FindWADByName(iwads[i].name) != NULL)
+        {
+            result |= 1 << i;
+        }
+    }
+
+    exit(result);
+}
+
--- /dev/null
+++ b/src/d_iwad.h
@@ -1,0 +1,44 @@
+// Emacs style mode select   -*- C++ -*- 
+//-----------------------------------------------------------------------------
+//
+// Copyright(C) 2006 Simon Howard
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// as published by the Free Software Foundation; either version 2
+// of the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+// 02111-1307, USA.
+//
+// DESCRIPTION:
+//     Find IWAD and initialise according to IWAD type.
+//
+//-----------------------------------------------------------------------------
+
+
+#ifndef __D_IWAD__
+#define __D_IWAD__
+
+#include "d_mode.h"
+
+typedef struct
+{
+    char *name;
+    GameMission_t mission;
+} iwad_t;
+
+char *D_FindWADByName(char *filename);
+char *D_TryFindWADByName(char *filename);
+char *D_FindIWAD(iwad_t *iwads, GameMission_t *mission);
+void D_FindInstalledIWADs(iwad_t *iwads);
+
+#endif
+
--- a/src/d_mode.h
+++ b/src/d_mode.h
@@ -28,6 +28,8 @@
 #ifndef __D_MODE__
 #define __D_MODE__
 
+#include "doomtype.h"
+
 // The "mission" controls what game we are playing.
 
 typedef enum
--- a/src/doom/Makefile.am
+++ b/src/doom/Makefile.am
@@ -6,7 +6,6 @@
 am_map.c           am_map.h     \
                    d_englsh.h   \
 d_items.c          d_items.h    \
-d_iwad.c           d_iwad.h     \
 d_main.c           d_main.h     \
 d_net.c            d_net.h      \
                    doomdata.h   \
--- a/src/doom/d_iwad.c
+++ /dev/null
@@ -1,913 +1,0 @@
-// Emacs style mode select   -*- C++ -*- 
-//-----------------------------------------------------------------------------
-//
-// Copyright(C) 2006 Simon Howard
-//
-// This program is free software; you can redistribute it and/or
-// modify it under the terms of the GNU General Public License
-// as published by the Free Software Foundation; either version 2
-// of the License, or (at your option) any later version.
-//
-// This program is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-// GNU General Public License for more details.
-//
-// You should have received a copy of the GNU General Public License
-// along with this program; if not, write to the Free Software
-// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
-// 02111-1307, USA.
-//
-// DESCRIPTION:
-//     Search for and locate an IWAD file, and initialise according
-//     to the IWAD type.
-//
-//-----------------------------------------------------------------------------
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <ctype.h>
-#include <string.h>
-
-#include "deh_main.h"
-#include "doomkeys.h"
-#include "doomdef.h"
-#include "doomstat.h"
-#include "i_system.h"
-#include "m_argv.h"
-#include "m_config.h"
-#include "m_misc.h"
-#include "w_wad.h"
-#include "z_zone.h"
-
-// Array of locations to search for IWAD files
-//
-// "128 IWAD search directories should be enough for anybody".
-
-#define MAX_IWAD_DIRS 128
-
-static boolean iwad_dirs_built = false;
-static char *iwad_dirs[MAX_IWAD_DIRS];
-static int num_iwad_dirs = 0;
-
-static void AddIWADDir(char *dir)
-{
-    if (num_iwad_dirs < MAX_IWAD_DIRS)
-    {
-        iwad_dirs[num_iwad_dirs] = dir;
-        ++num_iwad_dirs;
-    }
-}
-
-// This is Windows-specific code that automatically finds the location
-// of installed IWAD files.  The registry is inspected to find special
-// keys installed by the Windows installers for various CD versions
-// of Doom.  From these keys we can deduce where to find an IWAD.
-
-#ifdef _WIN32
-
-#define WIN32_LEAN_AND_MEAN
-#include <windows.h>
-
-typedef struct 
-{
-    HKEY root;
-    char *path;
-    char *value;
-} registry_value_t;
-
-#define UNINSTALLER_STRING "\\uninstl.exe /S "
-
-// Keys installed by the various CD editions.  These are actually the 
-// commands to invoke the uninstaller and look like this:
-//
-// C:\Program Files\Path\uninstl.exe /S C:\Program Files\Path
-//
-// With some munging we can find where Doom was installed.
-
-static registry_value_t uninstall_values[] = 
-{
-    // Ultimate Doom, CD version (Depths of Doom trilogy)
-
-    {
-        HKEY_LOCAL_MACHINE, 
-        "Software\\Microsoft\\Windows\\CurrentVersion\\"
-            "Uninstall\\Ultimate Doom for Windows 95",
-        "UninstallString",
-    },
-
-    // Doom II, CD version (Depths of Doom trilogy)
-
-    {
-        HKEY_LOCAL_MACHINE, 
-        "Software\\Microsoft\\Windows\\CurrentVersion\\"
-            "Uninstall\\Doom II for Windows 95",
-        "UninstallString",
-    },
-
-    // Final Doom
-
-    {
-        HKEY_LOCAL_MACHINE, 
-        "Software\\Microsoft\\Windows\\CurrentVersion\\"
-            "Uninstall\\Final Doom for Windows 95",
-        "UninstallString",
-    },
-
-    // Shareware version
-
-    {
-        HKEY_LOCAL_MACHINE, 
-        "Software\\Microsoft\\Windows\\CurrentVersion\\"
-            "Uninstall\\Doom Shareware for Windows 95",
-        "UninstallString",
-    },
-};
-
-// Value installed by the Collector's Edition when it is installed
-
-static registry_value_t collectors_edition_value =
-{
-    HKEY_LOCAL_MACHINE,
-    "Software\\Activision\\DOOM Collector's Edition\\v1.0",
-    "INSTALLPATH",
-};
-
-// Subdirectories of the above install path, where IWADs are installed.
-
-static char *collectors_edition_subdirs[] = 
-{
-    "Doom2",
-    "Final Doom",
-    "Ultimate Doom",
-};
-
-// Location where Steam is installed
-
-static registry_value_t steam_install_location =
-{
-    HKEY_LOCAL_MACHINE,
-    "Software\\Valve\\Steam",
-    "InstallPath",
-};
-
-// Subdirs of the steam install directory where IWADs are found
-
-static char *steam_install_subdirs[] =
-{
-    "steamapps\\common\\doom 2\\base",
-    "steamapps\\common\\final doom\\base",
-    "steamapps\\common\\ultimate doom\\base",
-};
-
-static char *GetRegistryString(registry_value_t *reg_val)
-{
-    HKEY key;
-    DWORD len;
-    DWORD valtype;
-    char *result;
-
-    // Open the key (directory where the value is stored)
-
-    if (RegOpenKeyEx(reg_val->root, reg_val->path, 0, KEY_READ, &key) 
-          != ERROR_SUCCESS)
-    {
-        return NULL;
-    }
-
-    // Find the type and length of the string
-
-    if (RegQueryValueEx(key, reg_val->value, NULL, &valtype, NULL, &len) 
-          != ERROR_SUCCESS)
-    {
-        return NULL;
-    }
-
-    // Only accept strings
-
-    if (valtype != REG_SZ)
-    {
-        return NULL;
-    }
-
-    // Allocate a buffer for the value and read the value
-
-    result = malloc(len);
-
-    if (RegQueryValueEx(key, reg_val->value, NULL, &valtype, (unsigned char *) result, &len) 
-          != ERROR_SUCCESS)
-    {
-        free(result);
-        return NULL;
-    }
-
-    // Close the key
-        
-    RegCloseKey(key);
-
-    return result;
-}
-
-// Check for the uninstall strings from the CD versions
-
-static void CheckUninstallStrings(void)
-{
-    unsigned int i;
-
-    for (i=0; i<arrlen(uninstall_values); ++i)
-    {
-        char *val;
-        char *path;
-        char *unstr;
-
-        val = GetRegistryString(&uninstall_values[i]);
-
-        if (val == NULL)
-        {
-            continue;
-        }
-
-        unstr = strstr(val, UNINSTALLER_STRING);
-
-        if (unstr == NULL)
-        {
-            free(val);
-        }
-        else
-        {
-            path = unstr + strlen(UNINSTALLER_STRING);
-
-            AddIWADDir(path);
-        }
-    }
-}
-
-// Check for Doom: Collector's Edition
-
-static void CheckCollectorsEdition(void)
-{
-    char *install_path;
-    char *subpath;
-    unsigned int i;
-
-    install_path = GetRegistryString(&collectors_edition_value);
-
-    if (install_path == NULL)
-    {
-        return;
-    }
-
-    for (i=0; i<arrlen(collectors_edition_subdirs); ++i)
-    {
-        subpath = malloc(strlen(install_path)
-                         + strlen(collectors_edition_subdirs[i])
-                         + 5);
-
-        sprintf(subpath, "%s\\%s", install_path, collectors_edition_subdirs[i]);
-
-        AddIWADDir(subpath);
-    }
-
-    free(install_path);
-}
-
-
-// Check for Doom downloaded via Steam
-
-static void CheckSteamEdition(void)
-{
-    char *install_path;
-    char *subpath;
-    size_t i;
-
-    install_path = GetRegistryString(&steam_install_location);
-
-    if (install_path == NULL)
-    {
-        return;
-    }
-
-    for (i=0; i<arrlen(steam_install_subdirs); ++i)
-    {
-        subpath = malloc(strlen(install_path) 
-                         + strlen(steam_install_subdirs[i]) + 5);
-
-        sprintf(subpath, "%s\\%s", install_path, steam_install_subdirs[i]);
-
-        AddIWADDir(subpath);
-    }
-}
-
-// Default install directories for DOS Doom
-
-static void CheckDOSDefaults(void)
-{
-    // These are the default install directories used by the deice
-    // installer program:
-
-    AddIWADDir("\\doom2");              // Doom II
-    AddIWADDir("\\plutonia");           // Final Doom
-    AddIWADDir("\\tnt");
-    AddIWADDir("\\doom_se");            // Ultimate Doom
-    AddIWADDir("\\doom");               // Shareware / Registered Doom
-    AddIWADDir("\\dooms");              // Shareware versions
-    AddIWADDir("\\doomsw");
-}
-
-#endif
-
-static struct 
-{
-    char *name;
-    GameMission_t mission;
-} iwads[] = {
-    {"doom2.wad",    doom2},
-    {"plutonia.wad", pack_plut},
-    {"tnt.wad",      pack_tnt},
-    {"doom.wad",     doom},
-    {"doom1.wad",    doom},
-    {"chex.wad",     doom},
-};
-            
-// Hack for chex quest mode
-
-static void CheckChex(char *iwad_name)
-{
-    if (!strcmp(iwad_name, "chex.wad")) 
-    {
-        gameversion = exe_chex;
-    }
-}
-
-// Search a directory to try to find an IWAD
-// Returns the location of the IWAD if found, otherwise NULL.
-
-static char *SearchDirectoryForIWAD(char *dir)
-{
-    size_t i;
-
-    for (i=0; i<arrlen(iwads); ++i) 
-    {
-        char *filename; 
-        char *iwadname;
-
-        iwadname = DEH_String(iwads[i].name);
-        
-        filename = malloc(strlen(dir) + strlen(iwadname) + 3);
-
-        if (!strcmp(dir, "."))
-        {
-            strcpy(filename, iwadname);
-        }
-        else
-        {
-            sprintf(filename, "%s%c%s", dir, DIR_SEPARATOR, iwadname);
-        }
-
-        if (M_FileExists(filename))
-        {
-            CheckChex(iwads[i].name);
-            gamemission = iwads[i].mission;
-
-            return filename;
-        }
-
-        free(filename);
-    }
-
-    return NULL;
-}
-
-// When given an IWAD with the '-iwad' parameter,
-// attempt to identify it by its name.
-
-static void IdentifyIWADByName(char *name)
-{
-    size_t i;
-
-    gamemission = none;
-    
-    for (i=0; i<arrlen(iwads); ++i)
-    {
-        char *iwadname;
-
-        iwadname = DEH_String(iwads[i].name);
-
-        if (strlen(name) < strlen(iwadname))
-            continue;
-
-        // Check if it ends in this IWAD name.
-
-        if (!strcasecmp(name + strlen(name) - strlen(iwadname), 
-                        iwadname))
-        {
-            CheckChex(iwads[i].name);
-            gamemission = iwads[i].mission;
-            break;
-        }
-    }
-}
-
-//
-// Add directories from the list in the DOOMWADPATH environment variable.
-// 
-
-static void AddDoomWadPath(void)
-{
-    char *doomwadpath;
-    char *p;
-
-    // Check the DOOMWADPATH environment variable.
-
-    doomwadpath = getenv("DOOMWADPATH");
-
-    if (doomwadpath == NULL)
-    {
-        return;
-    }
-
-    doomwadpath = strdup(doomwadpath);
-
-    // Add the initial directory
-
-    AddIWADDir(doomwadpath);
-
-    // Split into individual dirs within the list.
-
-    p = doomwadpath;
-
-    for (;;)
-    {
-        p = strchr(p, PATH_SEPARATOR);
-
-        if (p != NULL)
-        {
-            // Break at the separator and store the right hand side
-            // as another iwad dir
-  
-            *p = '\0';
-            p += 1;
-
-            AddIWADDir(p);
-        }
-        else
-        {
-            break;
-        }
-    }
-}
-
-
-//
-// Build a list of IWAD files
-//
-
-static void BuildIWADDirList(void)
-{
-    char *doomwaddir;
-
-    if (iwad_dirs_built)
-    {
-        return;
-    }
-
-    // Look in the current directory.  Doom always does this.
-
-    AddIWADDir(".");
-
-    // Add DOOMWADDIR if it is in the environment
-
-    doomwaddir = getenv("DOOMWADDIR");
-
-    if (doomwaddir != NULL)
-    {
-        AddIWADDir(doomwaddir);
-    }        
-
-    // Add dirs from DOOMWADPATH
-
-    AddDoomWadPath();
-
-#ifdef _WIN32
-
-    // Search the registry and find where IWADs have been installed.
-
-    CheckUninstallStrings();
-    CheckCollectorsEdition();
-    CheckSteamEdition();
-    CheckDOSDefaults();
-
-#else
-
-    // Standard places where IWAD files are installed under Unix.
-
-    AddIWADDir("/usr/share/games/doom");
-    AddIWADDir("/usr/local/share/games/doom");
-
-#endif
-
-    // Don't run this function again.
-
-    iwad_dirs_built = true;
-}
-
-//
-// Searches WAD search paths for an WAD with a specific filename.
-// 
-
-char *D_FindWADByName(char *name)
-{
-    char *buf;
-    int i;
-    boolean exists;
-    
-    // Absolute path?
-
-    if (M_FileExists(name))
-    {
-        return name;
-    }
-
-    BuildIWADDirList();
-    
-    // Search through all IWAD paths for a file with the given name.
-
-    for (i=0; i<num_iwad_dirs; ++i)
-    {
-        // Construct a string for the full path
-
-        buf = malloc(strlen(iwad_dirs[i]) + strlen(name) + 5);
-        sprintf(buf, "%s%c%s", iwad_dirs[i], DIR_SEPARATOR, name);
-
-        exists = M_FileExists(buf);
-
-        if (exists)
-        {
-            return buf;
-        }
-
-        free(buf);
-    }
-
-    // File not found
-
-    return NULL;
-}
-
-//
-// D_TryWADByName
-//
-// Searches for a WAD by its filename, or passes through the filename
-// if not found.
-//
-
-char *D_TryFindWADByName(char *filename)
-{
-    char *result;
-
-    result = D_FindWADByName(filename);
-
-    if (result != NULL)
-    {
-        return result;
-    }
-    else
-    {
-        return filename;
-    }
-}
-
-//
-// FindIWAD
-// Checks availability of IWAD files by name,
-// to determine whether registered/commercial features
-// should be executed (notably loading PWADs).
-//
-
-char *D_FindIWAD(void)
-{
-    char *result;
-    char *iwadfile;
-    int iwadparm;
-    int i;
-
-    // Check for the -iwad parameter
-
-    //!
-    // Specify an IWAD file to use.
-    //
-    // @arg <file>
-    //
-
-    iwadparm = M_CheckParm("-iwad");
-
-    if (iwadparm)
-    {
-        // Search through IWAD dirs for an IWAD with the given name.
-
-        iwadfile = myargv[iwadparm + 1];
-
-        result = D_FindWADByName(iwadfile);
-
-        if (result == NULL)
-        {
-            I_Error("IWAD file '%s' not found!", iwadfile);
-        }
-        
-        IdentifyIWADByName(result);
-    }
-    else
-    {
-        // Search through the list and look for an IWAD
-
-        result = NULL;
-
-        BuildIWADDirList();
-    
-        for (i=0; result == NULL && i<num_iwad_dirs; ++i)
-        {
-            result = SearchDirectoryForIWAD(iwad_dirs[i]);
-        }
-    }
-
-    return result;
-}
-
-// 
-// Get the IWAD name used for savegames.
-//
-
-static char *SaveGameIWADName(void)
-{
-    size_t i;
-
-    // Chex quest hack
-
-    if (gameversion == exe_chex)
-    {
-        return "chex.wad";
-    }
-
-    // Find what subdirectory to use for savegames
-    //
-    // They should be stored in something like
-    //    ~/.chocolate-doom/savegames/doom.wad/
-    //
-    // The directory depends on the IWAD, so that savegames for
-    // different IWADs are kept separate.
-    //
-    // Note that we match on gamemission rather than on IWAD name.
-    // This ensures that doom1.wad and doom.wad saves are stored
-    // in the same place.
-
-    for (i=0; i<arrlen(iwads); ++i)
-    {
-        if (gamemission == iwads[i].mission)
-        {
-            return iwads[i].name;
-        }
-    }
-    
-    return NULL;
-}
-// 
-// SetSaveGameDir
-//
-// Chooses the directory used to store saved games.
-//
-
-void D_SetSaveGameDir(void)
-{
-    char *iwad_name;
-
-    if (!strcmp(configdir, ""))
-    {
-        // Use the current directory, just like configdir.
-
-        savegamedir = strdup("");
-    }
-    else
-    {
-        // Directory for savegames
-
-        iwad_name = SaveGameIWADName();
-
-        if (iwad_name == NULL) 
-        {
-            iwad_name = "unknown.wad";
-        }
-
-        savegamedir = Z_Malloc(strlen(configdir) + 30, PU_STATIC, 0);
-        sprintf(savegamedir, "%ssavegames%c%s%c", configdir,
-                             DIR_SEPARATOR, iwad_name, DIR_SEPARATOR);
-
-        M_MakeDirectory(savegamedir);
-    }
-}
-
-// Strings for dehacked replacements of the startup banner
-//
-// These are from the original source: some of them are perhaps
-// not used in any dehacked patches
-
-static char *banners[] = 
-{
-    // doom1.wad
-    "                            "
-    "DOOM Shareware Startup v%i.%i"
-    "                           ",
-    // doom.wad
-    "                            "
-    "DOOM Registered Startup v%i.%i"
-    "                           ",
-    // Registered DOOM uses this
-    "                          "
-    "DOOM System Startup v%i.%i"
-    "                          ",
-    // doom.wad (Ultimate DOOM)
-    "                         "
-    "The Ultimate DOOM Startup v%i.%i"
-    "                        ",
-    // doom2.wad
-    "                         "
-    "DOOM 2: Hell on Earth v%i.%i"
-    "                           ",
-    // tnt.wad
-    "                     "
-    "DOOM 2: TNT - Evilution v%i.%i"
-    "                           ",
-    // plutonia.wad
-    "                   "
-    "DOOM 2: Plutonia Experiment v%i.%i"
-    "                           ",
-};
-
-//
-// Get game name: if the startup banner has been replaced, use that.
-// Otherwise, use the name given
-// 
-
-static char *GetGameName(char *gamename)
-{
-    size_t i;
-    char *deh_sub;
-    
-    for (i=0; i<arrlen(banners); ++i)
-    {
-        // Has the banner been replaced?
-
-        deh_sub = DEH_String(banners[i]);
-        
-        if (deh_sub != banners[i])
-        {
-            // Has been replaced
-            // We need to expand via printf to include the Doom version 
-            // number
-            // We also need to cut off spaces to get the basic name
-
-            gamename = Z_Malloc(strlen(deh_sub) + 10, PU_STATIC, 0);
-            sprintf(gamename, deh_sub, DOOM_VERSION / 100, DOOM_VERSION % 100);
-
-            while (gamename[0] != '\0' && isspace(gamename[0]))
-                strcpy(gamename, gamename+1);
-
-            while (gamename[0] != '\0' && isspace(gamename[strlen(gamename)-1]))
-                gamename[strlen(gamename) - 1] = '\0';
-            
-            return gamename;
-        }
-    }
-
-    return gamename;
-}
-
-
-//
-// Find out what version of Doom is playing.
-//
-
-void D_IdentifyVersion(void)
-{
-    // gamemission is set up by the D_FindIWAD function.  But if 
-    // we specify '-iwad', we have to identify using 
-    // IdentifyIWADByName.  However, if the iwad does not match
-    // any known IWAD name, we may have a dilemma.  Try to 
-    // identify by its contents.
-
-    if (gamemission == none)
-    {
-        unsigned int i;
-
-        for (i=0; i<numlumps; ++i)
-        {
-            if (!strncasecmp(lumpinfo[i].name, "MAP01", 8))
-            {
-                gamemission = doom2;
-                break;
-            } 
-            else if (!strncasecmp(lumpinfo[i].name, "E1M1", 8))
-            {
-                gamemission = doom;
-                break;
-            }
-        }
-
-        if (gamemission == none)
-        {
-            // Still no idea.  I don't think this is going to work.
-
-            I_Error("Unknown or invalid IWAD file.");
-        }
-    }
-
-    // Make sure gamemode is set up correctly
-
-    if (gamemission == doom)
-    {
-        // Doom 1.  But which version?
-
-        if (W_CheckNumForName("E4M1") > 0)
-        {
-            // Ultimate Doom
-
-            gamemode = retail;
-        } 
-        else if (W_CheckNumForName("E3M1") > 0)
-        {
-            gamemode = registered;
-        }
-        else
-        {
-            gamemode = shareware;
-        }
-    }
-    else
-    {
-        // Doom 2 of some kind.
-
-        gamemode = commercial;
-    }
-}
-
-// Set the gamedescription string
-
-void D_SetGameDescription(void)
-{
-    gamedescription = "Unknown";
-
-    if (gamemission == doom)
-    {
-        // Doom 1.  But which version?
-
-        if (gamemode == retail)
-        {
-            // Ultimate Doom
-
-            gamedescription = GetGameName("The Ultimate DOOM");
-        } 
-        else if (gamemode == registered)
-        {
-            gamedescription = GetGameName("DOOM Registered");
-        }
-        else if (gamemode == shareware)
-        {
-            gamedescription = GetGameName("DOOM Shareware");
-        }
-    }
-    else
-    {
-        // Doom 2 of some kind.  But which mission?
-
-        if (gamemission == doom2)
-            gamedescription = GetGameName("DOOM 2: Hell on Earth");
-        else if (gamemission == pack_plut)
-            gamedescription = GetGameName("DOOM 2: Plutonia Experiment"); 
-        else if (gamemission == pack_tnt)
-            gamedescription = GetGameName("DOOM 2: TNT - Evilution");
-    }
-}
-
-// Clever hack: Setup can invoke Doom to determine which IWADs are installed.
-// Doom searches install paths and exits with the return code being a 
-// bitmask of the installed IWAD files.
-
-void D_FindInstalledIWADs(void)
-{
-    unsigned int i;
-    int result;
-
-    BuildIWADDirList();
-
-    result = 0;
-
-    for (i=0; i<arrlen(iwads); ++i)
-    {
-        if (D_FindWADByName(iwads[i].name) != NULL)
-        {
-            result |= 1 << i;
-        }
-    }
-
-    exit(result);
-}
-
--- a/src/doom/d_iwad.h
+++ /dev/null
@@ -1,39 +1,0 @@
-// Emacs style mode select   -*- C++ -*- 
-//-----------------------------------------------------------------------------
-//
-// Copyright(C) 2006 Simon Howard
-//
-// This program is free software; you can redistribute it and/or
-// modify it under the terms of the GNU General Public License
-// as published by the Free Software Foundation; either version 2
-// of the License, or (at your option) any later version.
-//
-// This program is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-// GNU General Public License for more details.
-//
-// You should have received a copy of the GNU General Public License
-// along with this program; if not, write to the Free Software
-// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
-// 02111-1307, USA.
-//
-// DESCRIPTION:
-//     Find IWAD and initialise according to IWAD type.
-//
-//-----------------------------------------------------------------------------
-
-
-#ifndef __D_IWAD__
-#define __D_IWAD__
-
-char *D_FindWADByName(char *filename);
-char *D_TryFindWADByName(char *filename);
-char *D_FindIWAD(void);
-void D_SetSaveGameDir(void);
-void D_IdentifyVersion(void);
-void D_SetGameDescription(void);
-void D_FindInstalledIWADs(void);
-
-#endif
-
--- a/src/doom/d_main.c
+++ b/src/doom/d_main.c
@@ -586,9 +586,235 @@
     D_AdvanceDemo ();
 }
 
+static iwad_t iwads[] =
+{
+    {"doom2.wad",    doom2},
+    {"plutonia.wad", pack_plut},
+    {"tnt.wad",      pack_tnt},
+    {"doom.wad",     doom},
+    {"doom1.wad",    doom},
+    {"chex.wad",     doom},
+    {NULL,           none},
+};
+        
+// Strings for dehacked replacements of the startup banner
+//
+// These are from the original source: some of them are perhaps
+// not used in any dehacked patches
 
+static char *banners[] = 
+{
+    // doom1.wad
+    "                            "
+    "DOOM Shareware Startup v%i.%i"
+    "                           ",
+    // doom.wad
+    "                            "
+    "DOOM Registered Startup v%i.%i"
+    "                           ",
+    // Registered DOOM uses this
+    "                          "
+    "DOOM System Startup v%i.%i"
+    "                          ",
+    // doom.wad (Ultimate DOOM)
+    "                         "
+    "The Ultimate DOOM Startup v%i.%i"
+    "                        ",
+    // doom2.wad
+    "                         "
+    "DOOM 2: Hell on Earth v%i.%i"
+    "                           ",
+    // tnt.wad
+    "                     "
+    "DOOM 2: TNT - Evilution v%i.%i"
+    "                           ",
+    // plutonia.wad
+    "                   "
+    "DOOM 2: Plutonia Experiment v%i.%i"
+    "                           ",
+};
 
+//
+// Get game name: if the startup banner has been replaced, use that.
+// Otherwise, use the name given
+// 
 
+static char *GetGameName(char *gamename)
+{
+    size_t i;
+    char *deh_sub;
+    
+    for (i=0; i<arrlen(banners); ++i)
+    {
+        // Has the banner been replaced?
+
+        deh_sub = DEH_String(banners[i]);
+        
+        if (deh_sub != banners[i])
+        {
+            // Has been replaced
+            // We need to expand via printf to include the Doom version 
+            // number
+            // We also need to cut off spaces to get the basic name
+
+            gamename = Z_Malloc(strlen(deh_sub) + 10, PU_STATIC, 0);
+            sprintf(gamename, deh_sub, DOOM_VERSION / 100, DOOM_VERSION % 100);
+
+            while (gamename[0] != '\0' && isspace(gamename[0]))
+                strcpy(gamename, gamename+1);
+
+            while (gamename[0] != '\0' && isspace(gamename[strlen(gamename)-1]))
+                gamename[strlen(gamename) - 1] = '\0';
+            
+            return gamename;
+        }
+    }
+
+    return gamename;
+}
+
+//
+// Find out what version of Doom is playing.
+//
+
+void D_IdentifyVersion(void)
+{
+    // gamemission is set up by the D_FindIWAD function.  But if 
+    // we specify '-iwad', we have to identify using 
+    // IdentifyIWADByName.  However, if the iwad does not match
+    // any known IWAD name, we may have a dilemma.  Try to 
+    // identify by its contents.
+
+    if (gamemission == none)
+    {
+        unsigned int i;
+
+        for (i=0; i<numlumps; ++i)
+        {
+            if (!strncasecmp(lumpinfo[i].name, "MAP01", 8))
+            {
+                gamemission = doom2;
+                break;
+            } 
+            else if (!strncasecmp(lumpinfo[i].name, "E1M1", 8))
+            {
+                gamemission = doom;
+                break;
+            }
+        }
+
+        if (gamemission == none)
+        {
+            // Still no idea.  I don't think this is going to work.
+
+            I_Error("Unknown or invalid IWAD file.");
+        }
+    }
+
+    // Make sure gamemode is set up correctly
+
+    if (gamemission == doom)
+    {
+        // Doom 1.  But which version?
+
+        if (W_CheckNumForName("E4M1") > 0)
+        {
+            // Ultimate Doom
+
+            gamemode = retail;
+        } 
+        else if (W_CheckNumForName("E3M1") > 0)
+        {
+            gamemode = registered;
+        }
+        else
+        {
+            gamemode = shareware;
+        }
+    }
+    else
+    {
+        // Doom 2 of some kind.
+
+        gamemode = commercial;
+    }
+}
+
+// Set the gamedescription string
+
+void D_SetGameDescription(void)
+{
+    gamedescription = "Unknown";
+
+    if (gamemission == doom)
+    {
+        // Doom 1.  But which version?
+
+        if (gamemode == retail)
+        {
+            // Ultimate Doom
+
+            gamedescription = GetGameName("The Ultimate DOOM");
+        } 
+        else if (gamemode == registered)
+        {
+            gamedescription = GetGameName("DOOM Registered");
+        }
+        else if (gamemode == shareware)
+        {
+            gamedescription = GetGameName("DOOM Shareware");
+        }
+    }
+    else
+    {
+        // Doom 2 of some kind.  But which mission?
+
+        if (gamemission == doom2)
+            gamedescription = GetGameName("DOOM 2: Hell on Earth");
+        else if (gamemission == pack_plut)
+            gamedescription = GetGameName("DOOM 2: Plutonia Experiment"); 
+        else if (gamemission == pack_tnt)
+            gamedescription = GetGameName("DOOM 2: TNT - Evilution");
+    }
+}
+
+static void SetSaveGameDir(char *iwad_filename)
+{
+    char *sep;
+    char *basefile;
+
+    // Extract the base filename
+ 
+    sep = strrchr(iwad_filename, DIR_SEPARATOR);
+
+    if (sep == NULL)
+    {
+        basefile = iwad_filename;
+    }
+    else
+    {
+        basefile = sep + 1;
+    }
+
+    // eg. ~/.chocolate-doom/savegames/doom2.wad/
+
+    savegamedir = malloc(strlen(configdir) + strlen(basefile) + 10);
+    sprintf(savegamedir, "%ssavegames%c%s%c",
+            configdir, DIR_SEPARATOR, basefile, DIR_SEPARATOR);
+}
+
+// Check if the IWAD file is the Chex Quest IWAD.  
+// Returns true if this is chex.wad.
+
+static boolean CheckChex(char *iwadname)
+{
+    char *chex_iwadname = "chex.wad";
+
+    return (strlen(iwadname) > strlen(chex_iwadname)
+     && !strcasecmp(iwadname + strlen(iwadname) - strlen(chex_iwadname),
+                    chex_iwadname));
+}
+
 //      print title for every printed line
 char            title[128];
 
@@ -711,9 +937,11 @@
     {
         // Determine automatically
 
-        if (gameversion == exe_chex) 
+        if (CheckChex(iwadfile))
         {
-            // Already determined
+            // chex.exe - identified by iwad filename
+
+            gameversion = exe_chex;
         }
         else if (gamemode == shareware || gamemode == registered)
         {
@@ -833,7 +1061,7 @@
 
     if (M_CheckParm("-findiwads") > 0)
     {
-        D_FindInstalledIWADs();
+        D_FindInstalledIWADs(iwads);
     }
 
     // print banner
@@ -890,7 +1118,7 @@
     DEH_Init();
 #endif
 
-    iwadfile = D_FindIWAD();
+    iwadfile = D_FindIWAD(iwads, &gamemission);
 
     // None found?
 
@@ -1259,7 +1487,7 @@
     InitGameVersion();
     LoadChexDeh();
     D_SetGameDescription();
-    D_SetSaveGameDir();
+    SetSaveGameDir(iwadfile);
 
     // Check for -file in shareware
     if (modifiedgame)
--- a/src/heretic/d_main.c
+++ b/src/heretic/d_main.c
@@ -29,6 +29,7 @@
 #include "config.h"
 #include "ct_chat.h"
 #include "doomdef.h"
+#include "d_iwad.h"
 #include "i_system.h"
 #include "i_video.h"
 #include "m_argv.h"
@@ -434,8 +435,6 @@
 ===============
 */
 
-#define MAXWADFILES 20
-
 // MAPDIR should be defined as the directory that holds development maps
 // for the -wart # # command
 
@@ -443,15 +442,16 @@
 
 #define SHAREWAREWADNAME "heretic1.wad"
 
-char *wadfiles[MAXWADFILES] = {
-    "heretic.wad",
+static iwad_t iwads[] = {
+    { "heretic.wad",        heretic },
+    { "heretic1.wad",       heretic },
+    { NULL,                 none },
 };
 
+char *iwadfile;
+
 char *basedefault = "heretic.cfg";
 
-char exrnwads[80];
-char exrnwads2[80];
-
 void wadprintf(void)
 {
     if (debugmode)
@@ -468,41 +468,15 @@
 #endif
 }
 
-void D_AddFile(char *file)
+boolean D_AddFile(char *file)
 {
-    int numwadfiles;
-    char *new;
-//      char text[256];
+    wad_file_t *handle;
 
-    for (numwadfiles = 0; wadfiles[numwadfiles]; numwadfiles++);
-    new = malloc(strlen(file) + 1);
-    strcpy(new, file);
-    if (strlen(exrnwads) + strlen(file) < 78)
-    {
-        if (strlen(exrnwads))
-        {
-            strcat(exrnwads, ", ");
-        }
-        else
-        {
-            strcpy(exrnwads, "External Wadfiles: ");
-        }
-        strcat(exrnwads, file);
-    }
-    else if (strlen(exrnwads2) + strlen(file) < 79)
-    {
-        if (strlen(exrnwads2))
-        {
-            strcat(exrnwads2, ", ");
-        }
-        else
-        {
-            strcpy(exrnwads2, "     ");
-            strcat(exrnwads, ",");
-        }
-        strcat(exrnwads2, file);
-    }
-    wadfiles[numwadfiles] = new;
+    printf("  adding %s\n", file);
+
+    handle = W_AddFile(file);
+
+    return handle != NULL;
 }
 
 //==========================================================
@@ -789,13 +763,8 @@
 
 void D_DoomMain(void)
 {
-    int i;
     int p;
-    int e;
-    int m;
     char file[256];
-    FILE *fp;
-    boolean devMap;
 
     I_PrintBanner(PACKAGE_STRING);
 
@@ -813,17 +782,6 @@
     startmap = 1;
     autostart = false;
 
-    // wadfiles[0] is a char * to the main wad
-    fp = fopen(wadfiles[0], "rb");
-    if (fp)
-    {
-        fclose(fp);
-    }
-    else
-    {                           // Change to look for shareware wad
-        wadfiles[0] = SHAREWAREWADNAME;
-    }
-
     // Check for -CDROM
     cdrom = false;
 #ifdef __WATCOMC__
@@ -834,48 +792,6 @@
     }
 #endif
 
-    // -FILE [filename] [filename] ...
-    // Add files to the wad list.
-    p = M_CheckParm("-file");
-    if (p)
-    {                           // the parms after p are wadfile/lump names, until end of parms
-        // or another - preceded parm
-        while (++p != myargc && myargv[p][0] != '-')
-        {
-            D_AddFile(myargv[p]);
-        }
-    }
-
-    // -DEVMAP <episode> <map>
-    // Adds a map wad from the development directory to the wad list,
-    // and sets the start episode and the start map.
-    devMap = false;
-    p = M_CheckParm("-devmap");
-    if (p && p < myargc - 2)
-    {
-        e = myargv[p + 1][0];
-        m = myargv[p + 2][0];
-        sprintf(file, MAPDIR "E%cM%c.wad", e, m);
-        D_AddFile(file);
-        printf("DEVMAP: Episode %c, Map %c.\n", e, m);
-        startepisode = e - '0';
-        startmap = m - '0';
-        autostart = true;
-        devMap = true;
-    }
-
-    p = M_CheckParm("-playdemo");
-    if (!p)
-    {
-        p = M_CheckParm("-timedemo");
-    }
-    if (p && p < myargc - 1)
-    {
-        sprintf(file, "%s.lmp", myargv[p + 1]);
-        D_AddFile(file);
-        printf("Playing demo %s.lmp.\n", myargv[p + 1]);
-    }
-
 //
 // get skill / episode / map from parms
 //
@@ -928,11 +844,40 @@
 
     printf("W_Init: Init WADfiles.\n");
 
-    for (i=0; wadfiles[i] != NULL; ++i)
+    iwadfile = D_FindIWAD(iwads, &gamemission);
+
+    if (iwadfile == NULL)
     {
-        W_AddFile(wadfiles[i]);
+        I_Error("Game mode indeterminate. No IWAD was found. Try specifying\n"
+                "one with the '-iwad' command line parameter.");
     }
 
+    D_AddFile(iwadfile);
+
+    // -FILE [filename] [filename] ...
+    // Add files to the wad list.
+    p = M_CheckParm("-file");
+    if (p)
+    {                           // the parms after p are wadfile/lump names, until end of parms
+        // or another - preceded parm
+        while (++p != myargc && myargv[p][0] != '-')
+        {
+            D_AddFile(myargv[p]);
+        }
+    }
+
+    p = M_CheckParm("-playdemo");
+    if (!p)
+    {
+        p = M_CheckParm("-timedemo");
+    }
+    if (p && p < myargc - 1)
+    {
+        sprintf(file, "%s.lmp", myargv[p + 1]);
+        D_AddFile(file);
+        printf("Playing demo %s.lmp.\n", myargv[p + 1]);
+    }
+
     if (W_CheckNumForName("E2M1") == -1)
     {
         gamemode = shareware;
@@ -1064,7 +1009,7 @@
     }
 
     // Check valid episode and map
-    if ((autostart || netgame) && (devMap == false))
+    if (autostart || netgame)
     {
         if (M_ValidEpisodeMap(startepisode, startmap) == false)
         {