shithub: choc

Download patch

ref: 0b8bf3cfe37a3d6e8ad01c0f6726430f53c0ad7e
parent: 3cf74a97261b1a0aceb591b495b0857781918edd
parent: a9e2d244a5a37fed344405e40698de2a2969c12a
author: Simon Howard <[email protected]>
date: Wed Jan 27 14:50:30 EST 2010

Merge from trunk.

Subversion-branch: /branches/opl-branch
Subversion-revision: 1829

--- a/.gitignore
+++ b/.gitignore
@@ -10,9 +10,12 @@
 config.status
 config.h
 autom4te.cache
+rpm.spec
 stamp-h
 stamp-h.in
 stamp-h1
+tags
+TAGS
 
 # These are the default patterns globally ignored by Subversion:
 *.o
--- a/INSTALL
+++ b/INSTALL
@@ -23,7 +23,7 @@
 On a Unix system, follow the standard instructions for installing an 
 autotools-based package:
 
- 1. Run './configure' to initialise the package.
+ 1. Run './configure' to initialize the package.
  2. Run 'make' to compile the package.
  3. Run 'make install' to install the package.
 
--- a/Makefile.am
+++ b/Makefile.am
@@ -24,9 +24,12 @@
 	codeblocks/textscreen.cbp
 
 DATA_FILES=                   \
+        data/README           \
         data/doom.ico         \
+        data/doom8.ico        \
         data/doom.png         \
         data/setup.ico        \
+        data/setup8.ico       \
         data/setup.png        \
         data/convert-icon
 
@@ -35,12 +38,14 @@
         $(MSVC_FILES)                   \
         $(CODEBLOCKS_FILES)             \
         $(DATA_FILES)                   \
+        .lvimrc                         \
         config.h                        \
         CMDLINE                         \
         HACKING                         \
         README.OPL                      \
         TODO                            \
-        BUGS
+        BUGS                            \
+        rpm.spec
 
 MAINTAINERCLEANFILES =  $(AUX_DIST_GEN)
 
@@ -49,6 +54,8 @@
 DIST_SUBDIRS=pkg $(SUBDIRS)
 
 if HAVE_PYTHON
+
+noinst_DATA=CMDLINE
 
 CMDLINE : src/
 	./man/docgen -p man/CMDLINE.template src/ > $@
--- a/NEWS
+++ b/NEWS
@@ -1,35 +1,67 @@
 ...
 
      * Chocolate Doom now runs on Windows Mobile/Windows CE!
-     * It is possible to rebind most/all of the keys that control
-       the menu, shortcuts, automap and weapon switching.  The
-       main reason for this is to support the Windows CE port
-       and other platforms where a full keyboard may not be present.
-     * Memory-mapped WAD I/O is disabled by default, as it caused
-       various issues, including a slowdown/crash with Plutonia 2
-       MAP23.  It can be explicitly re-enabled using the '-mmap'
-       command line parameter.
+     * It is possible to rebind most/all of the keys that control the
+       menu, shortcuts, automap and weapon switching.  The main
+       reason for this is to support the Windows CE port and other
+       platforms where a full keyboard may not be present.
+     * Chocolate Doom now includes a proper Mac OS X package; it is
+       no longer necessary to compile binaries for this system by
+       hand.  The package includes a simple graphical launcher
+       program and can be installed simply by dragging the "Chocolate
+       Doom" icon to the Applications folder.
      * The video mode auto-adjust code will automatically choose
        windowed mode if no fullscreen video modes are available.
-     * The zone memory size is automatically reduced on systems
-       with a small amount of memory.
-     * There is now a second, small textscreen font, so that the
-       ENDOOM screen and setup tool can be used on low resolution
-       devices (eg. PDAs/embedded devices)
-     * The textscreen library now has a scrollable pane widget.
-     * Doxygen documentation was added for the textscreen library.
-     * The "join game" window in the setup tool now has an option
-       to automatically join a game on the local network.
+     * The zone memory size is automatically reduced on systems with
+       a small amount of memory.
+     * The "join game" window in the setup tool now has an option to
+       automatically join a game on the local network.
+     * Chocolate Doom includes some initial hacks for compiling under
+       SDL 1.3.
+     * Recent versions of SDL_mixer include rewritten MIDI code on Mac
+       OS X.  If you are using a version of SDL_mixer with the new
+       code, music will now be enabled by default.
+     * Windows Vista and Windows 7 no longer prompt for elevated
+       privileges when running the setup tool (thanks hobbs and
+       MikeRS).
+     * The Windows binaries now have better looking icons (thanks
+       MikeRS).
+     * Magic values specified using the -spechit command line
+       parameter can now be hexadecimal.
+     * DOOMWADDIR/DOOMWADPATH can now specify the complete path to
+       IWAD files, rather than the path to the directory that contains
+       them.
+     * When recording shorttics demos, errors caused by the reduced
+       turning resolution are carried forward, possibly making turning
+       smoother.
 
     Compatibility:
      * The A_BossDeath behavior in v1.9 emulation mode was fixed
        (thanks entryway)
+     * The "loading" disk icon is drawn more like how it is drawn in
+       Vanilla Doom, also fixing a bug with chook3.wad.
+     * Desync on 64-bit systems with ep1-0500.lmp has (at long last)
+       been fixed (thanks exp(x)).
+     * Donut overrun emulation code imported from Prboom+ (thanks
+       entryway).
+     * The correct level name should now be shown in the automap for
+       pl2.wad MAP33 (thanks Janizdreg).
+     * In Chex Quest, the green radiation suit colormap is now used
+       instead of the red colormaps normally used when taking damage
+       or using the berserk pack.  This matches Vanilla chex.exe
+       behavior (thanks Fuzztooth).
+     * Impassible glass now displays and works the same as in Vanilla,
+       fixing wads such as OTTAWAU.WAD (thanks Never_Again).
 
     Bugs fixed:
+     * Memory-mapped WAD I/O is disabled by default, as it caused
+       various issues, including a slowdown/crash with Plutonia 2
+       MAP23.  It can be explicitly re-enabled using the '-mmap'
+       command line parameter.
      * Crash when saving games due to the ~/.chocolate-doom/savegames
        directory not being created (thanks to everyone who reported
        this).
-     * Chocolate Doom will now under Win95/98, as the
+     * Chocolate Doom will now run under Win95/98, as the
        SetProcessAffinityMask function is looked up dynamically.
      * Compilation under Linux with older versions of libc will now
        work (the semantics for sched_setaffinity were different in
@@ -36,13 +68,26 @@
        older versions)
      * Sound clipping when using libsamplerate was improved (thanks
        David Flater)
-     * The audio buffer size is now calculated based on the sample rate,
-       so there is not a noticeable delay when using a lower sample
-       rate.
-     * The manpage documentation for the DOOMWADPATH variable was fixed
-       (thanks MikeRS).
-     * Compilation with FEATURE_MULTIPLAYER and FEATURE_SOUND disabled
-       was fixed.
+     * The audio buffer size is now calculated based on the sample
+       rate, so there is not a noticeable delay when using a lower
+       sample rate.
+     * The manpage documentation for the DOOMWADPATH variable was
+       fixed (thanks MikeRS).
+     * Compilation with FEATURE_MULTIPLAYER and FEATURE_SOUND
+       disabled was fixed.
+     * Fixed crash when using the donut special type and the joining
+       linedef is one sided (thanks Alexander Waldmann).
+     * Key settings in a configuration file that are out of range
+       do not cause a crash (thanks entryway).
+
+    libtextscreen:
+     * There is now a second, small textscreen font, so that the
+       ENDOOM screen and setup tool can be used on low resolution
+       devices (eg. PDAs/embedded devices)
+     * The textscreen library now has a scrollable pane widget. Thanks
+       to LionsPhil for contributing code to scroll up and down using
+       the keyboard.
+     * Doxygen documentation was added for the textscreen library.
 
 1.2.1 (2008-12-10):
 
--- a/TODO
+++ b/TODO
@@ -1,17 +1,22 @@
+Currently in progress:
+
+* OPL MIDI playback (see: opl-branch)
+* Heretic/Hexen support (see: raven-branch)
+* Strife support (see: strife-branch)
+
 To do:
 
-* Install packages:
-  - Debian/Ubuntu .deb packages, Fedora .rpm packages.
-  - Windows NSIS installer.
-  - MacOS X .dmg packages (should be universal binaries!)
+* Demo hashes for regression testing of this and other ports.
 * File selector for chocolate-setup, so that WADs can be selected from
   a browser, instead of simply typing the filenames.
 * Multiplayer:
   - Master server for locating servers automatically - makes setting up
     public servers easier.
+  - Use UPnP to automatically configure port forwarding for NATted
+    networks.
   - Incorporate local LAN search into setup interface.
   - Multiplayer options and configuration file (server name, etc)
-* Improve multiplayer startup: 
+* Improve multiplayer startup:
   - Select an IWAD automatically from the server's game type rather than
     all players having to specify -iwad.
   - Send list of WADs to load instead of all clients having to specify -file.
@@ -20,16 +25,14 @@
   - Test on and fix for architectures where ((-2) >> 1) != -1
   - Use size-specific types (eg. int32_t instead of int)
   - Don't make structure packing assumptions when loading levels.
-* Port to every OS and architecture under the sun
+  - Port to every OS and architecture under the sun
 
 Crazy pie in the sky ideas:
 
 * Automatic WAD installer - download and run TCs from a list automatically
   (automating the current "instructions on wiki" system).
-* Textscreen interface to the Compet-N database: menu driven system to 
+* Textscreen interface to the Compet-N database: menu driven system to
   automatically download and play speedruns.
 * DWANGO-like interface for finding players and setting up games.
-* Demo hashes for regression testing of this and other ports.
-* OPL emulation
 * Video capture mode?
 
--- a/autogen.sh
+++ b/autogen.sh
@@ -8,5 +8,5 @@
 autoconf
 automake
 
-./configure $@
+./configure "$@"
 
--- a/configure.in
+++ b/configure.in
@@ -1,5 +1,11 @@
 AC_INIT(Chocolate Doom, 1.2.1, [email protected], chocolate-doom)
 
+PACKAGE_SHORTDESC="Conservative Doom source port"
+PACKAGE_COPYRIGHT="Copyright (C) 1993-2010"
+PACKAGE_LICENSE="GNU General Public License, version 2"
+PACKAGE_MAINTAINER="Simon Howard"
+PACKAGE_URL="http://www.chocolate-doom.org/"
+
 AC_CONFIG_AUX_DIR(autotools)
 
 orig_CFLAGS="$CFLAGS"
