ref: d06dcf916776e58b1f476cf9320b5274a28957b1
parent: d91e3e86736f710265629e56dc77c1dec0b425e7
parent: 24783792e5398a2d5af6b7220b68c46357d23e31
author: Simon Howard <[email protected]>
date: Thu Jul 9 13:50:04 EDT 2009
Merge from trunk. Subversion-branch: /branches/raven-branch Subversion-revision: 1610
--- a/NEWS
+++ b/NEWS
@@ -1,3 +1,47 @@
+...
+
+ * 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.
+ * 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.
+
+ Compatibility:
+ * The A_BossDeath behavior in v1.9 emulation mode was fixed
+ (thanks entryway)
+
+ Bugs fixed:
+ * 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
+ 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
+ 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.
+
1.2.1 (2008-12-10):
This version just fixes a crash at the intermission screen when
--- a/configure.in
+++ b/configure.in
@@ -113,6 +113,7 @@
src/hexen/Makefile
src/setup/Makefile
pcsound/Makefile
+pkg/wince/Makefile
src/resource.rc
src/setup-res.rc
src/setup/setup-manifest.xml
--- /dev/null
+++ b/pkg/wince/.gitignore
@@ -1,0 +1,3 @@
+Makefile
+Makefile.in
+*.cab
--- /dev/null
+++ b/pkg/wince/Makefile.am
@@ -1,0 +1,10 @@
+
+DEPS=$(shell ./wince-cabgen -d $(CONFIG_FILE))
+CONFIG_FILE=wince-cab.cfg
+OUTPUT_FILE=@PACKAGE_TARNAME@-@[email protected]
+
+noinst_DATA = $(OUTPUT_FILE)
+
+$(OUTPUT_FILE) : $(CONFIG_FILE) $(DEPS)
+ ./wince-cabgen $< $@
+
--- /dev/null
+++ b/pkg/wince/wince-cab.cfg
@@ -1,0 +1,25 @@
+
+app_name = "Chocolate Doom"
+provider = "Simon Howard"
+arch = "strongarm"
+
+# Install files:
+
+d = "$(PROGRAMS_GAMES)/Chocolate Doom/"
+s = "$(START_GAMES)/"
+
+files = {
+ d+"chocolate-doom.exe": "../../src/chocolate-doom.exe",
+ d+"chocolate-setup.exe": "../../setup/chocolate-setup.exe",
+ d+"SDL.dll": "SDL.dll",
+ d+"SDL_mixer.dll": "SDL_mixer.dll",
+ d+"libSDL_net-1-2-0.dll": "libSDL_net-1-2-0.dll",
+}
+
+# Start menu links:
+
+links = {
+ s+"Chocolate Doom.lnk": d+"chocolate-doom.exe",
+ s+"Chocolate Doom Setup.lnk": d+"chocolate-setup.exe"
+}
+
--- /dev/null
+++ b/pkg/wince/wince-cabgen
@@ -1,0 +1,672 @@
+#!/usr/bin/env python
+
+import os
+import re
+import shutil
+import sys
+import tempfile
+
+CAB_HEADER = "MSCE"
+
+ARCHITECTURES = {
+ "shx-sh3": 103,
+ "shx-sh4": 104,
+ "i386": 386,
+ "i486": 486,
+ "i586": 586,
+ "powerpc-601": 601,
+ "powerpc-603": 603,
+ "powerpc-604": 604,
+ "powerpc-620": 620,
+ "powerpc-mpc821": 821,
+ "arm720": 1824,
+ "arm820": 2080,
+ "arm920": 2336,
+ "strongarm": 2577,
+ "mips-r4000": 4000,
+ "sh3": 10003,
+ "sh3e": 10004,
+ "sh4": 10005,
+ "alpha-21064": 21064,
+ "arm7tdmi": 70001,
+}
+
+DIR_VARIABLES = {
+ "PROGRAMS": "%CE1%", # \Program Files
+ "WINDOWS": "%CE2%", # \Windows
+ "DESKTOP": "%CE3%", # \Windows\Desktop
+ "STARTUP": "%CE4%", # \Windows\StartUp
+ "DOCUMENTS": "%CE5%", # \My Documents
+ "PROGRAMS_ACCESSORIES": "%CE6%", # \Program Files\Accessories
+ "PROGRAMS_COMMUNICATIONS": "%CE7%", # \Program Files\Communications
+ "PROGRAMS_GAMES": "%CE8%", # \Program Files\Games
+ "PROGRAMS_OUTLOOK": "%CE9%", # \Program Files\Pocket Outlook
+ "PROGRAMS_OFFICE": "%CE10%", # \Program Files\Office
+ "WINDOWS_PROGRAMS": "%CE11%", # \Windows\Programs
+ "WINDOWS_ACCESSORIES": "%CE12%", # \Windows\Programs\Accessories
+ "WINDOWS_COMMUNICATIONS": "%CE13%", # \Windows\Programs\Communications
+ "WINDOWS_GAMES": "%CE14%", # \Windows\Programs\Games
+ "FONTS": "%CE15%", # \Windows\Fonts
+ "RECENT": "%CE16%", # \Windows\Recent
+ "FAVORITES": "%CE17%", # \Windows\Favorites
+
+ "START_PROGRAMS": "%CE11%", # \Windows\Start Menu\Programs
+ "START_ACCESSORIES": "%CE12%", # \Windows\Start Menu\Accessories
+ "START_COMMUNICATIONS": "%CE13%", # \Windows\Start Menu\Communications
+ "START_GAMES": "%CE14%", # \Windows\Start Menu\Games
+ "START": "%CE17%", # \Windows\Start Menu
+}
+
+def write_int16(f, value):
+ b1 = value & 0xff
+ b2 = (value >> 8) & 0xff
+ f.write("%c%c" % (b1, b2))
+
+def write_int32(f, value):
+ b1 = value & 0xff
+ b2 = (value >> 8) & 0xff
+ b3 = (value >> 16) & 0xff
+ b4 = (value >> 24) & 0xff
+ f.write("%c%c%c%c" % (b1, b2, b3, b4))
+
+# Pad a string with NUL characters so that it has a length that is
+# a multiple of 4. At least one NUL is always added.
+
+def pad_string(s):
+ pad_len = 4 - (len(s) % 4)
+ return s + (pad_len * "\x00")
+
+class HeaderSection:
+
+ def __init__(self, cab_header):
+ self.cab_header = cab_header
+ self.arch = None
+ self.app_name = None
+ self.provider = None
+ self.unsupported = None
+
+ def __len__(self):
+ return 100 # header has fixed size
+
+ def set_meta(self, arch, app_name, provider, unsupported):
+
+ if arch not in ARCHITECTURES:
+ raise Exception("Unknown architecture '%s'" % arch)
+
+ self.arch = ARCHITECTURES[arch]
+
+ dictionary = self.cab_header.dictionary
+
+ self.app_name = app_name
+ dictionary.get(self.app_name)
+
+ self.provider = provider
+ dictionary.get(self.provider)
+
+ self.unsupported = unsupported
+ dictionary.get(self.unsupported)
+
+ def write(self, stream):
+
+ # Basic header
+
+ stream.write(CAB_HEADER)
+ write_int32(stream, 0)
+ write_int32(stream, len(self.cab_header))
+ write_int32(stream, 0)
+ write_int32(stream, 1)
+ write_int32(stream, self.arch)
+
+ # minimum Windows CE version:
+ write_int32(stream, 0)
+ write_int32(stream, 0)
+ write_int32(stream, 0)
+ write_int32(stream, 0)
+ write_int32(stream, 0)
+ write_int32(stream, 0)
+
+ dictionary = self.cab_header.dictionary
+
+ # Write number of entries in other sections:
+
+ for section in self.cab_header.sections:
+ if section is not self:
+ write_int16(stream, section.num_entries())
+
+ # Write offsets of other sections:
+
+ for section in self.cab_header.sections:
+ if section is not self:
+ offset = self.cab_header.get_section_offset(section)
+ write_int32(stream, offset)
+
+ # Special strings:
+
+ special_strings = (
+ self.app_name,
+ self.provider,
+ self.unsupported
+ )
+
+ dictionary_offset = self.cab_header.get_section_offset(dictionary)
+
+ for s in special_strings:
+ s_offset = dictionary.get_offset(s)
+ write_int16(stream, dictionary_offset + s_offset)
+ write_int16(stream, len(s) + 1)
+
+ # Two left-over fields of unknown use:
+
+ write_int16(stream, 0)
+ write_int16(stream, 0)
+
+class StringDictionary:
+ def __init__(self, cab_header):
+ self.cab_header = cab_header
+ self.string_list = []
+ self.strings = {}
+ self.length = 0
+ self.index = 1
+
+ # Get the length of the dictionary, in bytes.
+
+ def __len__(self):
+ return self.length
+
+ # Get the number of entries in the dictionary.
+
+ def num_entries(self):
+ return len(self.strings)
+
+ # Get the ID for the given string, adding it if necessary.
+
+ def get(self, s):
+ # Is this a new string? Add it to the dictionary.
+
+ if s not in self.strings:
+ offset = self.length
+ padded = pad_string(s)
+
+ self.strings[s] = (self.index, offset)
+ self.string_list.append((self.index, padded))
+ self.length += len(padded) + 4
+ self.index += 1
+
+ return self.strings[s][0]
+
+ # Get the offset of a particular string within the dictionary.
+
+ def get_offset(self, s):
+ return self.strings[s][1] + 4
+
+ # Write the dictionary to the output stream.
+
+ def write(self, stream):
+
+ # Write out all strings:
+
+ for i, s in self.string_list:
+ write_int16(stream, i)
+ write_int16(stream, len(s))
+ stream.write(s)
+
+class DirectoryList:
+ def __init__(self, cab_header):
+ self.cab_header = cab_header
+ self.directories_list = []
+ self.directories = {}
+ self.length = 0
+ self.index = 1
+
+ def __len__(self):
+ return self.length
+
+ def num_entries(self):
+ return len(self.directories_list)
+
+ # Find whether the specified directory exists in the list
+
+ def find(self, dir):
+ key = dir.lower()
+
+ if key in self.directories:
+ return self.directories[key]
+ else:
+ return None
+
+ # Get the ID for the given directory, adding it if necessary.
+
+ def get(self, dir):
+
+ key = dir.lower()
+ dictionary = self.cab_header.dictionary
+
+ # Add new directory?
+
+ if key not in self.directories:
+
+ # Separate into individual directories, and map to strings:
+
+ #dir_path = dir.split("\\")
+ #if dir_path[0] == "":
+ # dir_path = dir_path[1:]
+ dir_path = [ dir ]
+
+ dir_path = map(lambda x: dictionary.get(x), dir_path)
+
+ self.directories[key] = self.index
+ self.directories_list.append((self.index, dir_path))
+ self.length += 6 + 2 * len(dir_path)
+ self.index += 1
+
+ return self.directories[key]
+
+ # Write the directory list to the specified stream.
+
+ def write(self, stream):
+ for i, dir in self.directories_list:
+ write_int16(stream, i)
+ write_int16(stream, 2 * len(dir) + 2)
+
+ for subdir in dir:
+ write_int16(stream, subdir)
+
+ write_int16(stream, 0)
+
+class FileList:
+ def __init__(self, cab_header):
+ self.cab_header = cab_header
+ self.files = []
+ self.length = 0
+ self.index = 1
+
+ # Get the length of this section, in bytes.
+
+ def __len__(self):
+ return self.length
+
+ # Query whether the file list contains a particular file.
+
+ def find(self, filename):
+ dirname, sep, target_basename = filename.rpartition("\\")
+
+ target_basename = pad_string(target_basename)
+
+ target_dir_id = self.cab_header.directory_list.find(dirname)
+
+ if target_dir_id is None:
+ return None
+ else:
+ # Search the list of files:
+
+ for i, dir_id, basename, file_no, flags in self.files:
+ if dir_id == target_dir_id and basename == target_basename:
+ return file_no
+ else:
+ return None
+
+ # Get the number of entries in the file list
+
+ def num_entries(self):
+ return len(self.files)
+
+ # Add a file to the list.
+
+ def add(self, filename, file_no, flags=0):
+
+ dirname, sep, basename = filename.rpartition("\\")
+
+ dir_id = self.cab_header.directory_list.get(dirname)
+
+ padded = pad_string(basename)
+
+ self.files.append((self.index, dir_id, padded, file_no, flags))
+ self.length += 12 + len(padded)
+ self.index += 1
+
+ # Write this section to the output stream.
+
+ def write(self, stream):
+
+ for i, dir_id, filename, file_no, flags in self.files:
+ write_int16(stream, i)
+ write_int16(stream, dir_id)
+ write_int16(stream, file_no)
+ write_int32(stream, flags)
+ write_int16(stream, len(filename))
+ stream.write(filename)
+
+# TODO?
+
+class RegHiveList:
+ def __len__(self):
+ return 0
+
+ def num_entries(self):
+ return 0
+
+ def write(self, stream):
+ pass
+
+class RegKeyList():
+ def __len__(self):
+ return 0
+
+ def num_entries(self):
+ return 0
+
+ def write(self, stream):
+ pass
+
+class LinkList:
+ def __init__(self, cab_header):
+ self.cab_header = cab_header
+ self.links = []
+ self.length = 0
+ self.index = 1
+
+ def __len__(self):
+ return self.length
+
+ def num_entries(self):
+ return len(self.links)
+
+ # Determine the target type (dir/file) and ID:
+
+ def __find_target(self, target):
+ file_id = self.cab_header.file_list.find(target)
+
+ if file_id is not None:
+ return 1, file_id
+
+ dir_list = self.cab_header.get_section(DirectoryList)
+ dir_id = dir_list.find(target)
+
+ if dir_id is not None:
+ return 0, dir_id
+
+ raise Exception("Link target '%s' not found" % target)
+
+ def add(self, target, destination):
+
+ target_type, target_id = self.__find_target(target)
+
+ dest_path = destination.split("\\")
+
+ # Leading \:
+
+ if dest_path[0] == "":
+ dest_path = dest_path[1:]
+
+ # %CEn% to specify the install root is handled differently for
+ # links than it is for files/dirs.
+
+ match = re.match(r"\%CE(\d+)\%", dest_path[0])
+
+ if match:
+ base_dir = int(match.group(1))
+ dest_path = dest_path[1:]
+ else:
+ base_dir = 0
+
+ # Map dirs that make up the path to strings.
+
+ dictionary = self.cab_header.dictionary
+ dest_path = map(lambda x: dictionary.get(x), dest_path)
+
+ self.links.append((self.index, target_type, target_id,
+ base_dir, dest_path))
+ self.index += 1
+ self.length += 14 + 2 * len(dest_path)
+
+ def write(self, stream):
+
+ for i, target_type, target_id, base_dir, dest_path in self.links:
+
+ write_int16(stream, i)
+ write_int16(stream, 0)
+ write_int16(stream, base_dir)
+ write_int16(stream, target_id)
+ write_int16(stream, target_type)
+ write_int16(stream, 2 * len(dest_path) + 2)
+
+ for subdir in dest_path:
+ write_int16(stream, subdir)
+
+ write_int16(stream, 0)
+
+class CabHeaderFile:
+ def __init__(self):
+ self.dictionary = StringDictionary(self)
+ self.directory_list = DirectoryList(self)
+ self.file_list = FileList(self)
+
+ self.sections = [
+ HeaderSection(self),
+ self.dictionary,
+ self.directory_list,
+ self.file_list,
+ RegHiveList(),
+ RegKeyList(),
+ LinkList(self)
+ ]
+
+ def set_meta(self, *args):
+ header_section = self.get_section(HeaderSection)
+ header_section.set_meta(*args)
+
+ def add_file(self, filename, file_no, flags=0):
+ files_section = self.get_section(FileList)
+ files_section.add(filename, file_no, flags)
+
+ def add_link(self, target, destination):
+ links_section = self.get_section(LinkList)
+ links_section.add(target, destination)
+
+ def get_section(self, section_class):
+ for section in self.sections:
+ if isinstance(section, section_class):
+ return section
+ else:
+ raise Exception("Can't find section of class %s" % section_class)
+
+ def get_section_offset(self, section):
+ offset = 0
+
+ for s in self.sections:
+ if section is s:
+ return offset
+ offset += len(s)
+ else:
+ raise Exception("Section %s not found in list")
+
+ def __len__(self):
+ result = 0
+ for s in self.sections:
+ result += len(s)
+ return result
+
+ def write(self, stream):
+ old_pos = 0
+ for section in self.sections:
+ section.write(stream)
+ pos = stream.tell()
+ if pos != old_pos + len(section):
+ raise Exception("Section is %i bytes long, but %i written" % \
+ (len(section), pos - old_pos))
+ old_pos = pos
+
+class CabFile:
+ def __init__(self, config):
+ self.cab_header = CabHeaderFile()
+
+ self.__process_meta(config)
+ self.__process_files(config["files"])
+
+ if "links" in config:
+ self.__process_links(config["links"])
+
+ # Metadata:
+
+ def __process_meta(self, config):
+ arch = config.get("arch") or "strongarm"
+ app_name = config.get("app_name")
+ provider = config.get("provider")
+ unsupported = config.get("unsupported") or ""
+
+ if app_name is None or provider is None:
+ raise Exception("Application name and provider must be specified")
+
+ self.cab_header.set_meta(arch, app_name, provider, unsupported)
+ self.app_name = app_name
+
+ # Get the shortened 8.3 filename used for the specified file
+ # within the CAB.
+
+ def __shorten_name(self, filename, file_no):
+
+ # Strip down to base filename without extension:
+
+ basename = os.path.basename(filename)
+
+ if "." in basename:
+ basename = basename.rpartition(".")[0]
+
+ # Remove non-alphanumeric characters:
+
+ def only_alnum(x):
+ if x.isalnum():
+ return x
+ else:
+ return ""
+
+ cleaned_name = "".join(map(only_alnum, basename))
+ short_name = cleaned_name[0:8]
+
+ if len(short_name) < 8:
+ short_name = "0" * (8 - len(short_name)) + short_name
+
+ return "%s.%03i" % (short_name, file_no)
+
+ # Process the list of files to install:
+
+ def __process_files(self, files):
+ self.files = [ self.app_name ]
+
+ for filename, source_file in files.items():
+ file_no = len(self.files)
+ filename = expand_path(filename)
+ self.cab_header.add_file(filename, file_no)
+ self.files.append(source_file)
+
+ # Process the list of links:
+
+ def __process_links(self, links):
+ for destination, target in links.items():
+ target = expand_path(target)
+ destination = expand_path(destination)
+ self.cab_header.add_link(target, destination)
+
+ # Write the header file:
+
+ def __write_header(self, dir):
+
+ basename = self.__shorten_name(self.files[0], 0)
+ filename = os.path.join(dir, basename)
+
+ stream = file(filename, "w")
+ self.cab_header.write(stream)
+ stream.close()
+
+ return [ filename ]
+
+ # Write the files:
+
+ def __write_files(self, dir):
+
+ result = []
+
+ for file_no in range(1, len(self.files)):
+ source_file = self.files[file_no]
+ basename = self.__shorten_name(source_file, file_no)
+ filename = os.path.join(dir, basename)
+
+ shutil.copy(source_file, filename)
+ result.append(filename)
+
+ return result
+
+ # Output to a file:
+
+ def write(self, filename):
+
+ temp_dir = tempfile.mkdtemp()
+
+ header = self.__write_header(temp_dir)
+ files = self.__write_files(temp_dir)
+ files.reverse()
+
+ args = [ "lcab", "-n" ] + header + files + [ filename ]
+
+ os.spawnlp(os.P_WAIT, "lcab", *args)
+
+ # Clean up:
+
+ for tmpfile in header + files:
+ os.remove(tmpfile)
+ os.rmdir(temp_dir)
+
+def expand_path(filename):
+
+ # Replace Unix-style / path separators with DOS-style \
+
+ filename = filename.replace("/", "\\")
+
+ # Expand $(xyz) path variables to their Windows equivalents:
+
+ def replace_var(match):
+ var_name = match.group(1)
+
+ if not var_name in DIR_VARIABLES:
+ raise Exception("Unknown variable '%s'" % var_name)
+ else:
+ return DIR_VARIABLES[var_name]
+
+ return re.sub(r"\$\((.*?)\)", replace_var, filename)
+
+def read_config_file(filename):
+ f = file(filename)
+
+ data = f.readlines()
+ data = "".join(data)
+
+ f.close()
+
+ prog = compile(data, filename, "exec")
+ result = {}
+ eval(prog, result)
+
+ return result
+
+# List the files that the output CAB depends on.
+
+def print_dependencies(filename):
+ config = read_config_file(filename)
+
+ files_list = config["files"]
+
+ for dest, source_file in files_list.items():
+ print source_file
+
+if len(sys.argv) < 3:
+ print "Usage: %s <config file> <output file>" % sys.argv[0]
+ sys.exit(0)
+
+if sys.argv[1] == "-d":
+ print_dependencies(sys.argv[2])
+else:
+ config = read_config_file(sys.argv[1])
+
+ cab_file = CabFile(config)
+ cab_file.write(sys.argv[2])
+
--- a/src/i_system.c
+++ b/src/i_system.c
@@ -55,6 +55,8 @@
#include "w_wad.h"
#include "z_zone.h"
+#define MIN_RAM 4 /* MiB */
+
int mb_used = 16;
typedef struct atexit_listentry_s atexit_listentry_t;
@@ -86,8 +88,10 @@
{
}
-int I_GetHeapSize (void)
+byte *I_ZoneBase (int *size)
{
+ byte *zonemem;
+ int min_ram = MIN_RAM;
int p;
//!
@@ -97,28 +101,46 @@
//
p = M_CheckParm("-mb");
-
+
if (p > 0)
{
mb_used = atoi(myargv[p+1]);
+ min_ram = mb_used;
}
-
- return mb_used*1024*1024;
-}
-byte *I_ZoneBase (int *size)
-{
- byte *zonemem;
+ // Allocate the zone memory. This loop tries progressively smaller
+ // zone sizes until a size is found that can be allocated.
+ // If we used the -mb command line parameter, only the parameter
+ // provided is accepted.
- *size = I_GetHeapSize();
+ zonemem = NULL;
- zonemem = malloc(*size);
-
- if (zonemem == NULL)
+ while (zonemem == NULL)
{
- I_Error("Failed to allocate %i bytes for zone memory", *size);
+ // We need a reasonable minimum amount of RAM to start.
+
+ if (mb_used < min_ram)
+ {
+ I_Error("Unable to allocate %i MiB of RAM for zone", mb_used);
+ }
+
+ // Try to allocate the zone memory.
+
+ *size = mb_used * 1024 * 1024;
+
+ zonemem = malloc(*size);
+
+ // Failed to allocate? Reduce zone size until we reach a size
+ // that is acceptable. We decrease by 2 MiB at a time to ensure
+ // that there is 1-2 MiB still free on the system (my Windows
+ // Mobile PDA becomes unstable if very low on memory)
+
+ if (zonemem == NULL)
+ {
+ mb_used -= 2;
+ }
}
-
+
printf("zone memory: %p, %x allocated for zone\n",
zonemem, *size);
--- a/src/i_video.c
+++ b/src/i_video.c
@@ -662,13 +662,20 @@
event.data1 = TranslateKey(&sdlevent.key.keysym);
event.data2 = GetTypedChar(&sdlevent);
- D_PostEvent(&event);
+ if (event.data1 != 0)
+ {
+ D_PostEvent(&event);
+ }
break;
case SDL_KEYUP:
event.type = ev_keyup;
event.data1 = TranslateKey(&sdlevent.key.keysym);
- D_PostEvent(&event);
+
+ if (event.data1 != 0)
+ {
+ D_PostEvent(&event);
+ }
break;
/*
--- a/src/setup/execute.c
+++ b/src/setup/execute.c
@@ -29,11 +29,13 @@
#include <sys/types.h>
#if defined(_WIN32_WCE)
-
#include "libc_wince.h"
+#endif
-#elif defined(_WIN32)
+#ifdef _WIN32
+#define WIN32_LEAN_AND_MEAN
+#include <windows.h>
#include <process.h>
#else
@@ -66,7 +68,6 @@
char *tempdir;
#ifdef _WIN32
-
// Check the TEMP environment variable to find the location.
tempdir = getenv("TEMP");
@@ -134,28 +135,131 @@
fprintf(context->stream, "\n");
}
-#if defined(_WIN32_WCE)
+#if defined(_WIN32)
-static int ExecuteCommand(const char **argv)
+// Wait for the specified process to exit. Returns the exit code.
+
+static unsigned int WaitForProcessExit(HANDLE subprocess)
{
- // Windows CE version.
- // TODO
- return 0;
+ DWORD exit_code;
+
+ for (;;)
+ {
+ WaitForSingleObject(subprocess, INFINITE);
+
+ if (!GetExitCodeProcess(subprocess, &exit_code))
+ {
+ return -1;
+ }
+
+ if (exit_code != STILL_ACTIVE)
+ {
+ return exit_code;
+ }
+ }
}
-#elif defined(_WIN32)
+static wchar_t *GetFullExePath(const char *program)
+{
+ wchar_t *result;
+ unsigned int path_len;
+ char *sep;
-static int ExecuteCommand(const char **argv)
+ // Find the full path to the EXE to execute, by taking the path
+ // to this program and concatenating the EXE name:
+
+ sep = strrchr(myargv[0], DIR_SEPARATOR);
+
+ if (sep == NULL)
+ {
+ path_len = 0;
+ result = calloc(strlen(program) + 1, sizeof(wchar_t));
+ }
+ else
+ {
+ path_len = sep - myargv[0] + 1;
+
+ result = calloc(path_len + strlen(program) + 1,
+ sizeof(wchar_t));
+ MultiByteToWideChar(CP_OEMCP, 0,
+ myargv[0], path_len,
+ result, path_len);
+ }
+
+ MultiByteToWideChar(CP_OEMCP, 0,
+ program, strlen(program) + 1,
+ result + path_len, strlen(program) + 1);
+
+ return result;
+}
+
+// Convert command line argument to wchar_t string and add surrounding
+// "" quotes:
+
+static wchar_t *GetPaddedWideArg(const char *arg)
{
- return _spawnv(_P_WAIT, argv[0], argv);
+ wchar_t *result;
+ unsigned int len = strlen(arg);
+
+ // Convert the command line arg to a wide char string:
+
+ result = calloc(len + 3, sizeof(wchar_t));
+ MultiByteToWideChar(CP_OEMCP, 0,
+ arg, len + 1,
+ result + 1, len + 1);
+
+ // Surrounding quotes:
+
+ result[0] = '"';
+ result[len + 1] = '"';
+ result[len + 2] = 0;
+
+ return result;
}
+static int ExecuteCommand(const char *program, const char *arg)
+{
+ PROCESS_INFORMATION proc_info;
+ wchar_t *exe_path;
+ wchar_t *warg;
+ int result = 0;
+
+ exe_path = GetFullExePath(program);
+ warg = GetPaddedWideArg(arg);
+
+ // Invoke the program:
+
+ memset(&proc_info, 0, sizeof(proc_info));
+
+ if (!CreateProcessW(exe_path, warg,
+ NULL, NULL, FALSE, 0, NULL, NULL, NULL,
+ &proc_info))
+ {
+ result = -1;
+ }
+ else
+ {
+ // Wait for the process to finish, and save the exit code.
+
+ result = WaitForProcessExit(proc_info.hProcess);
+
+ CloseHandle(proc_info.hProcess);
+ CloseHandle(proc_info.hThread);
+ }
+
+ free(exe_path);
+ free(warg);
+
+ return result;
+}
+
#else
-static int ExecuteCommand(const char **argv)
+static int ExecuteCommand(const char *program, const char *arg)
{
pid_t childpid;
int result;
+ const char *argv[] = { program, arg, NULL };
childpid = fork();
@@ -189,7 +293,6 @@
int ExecuteDoom(execute_context_t *context)
{
- const char *argv[3];
char *response_file_arg;
int result;
@@ -200,17 +303,13 @@
response_file_arg = malloc(strlen(context->response_file) + 2);
sprintf(response_file_arg, "@%s", context->response_file);
- argv[0] = GetExecutableName();
- argv[1] = response_file_arg;
- argv[2] = NULL;
-
// Run Doom
- result = ExecuteCommand(argv);
+ result = ExecuteCommand(GetExecutableName(), response_file_arg);
free(response_file_arg);
-
- // Destroy context
+
+ // Destroy context
remove(context->response_file);
free(context->response_file);
free(context);
@@ -245,8 +344,8 @@
exec = NewExecuteContext();
AddCmdLineParameter(exec, "-testcontrols");
- AddCmdLineParameter(exec, "-config %s", main_cfg);
- AddCmdLineParameter(exec, "-extraconfig %s", extra_cfg);
+ AddCmdLineParameter(exec, "-config \"%s\"", main_cfg);
+ AddCmdLineParameter(exec, "-extraconfig \"%s\"", extra_cfg);
ExecuteDoom(exec);
TXT_CloseWindow(testwindow);