@@ -80,6 +86,7 @@
 ])
 
 AC_CHECK_TOOL(WINDRES, windres, )
+AC_CHECK_TOOL(STRIP, strip, )
 
 # Windows CE build?
 
@@ -115,24 +122,34 @@
 
 AC_SUBST(ac_aux_dir)
 
+AC_SUBST(PACKAGE_SHORTDESC)
+AC_SUBST(PACKAGE_COPYRIGHT)
+AC_SUBST(PACKAGE_LICENSE)
+AC_SUBST(PACKAGE_MAINTAINER)
+AC_SUBST(PACKAGE_URL)
+AC_SUBST(PACKAGE_LONGDESC)
+
 dnl Shut up the datarootdir warnings.
 AC_DEFUN([AC_DATAROOTDIR_CHECKED])
 
 AC_OUTPUT([
 Makefile
-wince/Makefile
-textscreen/Makefile
-textscreen/examples/Makefile
-setup/Makefile
+rpm.spec
 man/Makefile
 opl/Makefile
 opl/examples/Makefile
-src/Makefile
 pcsound/Makefile
 pkg/Makefile
-pkg/wince/GNUmakefile
-src/resource.rc
-src/doom-screensaver.desktop
+pkg/config.make
+pkg/osx/Info.plist
+pkg/osx/Info-gnustep.plist
+setup/Makefile
 setup/setup-res.rc
+src/Makefile
+src/doom-screensaver.desktop
+src/resource.rc
+textscreen/Makefile
+textscreen/examples/Makefile
+wince/Makefile
 ])
 
--- a/data/README
+++ b/data/README
@@ -3,3 +3,10 @@
 
     http://www.flickr.com/photos/laffy4k/448920776/
 
+The "foo8.ico" files are 8-bit depth only, while the "foo.ico" files
+contain full 32-bit versions, scaled to different sizes and with proper
+alpha masks (as well as the 8-bit versions).  The 8-bit versions are
+used when setting the icon within SDL, as SDL under Windows displays
+full color icons in a very poor quality.  The full-color versions are
+used in the resource files.
+
binary files a/data/doom.ico b/data/doom.ico differ
binary files /dev/null b/data/doom8.ico differ
binary files a/data/setup.ico b/data/setup.ico differ
binary files /dev/null b/data/setup8.ico differ
--- a/man/Makefile.am
+++ b/man/Makefile.am
@@ -5,9 +5,9 @@
 
 man_MANS=chocolate-doom.6      \
          chocolate-server.6    \
-	 chocolate-setup.6     \
-	 default.cfg.5         \
-	 $(PACKAGE).cfg.5
+         chocolate-setup.6     \
+         default.cfg.5         \
+         $(PACKAGE).cfg.5
 
 chocolate-doom.6: ../src $(MANPAGE_GEN_FILES)
 	./docgen -m manpage.template ../src > $@
@@ -21,5 +21,6 @@
 endif
 
 EXTRA_DIST = $(man_MANS) $(MANPAGE_GEN_FILES)        \
-	     wikipages
+             wikipages                               \
+             CMDLINE.template
 
--- a/pcsound/.gitignore
+++ b/pcsound/.gitignore
@@ -3,4 +3,6 @@
 .deps
 libpcsound.a
 *.rc
+tags
+TAGS
 
--- /dev/null
+++ b/pkg/.gitignore
@@ -1,0 +1,3 @@
+Makefile
+Makefile.in
+config.make
--- a/pkg/Makefile.am
+++ b/pkg/Makefile.am
@@ -1,3 +1,32 @@
 
-DIST_SUBDIRS=wince
+OSX_FILES=                                                              \
+osx/Resources/128x128.png                                               \
+osx/Resources/app.icns                                                  \
+osx/Resources/app.png                                                   \
+osx/Resources/wadfile.icns                                              \
+osx/Resources/wadfile.png                                               \
+osx/Resources/launcher.nib/classes.nib                                  \
+osx/Resources/launcher.nib/info.nib                                     \
+osx/Resources/launcher.nib/keyedobjects.nib                             \
+osx/GNUmakefile                                                         \
+osx/Info.plist.in       osx/Info-gnustep.plist.in                       \
+osx/PkgInfo                                                             \
+osx/cp-with-libs                                                        \
+osx/main.m                                                              \
+osx/AppController.m     osx/AppController.h                             \
+osx/Execute.m           osx/Execute.h                                   \
+osx/IWADController.m    osx/IWADController.h                            \
+osx/IWADLocation.m      osx/IWADLocation.h                              \
+osx/LauncherManager.m   osx/LauncherManager.h
+
+WINCE_FILES=                                                            \
+wince/GNUmakefile                                                       \
+wince/wince-cab.cfg                                                     \
+wince/wince-cabgen
+
+WIN32_FILES=                                                            \
+win32/GNUmakefile                                                       \
+win32/README
+
+EXTRA_DIST=$(OSX_FILES) $(WINCE_FILES) $(WIN32_FILES)
 
--- /dev/null
+++ b/pkg/config.make.in
@@ -1,0 +1,28 @@
+# Shared file included by the makefiles used to build packages.
+# This contains various information needed by the makefiles,
+# and is autogenerated by configure to include various
+# necessary details.
+
+# Tools needed:
+
+CC = @CC@
+STRIP = @STRIP@
+
+# Package name and version number:
+
+PACKAGE = @PACKAGE@
+PACKAGE_NAME = @PACKAGE_NAME@
+PACKAGE_STRING = @PACKAGE_STRING@
+PACKAGE_TARNAME = @PACKAGE_TARNAME@
+PACKAGE_VERSION = @PACKAGE_VERSION@
+
+# Documentation files to distribute with packages.
+
+DOC_FILES = README       \
+            COPYING      \
+            ChangeLog    \
+            NEWS         \
+            BUGS         \
+            CMDLINE      \
+            TODO
+
--- /dev/null
+++ b/pkg/osx/.gitignore
@@ -1,0 +1,7 @@
+Info.plist
+Info-gnustep.plist
+launcher
+*.o
+*.d
+*.dmg
+staging
--- /dev/null
+++ b/pkg/osx/AppController.h
@@ -1,0 +1,53 @@
+/* ... */
+//-----------------------------------------------------------------------------
+//
+// Copyright(C) 2009 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.
+//
+//-----------------------------------------------------------------------------
+
+#ifndef LAUNCHER_APPCONTROLLER_H
+#define LAUNCHER_APPCONTROLLER_H
+
+#include <AppKit/AppKit.h>
+
+#include "LauncherManager.h"
+
+@interface AppController : NSObject
+{
+    LauncherManager *launcherManager;
+    BOOL filesAdded;
+}
+
++ (void)initialize;
+
+- (id)init;
+- (void)dealloc;
+
+- (void)awakeFromNib;
+
+- (void)applicationDidFinishLaunching:(NSNotification *)aNotif;
+- (BOOL)applicationShouldTerminate:(id)sender;
+- (void)applicationWillTerminate:(NSNotification *)aNotif;
+- (BOOL)application:(NSApplication *)application openFile:(NSString *)fileName;
+
+- (void)showPrefPanel:(id)sender;
+
+@end
+
+#endif
+
--- /dev/null
+++ b/pkg/osx/AppController.m
@@ -1,0 +1,124 @@
+/* ... */
+//-----------------------------------------------------------------------------
+//
+// Copyright(C) 2009 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.
+//
+//-----------------------------------------------------------------------------
+
+#include "AppController.h"
+
+#include "config.h"
+
+@implementation AppController
+
++ (void)initialize
+{
+    NSMutableDictionary *defaults = [NSMutableDictionary dictionary];
+
+    /*
+     * Register your app's defaults here by adding objects to the
+     * dictionary, eg
+     *
+     * [defaults setObject:anObject forKey:keyForThatObject];
+     *
+     */
+
+    [[NSUserDefaults standardUserDefaults] registerDefaults:defaults];
+    [[NSUserDefaults standardUserDefaults] synchronize];
+}
+
+- (id)init
+{
+    if ((self = [super init]))
+    {
+    }
+
+    self->filesAdded = NO;
+
+    return self;
+}
+
+- (void)dealloc
+{
+    [super dealloc];
+}
+
+- (void)awakeFromNib
+{
+    [[NSApp mainMenu] setTitle:@PACKAGE_NAME];
+}
+
+- (void)applicationDidFinishLaunching:(NSNotification *)aNotif
+{
+// Uncomment if your application is Renaissance-based
+//  [NSBundle loadGSMarkupNamed:@"Main" owner:self];
+}
+
+- (BOOL)applicationShouldTerminate:(id)sender
+{
+    return YES;
+}
+
+- (void)applicationWillTerminate:(NSNotification *)aNotif
+{
+}
+
+- (BOOL) application:(NSApplication *) application
+         openFile:(NSString *) fileName
+{
+    NSString *extension;
+
+    // If this is the first file added, clear out the existing
+    // command line.  This allows us to select multiple files
+    // in the finder and open them all together (for TCs, etc).
+
+    if (!self->filesAdded)
+    {
+        [self->launcherManager clearCommandLine];
+    }
+
+    // Add file with appropriate command line option based on extension:
+
+    extension = [fileName pathExtension];
+
+    if (![extension caseInsensitiveCompare: @"wad"])
+    {
+        [self->launcherManager addFileToCommandLine: fileName
+                               forArgument: @"-merge"];
+    }
+    else if (![extension caseInsensitiveCompare: @"deh"])
+    {
+        [self->launcherManager addFileToCommandLine: fileName
+                               forArgument: @"-deh"];
+    }
+    else
+    {
+        return NO;
+    }
+
+    self->filesAdded = YES;
+
+    return YES;
+}
+
+- (void)showPrefPanel:(id)sender
+{
+}
+
+@end
+
--- /dev/null
+++ b/pkg/osx/Execute.h
@@ -1,0 +1,31 @@
+/* ... */
+//-----------------------------------------------------------------------------
+//
+// Copyright(C) 2009 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.
+//
+//-----------------------------------------------------------------------------
+
+#ifndef LAUNCHER_EXECUTE_H
+#define LAUNCHER_EXECUTE_H
+
+void SetProgramLocation(const char *path);
+void ExecuteProgram(const char *executable, const char *iwad, const char *args);
+void OpenTerminalWindow(const char *doomwadpath);
+
+#endif /* #ifndef LAUNCHER_EXECUTE_H */
+
--- /dev/null
+++ b/pkg/osx/Execute.m
@@ -1,0 +1,197 @@
+/* ... */
+//-----------------------------------------------------------------------------
+//
+// Copyright(C) 2009 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.
+//
+//-----------------------------------------------------------------------------
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+
+#include <AppKit/AppKit.h>
+
+#include "config.h"
+
+#define RESPONSE_FILE "/tmp/launcher.rsp"
+#define TEMP_SCRIPT "/tmp/tempscript.sh"
+
+static char *executable_path;
+
+// Called on startup to save the location of the launcher program
+// (within a package, other executables should be in the same directory)
+
+void SetProgramLocation(const char *path)
+{
+    char *p;
+
+    executable_path = strdup(path);
+
+    p = strrchr(executable_path, '/');
+    *p = '\0';
+}
+
+// Write out the response file containing command line arguments.
+
+static void WriteResponseFile(const char *iwad, const char *args)
+{
+    FILE *fstream;
+
+    fstream = fopen(RESPONSE_FILE, "w");
+
+    if (iwad != NULL)
+    {
+        fprintf(fstream, "-iwad \"%s\"", iwad);
+    }
+
+    if (args != NULL)
+    {
+        fprintf(fstream, "%s", args);
+    }
+
+    fclose(fstream);
+}
+
+static void DoExec(const char *executable, const char *iwad, const char *args)
+{
+    char *argv[3];
+
+    argv[0] = malloc(strlen(executable_path) + strlen(executable) + 3);
+    sprintf(argv[0], "%s/%s", executable_path, executable);
+
+    if (iwad != NULL || args != NULL)
+    {
+        WriteResponseFile(iwad, args);
+
+        argv[1] = "@" RESPONSE_FILE;
+        argv[2] = NULL;
+    }
+    else
+    {
+        argv[1] = NULL;
+    }
+
+    execv(argv[0], argv);
+    exit(-1);
+}
+
+// Execute the specified executable contained in the same directory
+// as the launcher, with the specified arguments.
+
+void ExecuteProgram(const char *executable, const char *iwad, const char *args)
+{
+    pid_t childpid;
+
+    childpid = fork();
+
+    if (childpid == 0)
+    {
+        signal(SIGCHLD, SIG_DFL);
+
+        DoExec(executable, iwad, args);
+    }
+    else
+    {
+        signal(SIGCHLD, SIG_IGN);
+    }
+}
+
+// Write a sequence of commands that will display the specified message
+// via shell commands.
+
+static void WriteMessage(FILE *script, char *msg)
+{
+    char *p;
+
+    fprintf(script, "echo \"");
+
+    for (p=msg; *p != '\0'; ++p)
+    {
+        // Start new line?
+
+        if (*p == '\n')
+        {
+            fprintf(script, "\"\necho \"");
+            continue;
+        }
+
+        // Escaped character?
+
+        if (*p == '\\' || *p == '\"')
+        {
+            fprintf(script, "\\");
+        }
+
+        fprintf(script, "%c", *p);
+    }
+
+    fprintf(script, "\"\n");
+}
+
+// Open a terminal window with the PATH set appropriately, and DOOMWADPATH
+// set to the specified value.
+
+void OpenTerminalWindow(const char *doomwadpath)
+{
+    FILE *stream;
+
+    // Generate a shell script that sets the PATH to include the location
+    // where the Doom binaries are, and DOOMWADPATH to include the
+    // IWAD files that have been configured in the launcher interface.
+    // The script then deletes itself and starts a shell.
+
+    stream = fopen(TEMP_SCRIPT, "w");
+
+    fprintf(stream, "#!/bin/sh\n");
+    //fprintf(stream, "set -x\n");
+    fprintf(stream, "PATH=\"%s:$PATH\"\n", executable_path);
+    fprintf(stream, "DOOMWADPATH=\"%s\"\n", doomwadpath);
+    fprintf(stream, "export DOOMWADPATH\n");
+    fprintf(stream, "rm -f \"%s\"\n", TEMP_SCRIPT);
+
+    // Display a useful message:
+
+    fprintf(stream, "clear\n");
+    WriteMessage(stream,
+        "\n"
+        "This command line has the PATH variable configured so that you may\n"
+        "launch the game with whatever parameters you desire.\n"
+        "\n"
+        "For example:\n"
+        "\n"
+        "   " PACKAGE_TARNAME " -iwad doom2.wad -file sid.wad -warp 1\n"
+        "\n"
+        "Type 'exit' to exit.\n");
+
+    fprintf(stream, "exec $SHELL\n");
+    fprintf(stream, "\n");
+
+    fclose(stream);
+
+    chmod(TEMP_SCRIPT, 0755);
+
+    // Tell the terminal to open a window to run the script.
+
+    [[NSWorkspace sharedWorkspace] openFile: @TEMP_SCRIPT
+                                   withApplication: @"Terminal"];
+}
+
--- /dev/null
+++ b/pkg/osx/GNUmakefile
@@ -1,0 +1,101 @@
+
+# Makefile for building the OS X launcher program and DMG package.
+# It is also possible to build and run the launcher under Unix
+# systems using GNUstep, although this is only here for development
+# and debugging purposes.
+
+include ../config.make
+
+STAGING_DIR=staging
+DMG=$(PACKAGE_TARNAME)-$(PACKAGE_VERSION).dmg
+
+TOPLEVEL=../..
+TOPLEVEL_DOCS=$(patsubst %,../../%,$(DOC_FILES))
+
+ifndef GNUSTEP_MAKEFILES
+
+# DMG file containing package:
+
+$(DMG) : $(STAGING_DIR)
+	rm -f $@
+	hdiutil create -volname "$(PACKAGE_STRING)" -srcdir $(STAGING_DIR) $@
+
+endif
+
+# Staging dir build for package:
+
+APP_DIR=$(STAGING_DIR)/$(PACKAGE_NAME).app
+
+# OS X and GNUstep apps have a slightly different internal structure:
+# OS X apps have their files within a containing "Contents" directory
+# that does not exist in GNUstep apps.  Similarly, the binaries are
+# installed at the top level, rather than in a "MacOS" directory.
+# Finally, we must install a different Info.plist file.
+
+ifdef GNUSTEP_MAKEFILES
+APP_TOP_DIR=$(APP_DIR)
+APP_BIN_DIR=$(APP_DIR)
+SRC_INFO_PLIST=Info-gnustep.plist
+else
+APP_TOP_DIR=$(APP_DIR)/Contents
+APP_BIN_DIR=$(APP_DIR)/Contents/MacOS
+SRC_INFO_PLIST=Info.plist
+endif
+
+$(STAGING_DIR): launcher $(TOPLEVEL_DOCS)
+	rm -rf $(STAGING_DIR)
+	mkdir $(STAGING_DIR)
+
+	cp $(TOPLEVEL_DOCS) "$(STAGING_DIR)"
+
+	mkdir -p "$(APP_TOP_DIR)"
+	cp -R Resources "$(APP_TOP_DIR)"
+	cp PkgInfo "$(APP_TOP_DIR)"
+	cp $(SRC_INFO_PLIST) "$(APP_TOP_DIR)"
+
+	mkdir -p "$(APP_BIN_DIR)"
+
+	cp launcher "$(APP_BIN_DIR)"
+	$(STRIP) "$(APP_BIN_DIR)/launcher"
+
+	./cp-with-libs $(TOPLEVEL)/src/$(PACKAGE_TARNAME) "$(APP_BIN_DIR)"
+	$(STRIP) "$(APP_BIN_DIR)/$(PACKAGE_TARNAME)"
+	./cp-with-libs $(TOPLEVEL)/setup/chocolate-setup "$(APP_BIN_DIR)"
+	$(STRIP) "$(APP_BIN_DIR)/chocolate-setup"
+
+	find $(STAGING_DIR) -name .svn -delete -exec rm -rf {} \; || true
+
+clean : launcher_clean
+	rm -f $(DMG)
+	rm -rf $(STAGING_DIR)
+
+# Launcher build:
+
+CFLAGS = -Wall -I$(TOPLEVEL)
+
+# Are we building using gs_make?
+
+ifdef GNUSTEP_MAKEFILES
+CFLAGS += $(shell gnustep-config --objc-flags)
+LDFLAGS = $(shell gnustep-config --gui-libs)
+else
+LDFLAGS = -framework Cocoa
+endif
+
+LAUNCHER_OBJS= \
+        AppController.o \
+        Execute.o \
+        IWADController.o \
+        IWADLocation.o \
+        LauncherManager.o \
+        main.o
+
+launcher : $(LAUNCHER_OBJS)
+	$(CC) $(LDFLAGS) $(LAUNCHER_OBJS) -o $@
+
+%.o : %.m
+	$(CC) -c $(CFLAGS) $^ -o $@
+
+launcher_clean :
+	rm -f $(LAUNCHER_OBJS) launcher
+
--- /dev/null
+++ b/pkg/osx/IWADController.h
@@ -1,0 +1,54 @@
+/* ... */
+//-----------------------------------------------------------------------------
+//
+// Copyright(C) 2009 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.
+//
+//-----------------------------------------------------------------------------
+
+#ifndef LAUNCHER_IWADCONTROLLER_H
+#define LAUNCHER_IWADCONTROLLER_H
+
+#include <AppKit/AppKit.h>
+#include <AppKit/NSNibLoading.h>
+
+@interface IWADController : NSObject
+{
+    id iwadSelector;
+    id configWindow;
+
+    id chex;
+    id doom1;
+    id doom2;
+    id plutonia;
+    id tnt;
+}
+
+- (void) closeConfigWindow: (id)sender;
+- (void) openConfigWindow: (id)sender;
+- (NSString *) getIWADLocation;
+- (void) awakeFromNib;
+- (BOOL) setDropdownList;
+- (void) setDropdownSelection;
+- (void) saveConfig;
+- (char *) doomWadPath;
+- (void) setEnvironment;
+
+@end
+
+#endif /* #ifndef LAUNCHER_IWADCONTROLLER_H */
+
--- /dev/null
+++ b/pkg/osx/IWADController.m
@@ -1,0 +1,347 @@
+/* ... */
+//-----------------------------------------------------------------------------
+//
+// Copyright(C) 2009 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.
+//
+//-----------------------------------------------------------------------------
+
+#include <stdlib.h>
+#include <string.h>
+#include <AppKit/AppKit.h>
+#include "IWADController.h"
+#include "IWADLocation.h"
+
+typedef enum
+{
+    IWAD_DOOM1,
+    IWAD_DOOM2,
+    IWAD_TNT,
+    IWAD_PLUTONIA,
+    IWAD_CHEX,
+    NUM_IWAD_TYPES
+} IWAD;
+
+static NSString *IWADLabels[NUM_IWAD_TYPES] =
+{
+    @"Doom",
+    @"Doom II: Hell on Earth",
+    @"Final Doom: TNT: Evilution",
+    @"Final Doom: Plutonia Experiment",
+    @"Chex Quest"
+};
+
+static NSString *IWADFilenames[NUM_IWAD_TYPES + 1] =
+{
+    @"doom.wad",
+    @"doom2.wad",
+    @"tnt.wad",
+    @"plutonia.wad",
+    @"chex.wad",
+    @"undefined"
+};
+
+@implementation IWADController
+
+- (void) getIWADList: (IWADLocation **) iwadList
+{
+    iwadList[IWAD_DOOM1] = self->doom1;
+    iwadList[IWAD_DOOM2] = self->doom2;
+    iwadList[IWAD_TNT] = self->tnt;
+    iwadList[IWAD_PLUTONIA] = self->plutonia;
+    iwadList[IWAD_CHEX] = self->chex;
+}
+
+- (IWAD) getSelectedIWAD
+{
+    unsigned int i;
+
+    for (i=0; i<NUM_IWAD_TYPES; ++i)
+    {
+        if ([self->iwadSelector titleOfSelectedItem] == IWADLabels[i])
+        {
+            return i;
+        }
+    }
+
+    return NUM_IWAD_TYPES;
+}
+
+// Get the location of the selected IWAD.
+
+- (NSString *) getIWADLocation
+{
+    IWAD selectedIWAD;
+    IWADLocation *iwadList[NUM_IWAD_TYPES];
+
+    selectedIWAD = [self getSelectedIWAD];
+
+    if (selectedIWAD == NUM_IWAD_TYPES)
+    {
+        return nil;
+    }
+    else
+    {
+        [self getIWADList: iwadList];
+
+	return [iwadList[selectedIWAD] getLocation];
+    }
+}
+
+- (void) setIWADConfig
+{
+    IWADLocation *iwadList[NUM_IWAD_TYPES];
+    NSUserDefaults *defaults;
+    NSString *key;
+    NSString *value;
+    unsigned int i;
+
+    [self getIWADList: iwadList];
+
+    // Load IWAD filename paths
+
+    defaults = [NSUserDefaults standardUserDefaults];
+
+    for (i=0; i<NUM_IWAD_TYPES; ++i)
+    {
+        key = IWADFilenames[i];
+        value = [defaults stringForKey:key];
+
+        if (value != nil)
+        {
+            [iwadList[i] setLocation:value];
+        }
+    }
+}
+
+// On startup, set the selected item in the IWAD dropdown
+
+- (void) setDropdownSelection
+{
+    NSUserDefaults *defaults;
+    NSString *selected;
+    unsigned int i;
+
+    defaults = [NSUserDefaults standardUserDefaults];
+    selected = [defaults stringForKey: @"selected_iwad"];
+
+    if (selected == nil)
+    {
+        return;
+    }
+
+    // Find this IWAD in the filenames list, and select it.
+
+    for (i=0; i<NUM_IWAD_TYPES; ++i)
+    {
+        if ([selected isEqualToString:IWADFilenames[i]])
+        {
+            [self->iwadSelector selectItemWithTitle:IWADLabels[i]];
+            break;
+        }
+    }
+}
+
+// Set the dropdown list to include an entry for each IWAD that has
+// been configured.  Returns true if at least one IWAD is configured.
+
+- (BOOL) setDropdownList
+{
+    IWADLocation *iwadList[NUM_IWAD_TYPES];
+    BOOL have_wads;
+    id location;
+    unsigned int i;
+    unsigned int enabled_wads;
+
+    // Build the new list.
+
+    [self getIWADList: iwadList];
+    [self->iwadSelector removeAllItems];
+
+    enabled_wads = 0;
+
+    for (i=0; i<NUM_IWAD_TYPES; ++i)
+    {
+        location = [iwadList[i] getLocation];
+
+        if (location != nil && [location length] > 0)
+        {
+            [self->iwadSelector addItemWithTitle: IWADLabels[i]];
+            ++enabled_wads;
+        }
+    }
+
+    // Enable/disable the dropdown depending on whether there
+    // were any configured IWADs.
+
+    have_wads = enabled_wads > 0;
+    [self->iwadSelector setEnabled: have_wads];
+
+    // Restore the old selection.
+
+    [self setDropdownSelection];
+
+    return have_wads;
+}
+
+- (void) saveConfig
+{
+    IWADLocation *iwadList[NUM_IWAD_TYPES];
+    IWAD selectedIWAD;
+    NSUserDefaults *defaults;
+    NSString *key;
+    NSString *value;
+    unsigned int i;
+
+    [self getIWADList: iwadList];
+
+    // Store all IWAD locations to user defaults.
+
+    defaults = [NSUserDefaults standardUserDefaults];
+
+    for (i=0; i<NUM_IWAD_TYPES; ++i)
+    {
+        key = IWADFilenames[i];
+        value = [iwadList[i] getLocation];
+
+        [defaults setObject:value forKey:key];
+    }
+
+    // Save currently selected IWAD.
+
+    selectedIWAD = [self getSelectedIWAD];
+    [defaults setObject:IWADFilenames[selectedIWAD]
+              forKey:@"selected_iwad"];
+}
+
+// Callback method invoked when the configuration button in the main
+// window is clicked.
+
+- (void) openConfigWindow: (id)sender
+{
+    if (![self->configWindow isVisible])
+    {
+        [self->configWindow makeKeyAndOrderFront: sender];
+    }
+}
+
+// Callback method invoked when the close button is clicked.
+
+- (void) closeConfigWindow: (id)sender
+{
+    [self->configWindow orderOut: sender];
+    [self saveConfig];
+    [self setDropdownList];
+}
+
+- (void) awakeFromNib
+{
+    [self->configWindow center];
+
+    // Set configuration for all IWADs from configuration file.
+
+    [self setIWADConfig];
+
+    // Populate the dropdown IWAD list.
+
+    if ([self setDropdownList])
+    {
+        [self setDropdownSelection];
+    }
+}
+
+// Generate a value to set for the DOOMWADPATH environment variable
+// that contains each of the configured IWAD files.
+
+- (char *) doomWadPath
+{
+    IWADLocation *iwadList[NUM_IWAD_TYPES];
+    NSString *location;
+    unsigned int i;
+    unsigned int len;
+    BOOL first;
+    char *env;
+
+    [self getIWADList: iwadList];
+
+    // Calculate length of environment string.
+
+    len = 0;
+
+    for (i=0; i<NUM_IWAD_TYPES; ++i)
+    {
+        location = [iwadList[i] getLocation];
+
+        if (location != nil && [location length] > 0)
+        {
+            len += [location length] + 1;
+        }
+    }
+
+    // Build string.
+
+    env = malloc(len);
+    strcpy(env, "");
+
+    first = YES;
+
+    for (i=0; i<NUM_IWAD_TYPES; ++i)
+    {
+        location = [iwadList[i] getLocation];
+
+        if (location != nil && [location length] > 0)
+        {
+            if (!first)
+            {
+                strcat(env, ":");
+            }
+
+            strcat(env, [location UTF8String]);
+            first = NO;
+        }
+    }
+
+    return env;
+}
+
+// Set the DOOMWADPATH environment variable to contain the path to each
+// of the configured IWAD files.
+
+- (void) setEnvironment
+{
+    char *doomwadpath;
+    char *env;
+
+    // Get the value for the path.
+
+    doomwadpath = [self doomWadPath];
+
+    env = malloc(strlen(doomwadpath) + 15);
+
+    sprintf(env, "DOOMWADPATH=%s", doomwadpath);
+
+    free(doomwadpath);
+
+    // Load into environment:
+
+    putenv(env);
+
+    //free(env);
+}
+
+@end
+
--- /dev/null
+++ b/pkg/osx/IWADLocation.h
@@ -1,0 +1,44 @@
+/* ... */
+//-----------------------------------------------------------------------------
+//
+// Copyright(C) 2009 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.
+//
+//-----------------------------------------------------------------------------
+
+#ifndef LAUNCHER_IWADLOCATION_H
+#define LAUNCHER_IWADLOCATION_H
+
+#include <AppKit/AppKit.h>
+
+#include "IWADController.h"
+
+@interface IWADLocation : NSObject
+{
+    IWADController *iwadController;
+
+    id locationConfigBox;
+}
+
+- (void) setButtonClicked: (id)sender;
+- (NSString *) getLocation;
+- (void) setLocation: (NSString *) value;
+
+@end
+
+#endif /* #ifndef LAUNCHER_IWADLOCATION_H */
+
--- /dev/null
+++ b/pkg/osx/IWADLocation.m
@@ -1,0 +1,74 @@
+/* ... */
+//-----------------------------------------------------------------------------
+//
+// Copyright(C) 2009 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.
+//
+//-----------------------------------------------------------------------------
+
+#include <AppKit/AppKit.h>
+#include "IWADLocation.h"
+
+static id WAD_TYPES[] =
+{
+    @"wad", @"WAD"
+};
+
+@implementation IWADLocation
+
+- (void) setButtonClicked: (id)sender
+{
+    NSArray *wadTypes = [NSArray arrayWithObjects: WAD_TYPES count: 2];
+    NSOpenPanel *openPanel;
+    NSArray *filenames;
+    int result;
+
+    [wadTypes retain];
+
+    // Open a file selector for the new file.
+
+    openPanel = [NSOpenPanel openPanel];
+    [openPanel setTitle: @"Add IWAD file"];
+    [openPanel setCanChooseFiles: YES];
+    [openPanel setCanChooseDirectories: NO];
+
+    result = [openPanel runModalForTypes: wadTypes];
+
+    // If the "OK" button was clicked, add the new IWAD file to the list.
+
+    if (result == NSOKButton)
+    {
+        filenames = [openPanel filenames];
+	[self setLocation: [filenames lastObject]];
+
+        [self->iwadController saveConfig];
+        [self->iwadController setDropdownList];
+    }
+}
+
+- (NSString *) getLocation
+{
+    return [self->locationConfigBox stringValue];
+}
+
+- (void) setLocation: (NSString *) filename
+{
+    [self->locationConfigBox setStringValue: filename];
+}
+
+@end
+
--- /dev/null
+++ b/pkg/osx/Info-gnustep.plist.in
@@ -1,0 +1,36 @@
+{
+    ApplicationName = "@PACKAGE_NAME@";
+    ApplicationDescription = "@PACKAGE_SHORTDESC@";
+    ApplicationIcon = app.png;
+    ApplicationRelease = @PACKAGE_VERSION@;
+    ApplicationURL = "@PACKAGE_URL@";
+    Authors = (
+        "@PACKAGE_MAINTAINER@ <@PACKAGE_BUGREPORT@>"
+    );
+    Copyright = "@PACKAGE_COPYRIGHT@";
+    CopyrightDescription = "@PACKAGE_LICENSE@";
+    FullVersionID = @PACKAGE_VERSION@;
+    GSMainMarkupFile = "";
+    NSExecutable = "launcher";
+    NSIcon = app.png;
+    NSMainNibFile = launcher.nib;
+    NSPrincipalClass = NSApplication;
+    NSRole = Application;
+    NSTypes = (
+        {
+            NSHumanReadableName = "Doom WAD file";
+            NSUnixExtensions = ( wad );
+            NSRole = Viewer;
+            NSMimeTypes = (
+                "application/x-doom"
+            );
+            NSIcon = "wadfile.png";
+        },
+        {
+            NSHumanReadableName = "Dehacked patch";
+            NSUnixExtensions = ( deh );
+            NSRole = Viewer;
+            NSIcon = "wadfile.png";
+        }
+    );
+}
--- /dev/null
+++ b/pkg/osx/Info.plist.in
@@ -1,0 +1,60 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+<dict>
+	<key>CFBundleDevelopmentRegion</key>
+	<string>English</string>
+	<key>CFBundleDisplayName</key>
+	<string>@PACKAGE_NAME@</string>
+	<key>CFBundleExecutable</key>
+	<string>launcher</string>
+	<key>CFBundleGetInfoString</key>
+	<string>@PACKAGE_STRING@</string>
+	<key>CFBundleIconFile</key>
+	<string>app.icns</string>
+	<key>CFBundleInfoDictionaryVersion</key>
+	<string>6.0</string>
+	<key>CFBundleName</key>
+	<string>@PACKAGE_NAME@</string>
+	<key>CFBundlePackageType</key>
+	<string>APPL</string>
+	<key>CFBundleShortVersionString</key>
+	<string>@PACKAGE_VERSION@</string>
+	<key>CFBundleVersion</key>
+	<string>@PACKAGE_VERSION@</string>
+	<key>NSPrincipalClass</key>
+	<string>NSApplication</string>
+	<key>NSMainNibFile</key>
+	<string>launcher</string>
+
+        <!-- file associations: -->
+
+        <key>CFBundleDocumentTypes</key>
+        <array>
+                <dict>
+                        <key>CFBundleTypeName</key>
+                        <string>Doom WAD file</string>
+                        <key>CFBundleTypeIconFile</key>
+                        <string>wadfile.icns</string>
+                        <key>CFBundleTypeRole</key>
+                        <string>Viewer</string>
+                        <key>CFBundleTypeExtensions</key>
+                        <array>
+                                <string>wad</string>
+                        </array>
+                </dict>
+                <dict>
+                        <key>CFBundleTypeName</key>
+                        <string>Dehacked patch</string>
+                        <key>CFBundleTypeIconFile</key>
+                        <string>wadfile.icns</string>
+                        <key>CFBundleTypeRole</key>
+                        <string>Viewer</string>
+                        <key>CFBundleTypeExtensions</key>
+                        <array>
+                                <string>deh</string>
+                        </array>
+                </dict>
+        </array>
+</dict>
+</plist>
--- /dev/null
+++ b/pkg/osx/LauncherManager.h
@@ -1,0 +1,51 @@
+/* ... */
+//-----------------------------------------------------------------------------
+//
+// Copyright(C) 2009 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.
+//
+//-----------------------------------------------------------------------------
+
+#ifndef LAUNCHER_LAUNCHERMANAGER_H
+#define LAUNCHER_LAUNCHERMANAGER_H
+
+#include <AppKit/AppKit.h>
+#include <AppKit/NSNibLoading.h>
+#include "IWADController.h"
+
+@interface LauncherManager : NSObject
+{
+    IWADController *iwadController;
+
+    id launcherWindow;
+
+    id commandLineArguments;
+    id packageLabel;
+}
+
+- (void) launch: (id)sender;
+- (void) runSetup: (id)sender;
+- (void) awakeFromNib;
+- (void) clearCommandLine;
+- (void) addFileToCommandLine: (NSString *) fileName
+         forArgument: (NSString *) args;
+- (void) openTerminal: (id) sender;
+
+@end
+
+#endif /* #ifndef LAUNCHER_LAUNCHERMANAGER_H */
+
--- /dev/null
+++ b/pkg/osx/LauncherManager.m
@@ -1,0 +1,337 @@
+/* ... */
+//-----------------------------------------------------------------------------
+//
+// Copyright(C) 2009 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.
+//
+//-----------------------------------------------------------------------------
+
+#include <AppKit/AppKit.h>
+#include "Execute.h"
+#include "LauncherManager.h"
+#include "config.h"
+
+@implementation LauncherManager
+
+// Save configuration.  Invoked when we launch the game or quit.
+
+- (void) saveConfig
+{
+    NSUserDefaults *defaults;
+
+    // Save IWAD configuration and selected IWAD.
+
+    [self->iwadController saveConfig];
+
+    // Save command line arguments.
+
+    defaults = [NSUserDefaults standardUserDefaults];
+    [defaults setObject:[self->commandLineArguments stringValue]
+              forKey:@"command_line_args"];
+}
+
+// Load configuration, invoked on startup.
+
+- (void) setConfig
+{
+    NSUserDefaults *defaults;
+    NSString *args;
+
+    defaults = [NSUserDefaults standardUserDefaults];
+
+    args = [defaults stringForKey:@"command_line_args"];
+
+    if (args != nil)
+    {
+        [self->commandLineArguments setStringValue:args];
+    }
+}
+
+// Get the next command line argument from the command line.
+// The position counter used to iterate over arguments is in 'pos'.
+// The index of the argument that was found is saved in arg_pos.
+
+static NSString *GetNextArgument(NSString *commandLine, int *pos, int *arg_pos)
+{
+    NSRange arg_range;
+
+    // Skip past any whitespace
+
+    while (*pos < [commandLine length]
+        && isspace([commandLine characterAtIndex: *pos]))
+    {
+        ++*pos;
+    }
+
+    if (*pos >= [commandLine length])
+    {
+        *arg_pos = *pos;
+        return nil;
+    }
+
+    // We are at the start of the argument.  This may be a quoted
+    // string argument, or a "normal" one.
+
+    if ([commandLine characterAtIndex: *pos] == '\"')
+    {
+        // Quoted string, skip past first quote
+
+        ++*pos;
+
+        // Save start position:
+
+        *arg_pos = *pos;
+
+        while (*pos < [commandLine length]
+            && [commandLine characterAtIndex: *pos] != '\"')
+        {
+            ++*pos;
+        }
+
+        // Unexpected end of string?
+
+        if (*pos >= [commandLine length])
+        {
+            return nil;
+        }
+
+        arg_range = NSMakeRange(*arg_pos, *pos - *arg_pos);
+
+        // Skip past last quote
+
+        ++*pos;
+    }
+    else
+    {
+        // Normal argument
+
+        // Save position:
+
+        *arg_pos = *pos;
+
+        // Read until end:
+
+        while (*pos < [commandLine length]
+            && !isspace([commandLine characterAtIndex: *pos]))
+        {
+            ++*pos;
+        }
+
+        arg_range = NSMakeRange(*arg_pos, *pos - *arg_pos);
+    }
+
+    return [commandLine substringWithRange: arg_range];
+}
+
+// Given the specified command line argument, find the index
+// to insert the new file within the command line.  Returns -1 if the 
+// argument is not already within the arguments string.
+
+static int GetFileInsertIndex(NSString *commandLine, NSString *needle)
+{
+    NSString *arg;
+    int arg_pos;
+    int pos;
+
+    pos = 0;
+
+    // Find the command line parameter we are searching
+    // for (-merge, -deh, etc)
+
+    for (;;)
+    {
+        arg = GetNextArgument(commandLine, &pos, &arg_pos);
+
+        // Searched to end of string and never found?
+
+        if (arg == nil)
+        {
+            return -1;
+        }
+
+        if (![arg caseInsensitiveCompare: needle])
+        {
+            break;
+        }
+    }
+
+    // Now skip over existing files.  For example, if we
+    // have -file foo.wad bar.wad, the new file should be appended
+    // to the end of the list.
+
+    for (;;)
+    {
+        arg = GetNextArgument(commandLine, &pos, &arg_pos);
+
+        // If we search to the end of the string now, it is fine;
+        // the new string should be added to the end of the command
+        // line.  Otherwise, if we find an argument that begins
+        // with '-', it is a new command line parameter and the end
+        // of the list.
+
+        if (arg == nil || [arg characterAtIndex: 0] == '-')
+        {
+            break;
+        }
+    }
+
+    // arg_pos should now contain the offset to insert the new filename.
+
+    return arg_pos;
+}
+
+// Given the specified string, append a filename, quoted if necessary.
+
+static NSString *AppendQuotedFilename(NSString *str, NSString *fileName)
+{
+    int i;
+
+    // Search the filename for spaces, and quote if necessary.
+
+    for (i=0; i<[fileName length]; ++i)
+    {
+        if (isspace([fileName characterAtIndex: i]))
+        {
+            str = [str stringByAppendingString: @" \""];
+            str = [str stringByAppendingString: fileName];
+            str = [str stringByAppendingString: @"\" "];
+
+            return str;
+        }
+    }
+
+    str = [str stringByAppendingString: @" "];
+    str = [str stringByAppendingString: fileName];
+
+    return str;
+}
+
+// Clear out the existing command line options.
+// Invoked before the first file is added.
+
+- (void) clearCommandLine
+{
+    [self->commandLineArguments setStringValue: @""];
+}
+
+// Add a file to the command line to load with the game.
+
+- (void) addFileToCommandLine: (NSString *) fileName
+         forArgument: (NSString *) arg
+{
+    NSString *commandLine;
+    int insert_pos;
+
+    // Get the current command line
+
+    commandLine = [self->commandLineArguments stringValue];
+
+    // Find the location to insert the new filename:
+
+    insert_pos = GetFileInsertIndex(commandLine, arg);
+
+    // If position < 0, we should add the new argument and filename
+    // to the end.  Otherwise, append the new filename to the existing
+    // list of files.
+
+    if (insert_pos < 0)
+    {
+        commandLine = [commandLine stringByAppendingString: @" "];
+        commandLine = [commandLine stringByAppendingString: arg];
+        commandLine = AppendQuotedFilename(commandLine, fileName);
+    }
+    else
+    {
+        NSString *start;
+        NSString *end;
+
+        // Divide existing command line in half:
+
+        start = [commandLine substringToIndex: insert_pos];
+        end = [commandLine substringFromIndex: insert_pos];
+
+        // Construct new command line:
+
+        commandLine = AppendQuotedFilename(start, fileName);
+        commandLine = [commandLine stringByAppendingString: @" "];
+        commandLine = [commandLine stringByAppendingString: end];
+    }
+
+    [self->commandLineArguments setStringValue: commandLine];
+}
+
+- (void) launch: (id)sender
+{
+    NSString *iwad;
+    NSString *args;
+
+    [self saveConfig];
+
+    iwad = [self->iwadController getIWADLocation];
+    args = [self->commandLineArguments stringValue];
+
+    if (iwad == nil)
+    {
+        NSRunAlertPanel(@"No IWAD selected",
+                        @"You have not selected an IWAD (game) file.\n\n"
+                         "You must configure and select a valid IWAD file "
+                         "in order to launch the game.",
+                        @"OK", nil, nil);
+        return;
+    }
+
+    ExecuteProgram(PACKAGE_TARNAME, [iwad UTF8String],
+                                    [args UTF8String]);
+    [NSApp terminate:sender];
+}
+
+// Invoked when the "Setup Tool" button is clicked, to run the setup tool:
+
+- (void) runSetup: (id)sender
+{
+    [self saveConfig];
+
+    [self->iwadController setEnvironment];
+    ExecuteProgram("chocolate-setup", NULL, NULL);
+}
+
+// Invoked when the "Terminal" option is selected from the menu, to open
+// a terminal window.
+
+- (void) openTerminal: (id) sender
+{
+    char *doomwadpath;
+
+    [self saveConfig];
+
+    doomwadpath = [self->iwadController doomWadPath];
+
+    OpenTerminalWindow(doomwadpath);
+
+    free(doomwadpath);
+}
+
+- (void) awakeFromNib
+{
+    [self->packageLabel setStringValue: @PACKAGE_STRING];
+    [self->launcherWindow setTitle: @PACKAGE_NAME " Launcher"];
+    [self->launcherWindow center];
+    [self setConfig];
+}
+
+@end
+
--- /dev/null
+++ b/pkg/osx/PkgInfo
@@ -1,0 +1,1 @@
+APPL????
binary files /dev/null b/pkg/osx/Resources/128x128.png differ
binary files /dev/null b/pkg/osx/Resources/app.icns differ
binary files /dev/null b/pkg/osx/Resources/app.png differ
--- /dev/null
+++ b/pkg/osx/Resources/launcher.nib/classes.nib
@@ -1,0 +1,46 @@
+{
+    IBClasses = (
+        {
+            CLASS = AppController; 
+            LANGUAGE = ObjC; 
+            OUTLETS = {launcherManager = id; }; 
+            SUPERCLASS = NSObject; 
+        }, 
+        {CLASS = FirstResponder; LANGUAGE = ObjC; SUPERCLASS = NSObject; }, 
+        {
+            ACTIONS = {closeConfigWindow = id; openConfigWindow = id; }; 
+            CLASS = IWADController; 
+            LANGUAGE = ObjC; 
+            OUTLETS = {
+                chex = id; 
+                configWindow = id; 
+                doom1 = id; 
+                doom2 = id; 
+                iwadSelector = id; 
+                plutonia = id; 
+                tnt = id; 
+            }; 
+            SUPERCLASS = NSObject; 
+        }, 
+        {
+            ACTIONS = {setButtonClicked = id; }; 
+            CLASS = IWADLocation; 
+            LANGUAGE = ObjC; 
+            OUTLETS = {locationConfigBox = id; }; 
+            SUPERCLASS = NSObject; 
+        }, 
+        {
+            ACTIONS = {launch = id; openTerminal = id; runSetup = id; }; 
+            CLASS = LauncherManager; 
+            LANGUAGE = ObjC; 
+            OUTLETS = {
+                commandLineArguments = id; 
+                iwadController = id; 
+                launcherWindow = id; 
+                packageLabel = id; 
+            }; 
+            SUPERCLASS = NSObject; 
+        }
+    ); 
+    IBVersion = 1; 
+}
\ No newline at end of file
--- /dev/null
+++ b/pkg/osx/Resources/launcher.nib/info.nib
@@ -1,0 +1,23 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+<dict>
+	<key>IBDocumentLocation</key>
+	<string>484 105 612 260 0 0 1440 878 </string>
+	<key>IBEditorPositions</key>
+	<dict>
+		<key>29</key>
+		<string>221 322 205 44 0 0 1440 878 </string>
+	</dict>
+	<key>IBFramework Version</key>
+	<string>446.1</string>
+	<key>IBOpenObjects</key>
+	<array>
+		<integer>29</integer>
+		<integer>21</integer>
+		<integer>227</integer>
+	</array>
+	<key>IBSystem Version</key>
+	<string>8S2167</string>
+</dict>
+</plist>
binary files /dev/null b/pkg/osx/Resources/launcher.nib/keyedobjects.nib differ
binary files /dev/null b/pkg/osx/Resources/wadfile.icns differ
binary files /dev/null b/pkg/osx/Resources/wadfile.png differ
--- /dev/null
+++ b/pkg/osx/cp-with-libs
@@ -1,0 +1,100 @@
+#!/bin/bash
+#
+# Copy a program to the specified destination, along
+# with libraries it depends upon.
+
+src_bin=$1
+dest_dir=$2
+
+# Returns true if the specified file is a dylib.
+
+is_dylib() {
+	case "$1" in
+		*.dylib)
+			true
+			;;
+		*)
+			false
+			;;
+	esac
+}
+
+# Returns true if the specified file is in a system location
+# (/System or /usr):
+
+is_sys_lib() {
+	case "$1" in
+		/System/*)
+			true
+			;;
+		/usr/*)
+			true
+			;;
+		*)
+			false
+			;;
+	esac
+}
+
+# Install the specified file to the location in dest_dir, along with
+# any libraries it depends upon (recursively):
+
+install_with_deps() {
+	local src_file
+	local bin_name
+	local dest_file
+	local lib_name
+
+	src_file=$1
+	bin_name=$(basename "$src_file")
+	dest_file="$dest_dir/$bin_name"
+
+	# Already copied into the package? Don't copy again.
+	# Prevents endless recursion.
+
+	if [ -e "$dest_file" ]; then
+		return
+	fi	
+
+	echo "Installing $bin_name..."
+
+	# Copy file into package.
+
+	cp "$src_file" "$dest_file"
+
+	# Copy libraries that this file depends on:
+
+	otool -L "$src_file" | tail -n +2 | sed 's/^.//; s/ (.*//' | while read; do
+		
+		# Don't copy system libraries
+
+		if is_sys_lib "$REPLY"; then
+			continue
+		fi
+
+		#echo "    - $bin_name depends on $REPLY"
+
+		# Copy this library into the package, and:
+		# recursively install any libraries that _this_ library depends on:
+
+		install_with_deps "$REPLY"
+
+		# Change destination binary to depend on the
+		# copy inside the package:
+
+		lib_name=$(basename "$REPLY")
+		install_name_tool -change "$REPLY" "@executable_path/$lib_name" \
+		                  "$dest_file"
+	done
+
+	# If this is a library that we have installed, change its id:
+
+	if is_dylib "$dest_file"; then
+		install_name_tool -id "@executable_path/$bin_name" "$dest_file"
+	fi
+}
+
+# Install the file, and recursively install any libraries:
+
+install_with_deps "$src_bin"
+
--- /dev/null
+++ b/pkg/osx/main.m
@@ -1,0 +1,32 @@
+/* ... */
+//-----------------------------------------------------------------------------
+//
+// Copyright(C) 2009 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.
+//
+//-----------------------------------------------------------------------------
+
+#include <AppKit/AppKit.h>
+#include "Execute.h"
+
+int main(int argc, const char *argv[])
+{
+    SetProgramLocation(argv[0]);
+
+    return NSApplicationMain (argc, argv);
+}
+
--- /dev/null
+++ b/pkg/win32/GNUmakefile
@@ -1,0 +1,32 @@
+
+include ../config.make
+
+TOPLEVEL=../..
+
+EXE_FILES=$(TOPLEVEL)/src/$(PACKAGE_TARNAME).exe       \
+          $(TOPLEVEL)/src/chocolate-server.exe         \
+          $(TOPLEVEL)/setup/chocolate-setup.exe
+
+DLL_FILES=$(TOPLEVEL)/src/SDL.dll                      \
+          $(TOPLEVEL)/src/SDL_mixer.dll                \
+          $(TOPLEVEL)/src/SDL_net.dll
+
+ZIP=$(PACKAGE_TARNAME)-$(PACKAGE_VERSION)-win32.zip
+
+$(ZIP) : staging
+	zip -j -r $@ staging/
+
+staging: $(EXE_FILES) $(DLL_FILES) $(patsubst %,../../%,$(DOC_FILES))
+	rm -rf staging
+	mkdir staging
+	cp $(EXE_FILES) $(DLL_FILES) staging/
+	$(STRIP) staging/*.exe
+	for f in $(DOC_FILES); do                    \
+		cp $(TOPLEVEL)/$$f staging/$$f.txt;  \
+		unix2dos staging/$$f.txt;            \
+	done
+
+clean:
+	rm -f $(ZIP)
+	rm -rf staging
+
--- /dev/null
+++ b/pkg/win32/README
@@ -1,0 +1,4 @@
+
+Makefile to build Windows packages.  Requires zip and unix2dos cygwin
+packages to be installed.
+
--- /dev/null
+++ b/pkg/wince/GNUmakefile
@@ -1,0 +1,15 @@
+
+include ../config.make
+
+DEPS=$(shell ./wince-cabgen -d $(CONFIG_FILE))
+EXECUTABLES=$(filter %.exe, $(DEPS))
+CONFIG_FILE=wince-cab.cfg
+OUTPUT_FILE=$(PACKAGE_TARNAME)-$(PACKAGE_VERSION).cab
+
+$(OUTPUT_FILE) : $(CONFIG_FILE) $(DEPS)
+	$(STRIP) $(EXECUTABLES)
+	./wince-cabgen $< $@
+
+clean:
+	rm -f $(OUTPUT_FILE)
+
--- a/pkg/wince/GNUmakefile.am
+++ /dev/null
@@ -1,12 +1,0 @@
-
-DEPS=$(shell ./wince-cabgen -d $(CONFIG_FILE))
-CONFIG_FILE=wince-cab.cfg
-OUTPUT_FILE=@PACKAGE_TARNAME@-@[email protected]
-
-EXTRA_DIST=wince-cabgen $(CONFIG_FILE)
-
-noinst_DATA = $(OUTPUT_FILE)
-
-$(OUTPUT_FILE) : $(CONFIG_FILE) $(DEPS)
-	./wince-cabgen $< $@
-
--- /dev/null
+++ b/rpm.spec.in
@@ -1,0 +1,59 @@
+
+Name: @PACKAGE@
+Summary: @PACKAGE_SHORTDESC@
+Version: @VERSION@
+Release: 1
+Source: http://mesh.dl.sourceforge.net/project/chocolate-doom/@PACKAGE@/@VERSION@/@PACKAGE@-@[email protected]
+URL: @PACKAGE_URL@
+Group: Amusements/Games
+BuildRoot: /var/tmp/@PACKAGE@-buildroot
+License: @PACKAGE_LICENSE@
+Packager: @PACKAGE_MAINTAINER@ <@PACKAGE_BUGREPORT@>
+Prefix: %{_prefix}
+Autoreq: 0
+Requires: libSDL-1.2.so.0, libSDL_mixer-1.2.so.0, libSDL_net-1.2.so.0
+
+%description
+%(sed -n "/==/ q; p " < README)
+
+See @PACKAGE_URL@ for more information.
+
+%prep
+rm -rf $RPM_BUILD_ROOT
+
+%setup -q
+
+%build
+./configure \
+ 	--prefix=/usr \
+	--exec-prefix=/usr \
+	--bindir=/usr/bin \
+	--sbindir=/usr/sbin \
+	--sysconfdir=/etc \
+	--datadir=/usr/share \
+	--includedir=/usr/include \
+	--libdir=/usr/lib \
+	--libexecdir=/usr/lib \
+	--localstatedir=/var/lib \
+	--sharedstatedir=/usr/com \
+	--mandir=/usr/share/man \
+	--infodir=/usr/share/info
+make
+
+%install
+%makeinstall
+
+%clean
+rm -rf $RPM_BUILD_ROOT
+
+%files
+%doc %{_mandir}/man5/*
+%doc %{_mandir}/man6/*
+%doc NEWS
+%doc AUTHORS
+%doc README
+%doc COPYING
+%doc CMDLINE
+%doc BUGS
+/usr/games/*
+
--- a/setup/.gitignore
+++ b/setup/.gitignore
@@ -4,3 +4,5 @@
 chocolate-setup
 *.rc
 *.exe
+tags
+TAGS
--- a/setup/Makefile.am
+++ b/setup/Makefile.am
@@ -44,7 +44,7 @@
 
 if HAVE_PYTHON
 
-setup_icon.c : ../data/setup.ico
+setup_icon.c : ../data/setup8.ico
 	../data/convert-icon $^ $@
 
 endif
--- a/setup/execute.c
+++ b/setup/execute.c
@@ -185,29 +185,38 @@
 
 static wchar_t *BuildCommandLine(const char *program, const char *arg)
 {
+    wchar_t exe_path[MAX_PATH];
     wchar_t *result;
-    char *sep;
+    wchar_t *sep;
 
-    result = calloc(strlen(myargv[0]) + strlen(program) + strlen(arg) + 6,
+    // Get the path to this .exe file.
+
+    GetModuleFileNameW(NULL, exe_path, MAX_PATH);
+
+    // Allocate buffer to contain result string.
+
+    result = calloc(wcslen(exe_path) + strlen(program) + strlen(arg) + 6,
                     sizeof(wchar_t));
 
     wcscpy(result, L"\"");
 
-    sep = strrchr(myargv[0], DIR_SEPARATOR);
+    // Copy the path part of the filename (including ending \)
+    // into the result buffer:
 
+    sep = wcsrchr(exe_path, DIR_SEPARATOR);
+
     if (sep != NULL)
     {
-        ConcatWCString(result, myargv[0]);
-
-        // Cut off the string after the last directory separator,
-        // before appending the actual program.
-
-        result[sep - myargv[0] + 2] = '\0';
-        
+        wcsncpy(result + 1, exe_path, sep - exe_path + 1);
+        result[sep - exe_path + 2] = '\0';
     }
 
+    // Concatenate the name of the program:
+
     ConcatWCString(result, program);
 
+    // End of program name, start of argument:
+
     wcscat(result, L"\" \"");
 
     ConcatWCString(result, arg);
@@ -301,9 +310,9 @@
         argv[1] = arg;
         argv[2] = NULL;
 
-        execv(argv[0], (char **) argv);
+        execvp(argv[0], (char **) argv);
 
-        exit(-1);
+        exit(0x80);
     }
     else
     {
@@ -312,7 +321,7 @@
 
         waitpid(childpid, &result, 0);
 
-        if (WIFEXITED(result)) 
+        if (WIFEXITED(result) && WEXITSTATUS(result) != 0x80) 
         {
             return WEXITSTATUS(result);
         }
--- a/setup/setup-manifest.xml
+++ b/setup/setup-manifest.xml
@@ -1,16 +1,33 @@
 <?xml version="1.0" encoding="UTF-8" standalone="yes"?>
+
+<!-- Magic manifest file that should make Windows Vista/7 not
+     attempt to gain elevated privileges for chocolate-setup.
+     
+     Based on:
+     
+     http://www.cygwin.com/ml/cygwin/2006-12/msg00580.html
+  -->
+
 <assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0">
   <!-- The "name" field in this tag should be the same as the executable's
        name -->
-  <assemblyIdentity version="1.2.1.0" processorArchitecture="*"
-                    name="chocolate-setup" type="win32"/>
+  <assemblyIdentity version="0.0.0.0" processorArchitecture="X86"
+                    name="chocolate-setup.exe" type="win32"/>
   <trustInfo xmlns="urn:schemas-microsoft-com:asm.v3">
     <security>
       <requestedPrivileges>
-        <!-- Hi Vista! We don't require elevated privileges. Thanks! -->
-        <requestedExecutionLevel level="asInvoker"/>
+        <requestedExecutionLevel level="asInvoker" uiAccess="false" />
       </requestedPrivileges>
     </security>
   </trustInfo>
+
+  <!-- Stop the Program Compatibility Assistant appearing: -->
+
+  <compatibility xmlns="urn:schemas-microsoft-com:compatibility.v1">
+    <application>
+      <supportedOS Id="{35138b9a-5d96-4fbd-8e2d-a2440225f93a}"/> <!-- 7 -->
+      <supportedOS Id="{e2011457-1546-43c5-a5fe-008deee3d3f0}"/> <!-- Vista -->
+    </application>
+  </compatibility>
 </assembly>
 
--- a/setup/setup-res.rc.in
+++ b/setup/setup-res.rc.in
@@ -1,6 +1,6 @@
 1 ICON "../data/setup.ico"
 
-CREATEPROCESS_MANIFEST_RESOURCE_ID RT_MANIFEST "setup-manifest.xml"
+1 24 MOVEABLE PURE "setup-manifest.xml"
 
 1 VERSIONINFO
 PRODUCTVERSION @WINDOWS_RC_VERSION@
--- a/src/.gitignore
+++ b/src/.gitignore
@@ -5,3 +5,5 @@
 chocolate-doom
 chocolate-server
 *.exe
+tags
+TAGS
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -191,7 +191,7 @@
 
 if HAVE_PYTHON
 
-icon.c : ../data/doom.ico
+icon.c : ../data/doom8.ico
 	../data/convert-icon $^ $@
 
 endif
--- a/src/d_iwad.c
+++ b/src/d_iwad.c
@@ -338,40 +338,81 @@
     }
 }
 
+// Returns true if the specified path is a path to a file
+// of the specified name.
+
+static boolean DirIsFile(char *path, char *filename)
+{
+    size_t path_len;
+    size_t filename_len;
+
+    path_len = strlen(path);
+    filename_len = strlen(filename);
+
+    return path_len >= filename_len + 1
+        && path[path_len - filename_len - 1] == DIR_SEPARATOR
+        && !strcasecmp(&path[path_len - filename_len], filename);
+}
+
+// Check if the specified directory contains the specified IWAD
+// file, returning the full path to the IWAD if found, or NULL
+// if not found.
+
+static char *CheckDirectoryHasIWAD(char *dir, char *iwadname)
+{
+    char *filename; 
+
+    // As a special case, the "directory" may refer directly to an
+    // IWAD file if the path comes from DOOMWADDIR or DOOMWADPATH.
+    
+    if (DirIsFile(dir, iwadname) && M_FileExists(dir))
+    {
+        return strdup(dir);
+    }
+
+    // Construct the full path to the IWAD if it is located in
+    // this directory, and check if it exists.
+
+    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))
+    {
+        return filename;
+    }
+
+    free(filename);
+
+    return NULL;
+}
+
 // Search a directory to try to find an IWAD
 // Returns the location of the IWAD if found, otherwise NULL.
 
 static char *SearchDirectoryForIWAD(char *dir)
 {
+    char *filename;
     size_t i;
 
     for (i=0; i<arrlen(iwads); ++i) 
     {
-        char *filename; 
-        char *iwadname;
+        filename = CheckDirectoryHasIWAD(dir, DEH_String(iwads[i].name));
 
-        iwadname = DEH_String(iwads[i].name);
-        
-        filename = malloc(strlen(dir) + strlen(iwadname) + 3);
-
-        if (!strcmp(dir, "."))
+        if (filename != NULL)
         {
-            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;
@@ -525,7 +566,6 @@
 {
     char *buf;
     int i;
-    boolean exists;
     
     // Absolute path?
 
@@ -540,14 +580,21 @@
 
     for (i=0; i<num_iwad_dirs; ++i)
     {
+        // As a special case, if this is in DOOMWADDIR or DOOMWADPATH,
+        // the "directory" may actually refer directly to an IWAD
+        // file.
+
+        if (DirIsFile(iwad_dirs[i], name) && M_FileExists(iwad_dirs[i]))
+        {
+            return strdup(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)
+        if (M_FileExists(buf))
         {
             return buf;
         }
--- a/src/g_game.c
+++ b/src/g_game.c
@@ -650,10 +650,20 @@
 
     if (lowres_turn)
     {
-        // round angleturn to the nearest 256 boundary
+        static signed short carry = 0;
+        signed short desired_angleturn;
+
+        desired_angleturn = cmd->angleturn + carry;
+
+        // round angleturn to the nearest 256 unit boundary
         // for recording demos with single byte values for turn
 
-        cmd->angleturn = (cmd->angleturn + 128) & 0xff00;
+        cmd->angleturn = (desired_angleturn + 128) & 0xff00;
+
+        // Carry forward the error from the reduced resolution to the
+        // next tic, so that successive small movements can accumulate.
+
+        carry = desired_angleturn - cmd->angleturn;
     }
 } 
  
--- a/src/hu_stuff.c
+++ b/src/hu_stuff.c
@@ -50,9 +50,9 @@
 // Locally used constants, shortcuts.
 //
 #define HU_TITLE	(mapnames[(gameepisode-1)*9+gamemap-1])
-#define HU_TITLE2	(mapnames2[gamemap-1])
-#define HU_TITLEP	(mapnamesp[gamemap-1])
-#define HU_TITLET	(mapnamest[gamemap-1])
+#define HU_TITLE2	(mapnames_commercial[gamemap-1])
+#define HU_TITLEP	(mapnames_commercial[gamemap-1 + 32])
+#define HU_TITLET	(mapnames_commercial[gamemap-1 + 64])
 #define HU_TITLE_CHEX   (mapnames[gamemap - 1])
 #define HU_TITLEHEIGHT	1
 #define HU_TITLEX	0
@@ -171,8 +171,16 @@
     "NEWLEVEL"
 };
 
-char*	mapnames2[] =	// DOOM 2 map names.
+// List of names for levels in commercial IWADs
+// (doom2.wad, plutonia.wad, tnt.wad).  These are stored in a
+// single large array; WADs like pl2.wad have a MAP33, and rely on
+// the layout in the Vanilla executable, where it is possible to
+// overflow the end of one array into the next.
+
+char *mapnames_commercial[] =
 {
+    // DOOM 2 map names.
+
     HUSTR_1,
     HUSTR_2,
     HUSTR_3,
@@ -206,12 +214,10 @@
     HUSTR_29,
     HUSTR_30,
     HUSTR_31,
-    HUSTR_32
-};
+    HUSTR_32,
 
+    // Plutonia WAD map names.
 
-char*	mapnamesp[] =	// Plutonia WAD map names.
-{
     PHUSTR_1,
     PHUSTR_2,
     PHUSTR_3,
@@ -245,12 +251,10 @@
     PHUSTR_29,
     PHUSTR_30,
     PHUSTR_31,
-    PHUSTR_32
-};
+    PHUSTR_32,
+    
+    // TNT WAD map names.
 
-
-char *mapnamest[] =	// TNT WAD map names.
-{
     THUSTR_1,
     THUSTR_2,
     THUSTR_3,
--- a/src/i_video.c
+++ b/src/i_video.c
@@ -402,6 +402,7 @@
 {
     if (initialized)
     {
+        SDL_SetCursor(cursors[1]);
         SDL_ShowCursor(1);
         SDL_WM_GrabInput(SDL_GRAB_OFF);
 
--- a/src/p_map.c
+++ b/src/p_map.c
@@ -885,7 +885,17 @@
 	
 	dist = FixedMul (attackrange, in->frac);
 
-	if (li->frontsector->floorheight != li->backsector->floorheight)
+        // Return false if there is no back sector.  This should never
+        // be the case if the line is two-sided; however, some WADs
+        // (eg. ottawau.wad) use this as an "impassible glass" trick
+        // and rely on Vanilla Doom's (unintentional) support for this.
+
+        if (li->backsector == NULL)
+        {
+            return false;
+        }
+
+        if (li->frontsector->floorheight != li->backsector->floorheight)
 	{
 	    slope = FixedDiv (openbottom - shootz , dist);
 	    if (slope > bottomslope)
@@ -973,7 +983,14 @@
 		
 	dist = FixedMul (attackrange, in->frac);
 
-	if (li->frontsector->floorheight != li->backsector->floorheight)
+        // Check if backsector is NULL.  See comment in PTR_AimTraverse.
+
+	if (li->backsector == NULL)
+        {
+            goto hitline;
+        }
+
+        if (li->frontsector->floorheight != li->backsector->floorheight)
 	{
 	    slope = FixedDiv (openbottom - shootz , dist);
 	    if (slope > aimslope)
--- a/src/p_setup.c
+++ b/src/p_setup.c
@@ -167,6 +167,7 @@
     line_t*		ldef;
     int			linedef;
     int			side;
+    int                 sidenum;
 	
     numsegs = W_LumpLength (lump) / sizeof(mapseg_t);
     segs = Z_Malloc (numsegs*sizeof(seg_t),PU_LEVEL,0);	
@@ -179,7 +180,7 @@
     {
 	li->v1 = &vertexes[SHORT(ml->v1)];
 	li->v2 = &vertexes[SHORT(ml->v2)];
-					
+
 	li->angle = (SHORT(ml->angle))<<16;
 	li->offset = (SHORT(ml->offset))<<16;
 	linedef = SHORT(ml->linedef);
@@ -188,10 +189,28 @@
 	side = SHORT(ml->side);
 	li->sidedef = &sides[ldef->sidenum[side]];
 	li->frontsector = sides[ldef->sidenum[side]].sector;
-	if (ldef-> flags & ML_TWOSIDED)
-	    li->backsector = sides[ldef->sidenum[side^1]].sector;
-	else
+
+        if (ldef-> flags & ML_TWOSIDED)
+        {
+            sidenum = ldef->sidenum[side ^ 1];
+
+            // If the sidenum is out of range, this may be a "glass hack"
+            // impassible window.  Point at side #0 (this may not be
+            // the correct Vanilla behavior; however, it seems to work for
+            // OTTAWAU.WAD, which is the one place I've seen this trick
+            // used).
+
+            if (sidenum < 0 || sidenum >= numsides)
+            {
+                sidenum = 0;
+            }
+
+            li->backsector = sides[sidenum].sector;
+        }
+        else
+        {
 	    li->backsector = 0;
+        }
     }
 	
     W_ReleaseLumpNum(lump);
--- a/src/p_sight.c
+++ b/src/p_sight.c
@@ -173,7 +173,7 @@
 	    continue;
 	
 	line->validcount = validcount;
-		
+
 	v1 = line->v1;
 	v2 = line->v2;
 	s1 = P_DivlineSide (v1->x,v1->y, &strace);
@@ -193,6 +193,14 @@
 	// line isn't crossed?
 	if (s1 == s2)
 	    continue;	
+
+        // Backsector may be NULL if this is an "impassible
+        // glass" hack line.
+
+        if (line->backsector == NULL)
+        {
+            return false;
+        }
 
 	// stop because it is not two sided anyway
 	// might do this after updating validcount?
--- a/src/st_stuff.c
+++ b/src/st_stuff.c
@@ -259,9 +259,6 @@
  // Height, in lines. 
 #define ST_OUTHEIGHT		1
 
-#define ST_MAPWIDTH	\
-    (strlen(mapnames[(gameepisode-1)*9+(gamemap-1)]))
-
 #define ST_MAPTITLEX \
     (SCREENWIDTH - ST_MAPWIDTH * ST_CHATFONTWIDTH)
 
@@ -418,10 +415,6 @@
 cheatseq_t cheat_mypos = CHEAT("idmypos", 0);
 
 
-// 
-extern char*	mapnames[];
-
-
 //
 // STATUS BAR CODE
 //
@@ -980,6 +973,17 @@
 	palette = RADIATIONPAL;
     else
 	palette = 0;
+
+    // In Chex Quest, the player never sees red.  Instead, the
+    // radiation suit palette is used to tint the screen green,
+    // as though the player is being covered in goo by an
+    // attacking flemoid.
+
+    if (gameversion == exe_chex
+     && palette >= STARTREDPALS && palette < STARTREDPALS + NUMREDPALS)
+    {
+        palette = RADIATIONPAL;
+    }
 
     if (palette != st_palette)
     {
--- a/textscreen/.gitignore
+++ b/textscreen/.gitignore
@@ -2,3 +2,5 @@
 Makefile.in
 .deps
 *.a
+tags
+TAGS
--- a/textscreen/examples/.gitignore
+++ b/textscreen/examples/.gitignore
@@ -4,3 +4,5 @@
 guitest
 calculator
 *.exe
+tags
+TAGS
--- a/textscreen/txt_sdl.c
+++ b/textscreen/txt_sdl.c
@@ -285,10 +285,10 @@
     int x_end;
     int y_end;
 
-    x_end = LimitToRange(x + w, 0, TXT_SCREEN_W - 1);
-    y_end = LimitToRange(y + h, 0, TXT_SCREEN_H - 1);
-    x = LimitToRange(x, 0, TXT_SCREEN_W - 1);
-    y = LimitToRange(y, 0, TXT_SCREEN_H - 1);
+    x_end = LimitToRange(x + w, 0, TXT_SCREEN_W);
+    y_end = LimitToRange(y + h, 0, TXT_SCREEN_H);
+    x = LimitToRange(x, 0, TXT_SCREEN_W);
+    y = LimitToRange(y, 0, TXT_SCREEN_H);
 
     for (y1=y; y1<y_end; ++y1)
     {
--- /dev/null
+++ b/wince/.gitignore
@@ -1,0 +1,5 @@
+Makefile
+Makefile.in
+.deps
+tags
+TAGS
--- a/wince/Makefile.am
+++ b/wince/Makefile.am
@@ -4,6 +4,7 @@
 if WINDOWS_CE
 
 libc_wince_a_SOURCES =                            \
+        libc_wince.h                              \
         env.c            env.h                    \
 	errno.c          errno.h                  \
         fileops.c        fileops.h