(Big tangle of changes that all happened as I was looking into the ROM

loader rewrite, which is still in progress....)

Replaced mamedriv.c with a new driver list mechanism that is generated
by the build tools. The emulator core now expects the presence of a
file called src/$(TARGET)/$(SUBTARGET).lst which is just a raw list of
driver names, one per line. C and C++ comments are still permitted.
This file is parsed by a new build tool makelist which extracts the
driver names, sorts them, and generates a file called drivlist.c, which
is consumed by the core. [Aaron Giles]

Added new osdcore function osd_malloc_array() which is identical to
osd_malloc() but obviously hints that the underlying allocation is for
an array. Updated all callers to use the appropriate form. Modified the
Windows allocator to only use guard pages for array-style allocations,
allowing us to enable them once again in debug builds. [Aaron Giles]

Created new static class driver_list to wrap accesses to the list of
available drivers. Improved speed of driver lookups by relying on the
presorting done by makelist. [Aaron Giles]

Created helper class driver_enumerator as a helper for iterating through 
the list of drivers. This class supports basic filtering and iteration,
and also serves as a temporary cache of machine_configs. [Aaron Giles]

Created cli_frontend object to wrap all the CLI handling code in
clifront.c. Updated/simplified all the code to take advantage of the
driver_enumerator. [Aaron Giles]

Created media_auditor object to wrap all the auditing functions in
audit.c. Updated all users to the new interface. Note that the new
auditing mechanism is slightly out of sync with the romload code in
terms of finding ROMs owned by devices, so it may mis-report some
issues until the new ROM loading code is in. [Aaron Giles]

Added concept of a per-device searchpath. For most devices, their 
searchpath is just the short name of the device. For driver_devices, the
searchpath is driver[;parent[;bios]]. This searchpath will eventually be
used by the rom loader to find ROMs. For now it is used by the media
auditor only. [Aaron Giles]

Created info_xml_creator object to wrap all the info generation functions
in info.c. Converted the file to C++ and cleaned up the input processing
code. [Aaron Giles]

(not for whatsnew ... Known issues: auditing of CHDs appears busted, and 
debug builds report unfreed memory if you use the built-in game picker)
This commit is contained in:
Aaron Giles 2011-04-13 20:31:00 +00:00
parent f99e1a5da6
commit 00d745ca77
67 changed files with 15978 additions and 16007 deletions

8
.gitattributes vendored
View File

@ -10,6 +10,7 @@ hash/softwarelist.dtd svneol=native#text/plain
src/build/build.mak svneol=native#text/plain src/build/build.mak svneol=native#text/plain
src/build/file2str.c svneol=native#text/plain src/build/file2str.c svneol=native#text/plain
src/build/makedep.c svneol=native#text/plain src/build/makedep.c svneol=native#text/plain
src/build/makelist.c svneol=native#text/plain
src/build/png2bdc.c svneol=native#text/plain src/build/png2bdc.c svneol=native#text/plain
src/build/verinfo.c svneol=native#text/plain src/build/verinfo.c svneol=native#text/plain
src/emu/addrmap.c svneol=native#text/plain src/emu/addrmap.c svneol=native#text/plain
@ -708,6 +709,7 @@ src/emu/layout/hoffff20.lay svneol=native#text/plain
src/emu/layout/horizont.lay svneol=native#text/plain src/emu/layout/horizont.lay svneol=native#text/plain
src/emu/layout/lcd.lay svneol=native#text/plain src/emu/layout/lcd.lay svneol=native#text/plain
src/emu/layout/lcd_rot.lay svneol=native#text/plain src/emu/layout/lcd_rot.lay svneol=native#text/plain
src/emu/layout/pinball.lay svneol=native#text/plain
src/emu/layout/snap.lay svneol=native#text/plain src/emu/layout/snap.lay svneol=native#text/plain
src/emu/layout/triphsxs.lay svneol=native#text/plain src/emu/layout/triphsxs.lay svneol=native#text/plain
src/emu/layout/vertical.lay svneol=native#text/plain src/emu/layout/vertical.lay svneol=native#text/plain
@ -3441,7 +3443,6 @@ src/mame/layout/pe_poker.lay svneol=native#text/plain
src/mame/layout/pe_schip.lay svneol=native#text/plain src/mame/layout/pe_schip.lay svneol=native#text/plain
src/mame/layout/pe_slots.lay svneol=native#text/plain src/mame/layout/pe_slots.lay svneol=native#text/plain
src/mame/layout/peplus.lay svneol=native#text/plain src/mame/layout/peplus.lay svneol=native#text/plain
src/mame/layout/pinball.lay svneol=native#text/plain
src/mame/layout/pirpok2.lay svneol=native#text/plain src/mame/layout/pirpok2.lay svneol=native#text/plain
src/mame/layout/pmpoker.lay svneol=native#text/plain src/mame/layout/pmpoker.lay svneol=native#text/plain
src/mame/layout/pmroulet.lay -text svneol=native#plain/text src/mame/layout/pmroulet.lay -text svneol=native#plain/text
@ -3721,9 +3722,9 @@ src/mame/machine/znsec.c svneol=native#text/plain
src/mame/machine/znsec.h svneol=native#text/plain src/mame/machine/znsec.h svneol=native#text/plain
src/mame/machine/zs01.c svneol=native#text/plain src/mame/machine/zs01.c svneol=native#text/plain
src/mame/machine/zs01.h svneol=native#text/plain src/mame/machine/zs01.h svneol=native#text/plain
src/mame/mame.lst svneol=native#text/plain
src/mame/mame.mak svneol=native#text/plain src/mame/mame.mak svneol=native#text/plain
src/mame/mamedriv.c svneol=native#text/plain src/mame/tiny.lst svneol=native#text/plain
src/mame/tiny.c svneol=native#text/plain
src/mame/tiny.mak svneol=native#text/plain src/mame/tiny.mak svneol=native#text/plain
src/mame/video/1942.c svneol=native#text/plain src/mame/video/1942.c svneol=native#text/plain
src/mame/video/1943.c svneol=native#text/plain src/mame/video/1943.c svneol=native#text/plain
@ -4607,7 +4608,6 @@ src/osd/windows/strconv.h svneol=native#text/plain
src/osd/windows/vconv.c svneol=native#text/plain src/osd/windows/vconv.c svneol=native#text/plain
src/osd/windows/video.c svneol=native#text/plain src/osd/windows/video.c svneol=native#text/plain
src/osd/windows/video.h svneol=native#text/plain src/osd/windows/video.h svneol=native#text/plain
src/osd/windows/winalloc.c svneol=native#text/plain
src/osd/windows/winclip.c svneol=native#text/plain src/osd/windows/winclip.c svneol=native#text/plain
src/osd/windows/windir.c svneol=native#text/plain src/osd/windows/windir.c svneol=native#text/plain
src/osd/windows/window.c svneol=native#text/plain src/osd/windows/window.c svneol=native#text/plain

View File

@ -577,6 +577,8 @@ LIBOCORE = $(OBJ)/libocore.a
LIBOSD = $(OBJ)/libosd.a LIBOSD = $(OBJ)/libosd.a
VERSIONOBJ = $(OBJ)/version.o VERSIONOBJ = $(OBJ)/version.o
DRIVLISTSRC = $(OBJ)/drivlist.c
DRIVLISTOBJ = $(OBJ)/drivlist.o
@ -722,7 +724,7 @@ ifndef EXECUTABLE_DEFINED
# always recompile the version string # always recompile the version string
$(VERSIONOBJ): $(DRVLIBS) $(LIBOSD) $(LIBCPU) $(LIBEMU) $(LIBSOUND) $(LIBUTIL) $(EXPAT) $(ZLIB) $(SOFTFLOAT) $(LIBOCORE) $(RESFILE) $(VERSIONOBJ): $(DRVLIBS) $(LIBOSD) $(LIBCPU) $(LIBEMU) $(LIBSOUND) $(LIBUTIL) $(EXPAT) $(ZLIB) $(SOFTFLOAT) $(LIBOCORE) $(RESFILE)
$(EMULATOR): $(VERSIONOBJ) $(DRVLIBS) $(LIBOSD) $(LIBCPU) $(LIBEMU) $(LIBDASM) $(LIBSOUND) $(LIBUTIL) $(EXPAT) $(SOFTFLOAT) $(ZLIB) $(LIBOCORE) $(RESFILE) $(EMULATOR): $(VERSIONOBJ) $(DRIVLISTOBJ) $(DRVLIBS) $(LIBOSD) $(LIBCPU) $(LIBEMU) $(LIBDASM) $(LIBSOUND) $(LIBUTIL) $(EXPAT) $(SOFTFLOAT) $(ZLIB) $(LIBOCORE) $(RESFILE)
@echo Linking $@... @echo Linking $@...
$(LD) $(LDFLAGS) $(LDFLAGSEMULATOR) $^ $(LIBS) -o $@ $(LD) $(LDFLAGS) $(LDFLAGSEMULATOR) $^ $(LIBS) -o $@
ifeq ($(TARGETOS),win32) ifeq ($(TARGETOS),win32)
@ -760,6 +762,14 @@ $(OBJ)/%.fh: $(SRC)/%.png $(PNG2BDC_TARGET) $(FILE2STR_TARGET)
@$(PNG2BDC) $< $(OBJ)/temp.bdc @$(PNG2BDC) $< $(OBJ)/temp.bdc
@$(FILE2STR) $(OBJ)/temp.bdc $@ font_$(basename $(notdir $<)) UINT8 @$(FILE2STR) $(OBJ)/temp.bdc $@ font_$(basename $(notdir $<)) UINT8
$(DRIVLISTOBJ): $(DRIVLISTSRC)
@echo Compiling $<...
$(CC) $(CDEFS) $(CFLAGS) -c $< -o $@
$(DRIVLISTSRC): $(SRC)/$(TARGET)/$(SUBTARGET).lst $(MAKELIST_TARGET)
@echo Building driver list $<...
@$(MAKELIST) $< >$@
$(OBJ)/%.a: $(OBJ)/%.a:
@echo Archiving $@... @echo Archiving $@...
$(RM) $@ $(RM) $@

View File

@ -20,17 +20,20 @@ OBJDIRS += \
FILE2STR_TARGET = $(BUILDOUT)/file2str$(BUILD_EXE) FILE2STR_TARGET = $(BUILDOUT)/file2str$(BUILD_EXE)
MAKEDEP_TARGET = $(BUILDOUT)/makedep$(BUILD_EXE) MAKEDEP_TARGET = $(BUILDOUT)/makedep$(BUILD_EXE)
MAKELIST_TARGET = $(BUILDOUT)/makelist$(BUILD_EXE)
PNG2BDC_TARGET = $(BUILDOUT)/png2bdc$(BUILD_EXE) PNG2BDC_TARGET = $(BUILDOUT)/png2bdc$(BUILD_EXE)
VERINFO_TARGET = $(BUILDOUT)/verinfo$(BUILD_EXE) VERINFO_TARGET = $(BUILDOUT)/verinfo$(BUILD_EXE)
ifeq ($(TARGETOS),win32) ifeq ($(TARGETOS),win32)
FILE2STR = $(subst /,\,$(FILE2STR_TARGET)) FILE2STR = $(subst /,\,$(FILE2STR_TARGET))
MAKEDEP = $(subst /,\,$(MAKEDEP_TARGET)) MAKEDEP = $(subst /,\,$(MAKEDEP_TARGET))
MAKELIST = $(subst /,\,$(MAKELIST_TARGET))
PNG2BDC = $(subst /,\,$(PNG2BDC_TARGET)) PNG2BDC = $(subst /,\,$(PNG2BDC_TARGET))
VERINFO = $(subst /,\,$(VERINFO_TARGET)) VERINFO = $(subst /,\,$(VERINFO_TARGET))
else else
FILE2STR = $(FILE2STR_TARGET) FILE2STR = $(FILE2STR_TARGET)
MAKEDEP = $(MAKEDEP_TARGET) MAKEDEP = $(MAKEDEP_TARGET)
MAKELIST = $(MAKELIST_TARGET)
PNG2BDC = $(PNG2BDC_TARGET) PNG2BDC = $(PNG2BDC_TARGET)
VERINFO = $(VERINFO_TARGET) VERINFO = $(VERINFO_TARGET)
endif endif
@ -39,6 +42,7 @@ ifneq ($(CROSS_BUILD),1)
BUILD += \ BUILD += \
$(FILE2STR_TARGET) \ $(FILE2STR_TARGET) \
$(MAKEDEP_TARGET) \ $(MAKEDEP_TARGET) \
$(MAKELIST_TARGET) \
$(PNG2BDC_TARGET) \ $(PNG2BDC_TARGET) \
$(VERINFO_TARGET) \ $(VERINFO_TARGET) \
@ -70,6 +74,19 @@ $(MAKEDEP_TARGET): $(MAKEDEPOBJS) $(LIBUTIL) $(LIBOCORE) $(ZLIB)
#-------------------------------------------------
# makelist
#-------------------------------------------------
MAKELISTOBJS = \
$(BUILDOBJ)/makelist.o \
$(MAKELIST_TARGET): $(MAKELISTOBJS) $(LIBUTIL) $(LIBOCORE) $(ZLIB)
@echo Linking $@...
$(LD) $(LDFLAGS) $^ $(LIBS) -o $@
#------------------------------------------------- #-------------------------------------------------
# png2bdc # png2bdc
#------------------------------------------------- #-------------------------------------------------

203
src/build/makelist.c Normal file
View File

@ -0,0 +1,203 @@
/***************************************************************************
makelist.c
Create and sort the driver list.
****************************************************************************
Copyright Aaron Giles
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are
met:
* Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in
the documentation and/or other materials provided with the
distribution.
* Neither the name 'MAME' nor the names of its contributors may be
used to endorse or promote products derived from this software
without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY AARON GILES ''AS IS'' AND ANY EXPRESS OR
IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL AARON GILES BE LIABLE FOR ANY DIRECT,
INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
POSSIBILITY OF SUCH DAMAGE.
***************************************************************************/
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
#include "corefile.h"
#define MAX_DRIVERS 65536
static const char *drivlist[MAX_DRIVERS];
//-------------------------------------------------
// driver_sort_callback - compare two items in
// a string array
//-------------------------------------------------
int sort_callback(const void *elem1, const void *elem2)
{
const char **item1 = (const char **)elem1;
const char **item2 = (const char **)elem2;
return strcmp(*item1, *item2);
}
//-------------------------------------------------
// main - primary entry point
//-------------------------------------------------
int main(int argc, char *argv[])
{
// needs at least 1 argument
if (argc < 2)
{
fprintf(stderr,
"Usage:\n"
" makelist <source.lst>\n"
);
return 0;
}
// extract arguments
const char *srcfile = argv[1];
// read source file
void *buffer;
UINT32 length;
file_error filerr = core_fload(srcfile, &buffer, &length);
if (filerr != FILERR_NONE)
{
fprintf(stderr, "Unable to read source file '%s'\n", srcfile);
return 1;
}
// rip through it to find all drivers
int drivcount = 0;
char *srcptr = (char *)buffer;
char *endptr = srcptr + length;
int linenum = 1;
bool in_comment = false;
while (srcptr < endptr)
{
char c = *srcptr++;
// count newlines
if (c == 13 || c == 10)
{
if (c == 13 && *srcptr == 10)
srcptr++;
linenum++;
continue;
}
// skip any spaces
if (isspace(c))
continue;
// look for end of C comment
if (in_comment && c == '*' && *srcptr == '/')
{
srcptr++;
in_comment = false;
continue;
}
// skip anything else inside a C comment
if (in_comment)
continue;
// look for start of C comment
if (c == '/' && *srcptr == '*')
{
srcptr++;
in_comment = true;
continue;
}
// if we hit a C++ comment, scan to the end of line
if (c == '/' && *srcptr == '/')
{
while (srcptr < endptr && *srcptr != 13 && *srcptr != 10)
srcptr++;
continue;
}
// extract the driver name
char drivname[32];
drivname[0] = 0;
srcptr--;
for (int pos = 0; srcptr < endptr && pos < ARRAY_LENGTH(drivname) - 1 && !isspace(*srcptr); pos++)
{
drivname[pos] = *srcptr++;
drivname[pos+1] = 0;
}
// verify the name as valid
for (char *drivch = drivname; *drivch != 0; drivch++)
{
if ((*drivch >= 'a' && *drivch <= 'z') || (*drivch >= '0' && *drivch <= '9') || *drivch == '_')
continue;
fprintf(stderr, "%s:%d - Invalid character '%c' in driver \"%s\"\n", srcfile, linenum, *drivch, drivname);
return 1;
}
// add it to the list
char *name = (char *)malloc(strlen(drivname) + 1);
strcpy(name, drivname);
drivlist[drivcount++] = name;
}
// add a reference to the ___empty driver
drivlist[drivcount++] = "___empty";
// output a count
if (drivcount == 0)
{
fprintf(stderr, "No drivers found\n");
return 1;
}
fprintf(stderr, "%d drivers found\n", drivcount);
// sort the list
qsort(drivlist, drivcount, sizeof(*drivlist), sort_callback);
// start with a header
printf("#include \"emu.h\"\n\n");
// output the list of externs first
for (int index = 0; index < drivcount; index++)
printf("GAME_EXTERN(%s);\n", drivlist[index]);
printf("\n");
// then output the array
printf("const game_driver * const driver_list::s_drivers_sorted[%d] =\n", drivcount);
printf("{\n");
for (int index = 0; index < drivcount; index++)
printf("\t&GAME_NAME(%s)%s\n", drivlist[index], (index == drivcount - 1) ? "" : ",");
printf("};\n");
printf("\n");
// also output a global count
printf("int driver_list::s_driver_count = %d;\n", drivcount);
return 0;
}

View File

@ -4,8 +4,36 @@
ROM set auditing functions. ROM set auditing functions.
Copyright Nicola Salmoria and the MAME Team. ****************************************************************************
Visit http://mamedev.org for licensing and usage restrictions.
Copyright Aaron Giles
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are
met:
* Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in
the documentation and/or other materials provided with the
distribution.
* Neither the name 'MAME' nor the names of its contributors may be
used to endorse or promote products derived from this software
without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY AARON GILES ''AS IS'' AND ANY EXPRESS OR
IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL AARON GILES BE LIABLE FOR ANY DIRECT,
INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
POSSIBILITY OF SUCH DAMAGE.
***************************************************************************/ ***************************************************************************/
@ -17,510 +45,419 @@
#include "sound/samples.h" #include "sound/samples.h"
//**************************************************************************
// CORE FUNCTIONS
//**************************************************************************
/*************************************************************************** //-------------------------------------------------
FUNCTION PROTOTYPES // media_auditor - constructor
***************************************************************************/ //-------------------------------------------------
static void audit_one_rom(emu_options &options, const rom_entry *rom, const char *regiontag, const game_driver *gamedrv, const char *validation, audit_record *record); media_auditor::media_auditor(const driver_enumerator &enumerator)
static void audit_one_disk(emu_options &options, const rom_entry *rom, const game_driver *gamedrv, const char *validation, audit_record *record); : m_enumerator(enumerator),
static int rom_used_by_parent(emu_options &options, const game_driver *gamedrv, const hash_collection &romhashes, const game_driver **parent); m_validation(AUDIT_VALIDATE_FULL),
m_searchpath(NULL)
/***************************************************************************
INLINE FUNCTIONS
***************************************************************************/
/*-------------------------------------------------
set_status - shortcut for setting status and
substatus values
-------------------------------------------------*/
INLINE void set_status(audit_record *record, UINT8 status, UINT8 substatus)
{ {
record->status = status;
record->substatus = substatus;
} }
//-------------------------------------------------
// audit_media - audit the media described by the
// currently-enumerated driver
//-------------------------------------------------
/*************************************************************************** media_auditor::summary media_auditor::audit_media(const char *validation)
CORE FUNCTIONS
***************************************************************************/
/*-------------------------------------------------
audit_images - validate the ROM and disk
images for a game
-------------------------------------------------*/
int audit_images(emu_options &options, const game_driver *gamedrv, const char *validation, audit_record **audit)
{ {
machine_config config(*gamedrv, options); // start fresh
const rom_entry *region, *rom; m_record_list.reset();
const rom_source *source;
audit_record *record;
int anyfound = FALSE;
int anyrequired = FALSE;
int allshared = TRUE;
int records;
/* determine the number of records we will generate */ // store validation for later
records = 0; m_validation = validation;
bool source_is_gamedrv = true;
for (source = rom_first_source(config); source != NULL; source = rom_next_source(*source)) // iterate over ROM sources and regions
bool anyfound = false;
bool anyrequired = false;
for (const rom_source *source = rom_first_source(m_enumerator.config()); source != NULL; source = rom_next_source(*source))
{ {
for (region = rom_first_region(*source); region != NULL; region = rom_next_region(region)) // determine the search path for this source and iterate through the regions
for (rom = rom_first_file(region); rom != NULL; rom = rom_next_file(rom)) m_searchpath = source->searchpath();
if (ROMREGION_ISROMDATA(region) || ROMREGION_ISDISKDATA(region))
{ // also determine if this is the driver's specific ROMs or not
if (source_is_gamedrv && !ROM_ISOPTIONAL(rom)) bool source_is_gamedrv = (dynamic_cast<const driver_device_config_base *>(source) != NULL);
{
hash_collection hashes(ROM_GETHASHDATA(rom)); // now iterate over regions and ROMs within
if (!hashes.flag(hash_collection::FLAG_NO_DUMP)) for (const rom_entry *region = rom_first_region(*source); region != NULL; region = rom_next_region(region))
{ for (const rom_entry *rom = rom_first_file(region); rom; rom = rom_next_file(rom))
anyrequired = TRUE; {
if (allshared && !rom_used_by_parent(options, gamedrv, hashes, NULL)) hash_collection hashes(ROM_GETHASHDATA(rom));
allshared = FALSE;
}
}
records++;
}
source_is_gamedrv = false; // if a dump exists, then at least one entry is required
if (!hashes.flag(hash_collection::FLAG_NO_DUMP))
anyrequired = true;
// audit a file
audit_record *record = NULL;
if (ROMREGION_ISROMDATA(region))
record = audit_one_rom(rom);
// audit a disk
else if (ROMREGION_ISDISKDATA(region))
record = audit_one_disk(rom);
// skip if no record
if (record == NULL)
continue;
// if we got a record back,
if (record->status() != audit_record::STATUS_NOT_FOUND && source_is_gamedrv && also_used_by_parent(hashes) == -1)
anyfound = true;
}
} }
if (records > 0) // if we found nothing, we don't have the set at all
{ if (!anyfound && anyrequired)
/* allocate memory for the records */ m_record_list.reset();
*audit = global_alloc_array_clear(audit_record, records);
record = *audit; // return a summary
return summarize();
}
/* iterate over ROM sources and regions */
bool source_is_gamedrv = true; //-------------------------------------------------
for (source = rom_first_source(config); source != NULL; source = rom_next_source(*source)) // audit_samples - validate the samples for the
// currently-enumerated driver
//-------------------------------------------------
media_auditor::summary media_auditor::audit_samples()
{
// start fresh
m_record_list.reset();
// iterate over sample entries
for (const device_config *devconfig = m_enumerator.config().first_device(); devconfig != NULL; devconfig = devconfig->next())
if (devconfig->type() == SAMPLES)
{ {
for (region = rom_first_region(*source); region != NULL; region = rom_next_region(region)) const samples_interface *intf = reinterpret_cast<const samples_interface *>(devconfig->static_config());
if (intf->samplenames != NULL)
{ {
const char *regiontag = ROMREGION_ISLOADBYNAME(region) ? ROM_GETNAME(region) : NULL; // by default we just search using the driver name
for (rom = rom_first_file(region); rom; rom = rom_next_file(rom)) astring searchpath(m_enumerator.driver().name);
// iterate over samples in this entry
for (int sampnum = 0; intf->samplenames[sampnum] != NULL; sampnum++)
{ {
/* audit a file */ // starred entries indicate an additional searchpath
if (ROMREGION_ISROMDATA(region)) if (intf->samplenames[sampnum][0] == '*')
{
audit_one_rom(options, rom, regiontag, gamedrv, validation, record);
}
/* audit a disk */
else if (ROMREGION_ISDISKDATA(region))
{
audit_one_disk(options, rom, gamedrv, validation, record);
}
else
{ {
searchpath.cat(";").cat(&intf->samplenames[sampnum][1]);
continue; continue;
} }
if (source_is_gamedrv && record->status != AUDIT_STATUS_NOT_FOUND && (allshared || !rom_used_by_parent(options, gamedrv, record->exphashes, NULL))) // create a new record
anyfound = TRUE; audit_record &record = m_record_list.append(*global_alloc(audit_record(intf->samplenames[sampnum], audit_record::MEDIA_SAMPLE)));
record++; // look for the files
emu_file file(m_enumerator.options().sample_path(), OPEN_FLAG_READ | OPEN_FLAG_NO_PRELOAD);
path_iterator path(searchpath);
astring curpath;
while (path.next(curpath, intf->samplenames[sampnum]))
{
// attempt to access the file
file_error filerr = file.open(curpath);
if (filerr == FILERR_NONE)
record.set_status(audit_record::STATUS_GOOD, audit_record::SUBSTATUS_GOOD);
else
record.set_status(audit_record::STATUS_NOT_FOUND, audit_record::SUBSTATUS_NOT_FOUND);
}
} }
} }
source_is_gamedrv = false;
} }
}
// return a summary
/* if we found nothing, we don't have the set at all */ return summarize();
if (!anyfound && anyrequired)
{
global_free(*audit);
*audit = NULL;
records = 0;
}
return records;
} }
/*------------------------------------------------- //-------------------------------------------------
audit_samples - validate the samples for a // summary - generate a summary, with an optional
game // string format
-------------------------------------------------*/ //-------------------------------------------------
int audit_samples(emu_options &options, const game_driver *gamedrv, audit_record **audit) media_auditor::summary media_auditor::summarize(astring *string)
{ {
machine_config config(*gamedrv, options); // no count AND no records means not found
audit_record *record; if (m_record_list.count() == 0)
int records = 0;
int sampnum;
/* count the number of sample records attached to this driver */
const device_config_sound_interface *sound = NULL;
for (bool gotone = config.m_devicelist.first(sound); gotone; gotone = sound->next(sound))
if (sound->devconfig().type() == SAMPLES)
{
const samples_interface *intf = (const samples_interface *)sound->devconfig().static_config();
if (intf->samplenames != NULL)
{
/* iterate over samples in this entry */
for (sampnum = 0; intf->samplenames[sampnum] != NULL; sampnum++)
if (intf->samplenames[sampnum][0] != '*')
records++;
}
}
/* if no records, just quit now */
if (records == 0)
goto skip;
/* allocate memory for the records */
*audit = global_alloc_array_clear(audit_record, records);
record = *audit;
/* now iterate over sample entries */
for (bool gotone = config.m_devicelist.first(sound); gotone; gotone = sound->next(sound))
if (sound->devconfig().type() == SAMPLES)
{
const samples_interface *intf = (const samples_interface *)sound->devconfig().static_config();
const char *sharedname = NULL;
if (intf->samplenames != NULL)
{
/* iterate over samples in this entry */
for (sampnum = 0; intf->samplenames[sampnum] != NULL; sampnum++)
if (intf->samplenames[sampnum][0] == '*')
sharedname = &intf->samplenames[sampnum][1];
else
{
/* attempt to access the file from the game driver name */
emu_file file(options.sample_path(), OPEN_FLAG_READ | OPEN_FLAG_NO_PRELOAD);
file_error filerr = file.open(gamedrv->name, PATH_SEPARATOR, intf->samplenames[sampnum]);
/* attempt to access the file from the shared driver name */
if (filerr != FILERR_NONE && sharedname != NULL)
filerr = file.open(sharedname, PATH_SEPARATOR, intf->samplenames[sampnum]);
/* fill in the record */
record->type = AUDIT_FILE_SAMPLE;
record->name = intf->samplenames[sampnum];
if (filerr == FILERR_NONE)
set_status(record++, AUDIT_STATUS_GOOD, SUBSTATUS_GOOD);
else
set_status(record++, AUDIT_STATUS_NOT_FOUND, SUBSTATUS_NOT_FOUND);
}
}
}
skip:
return records;
}
/*-------------------------------------------------
audit_summary - output a summary given a
list of audit records
-------------------------------------------------*/
int audit_summary(const game_driver *gamedrv, int count, const audit_record *records, int output)
{
int overall_status = CORRECT;
int recnum;
/* no count AND no records means not found */
if (count == 0 && records == NULL)
return NOTFOUND; return NOTFOUND;
/* loop over records */ // loop over records
for (recnum = 0; recnum < count; recnum++) summary overall_status = CORRECT;
for (audit_record *record = m_record_list.first(); record != NULL; record = record->next())
{ {
const audit_record *record = &records[recnum]; summary best_new_status = INCORRECT;
int best_new_status = INCORRECT;
/* skip anything that's fine */ // skip anything that's fine
if (record->substatus == SUBSTATUS_GOOD) if (record->substatus() == audit_record::SUBSTATUS_GOOD)
continue; continue;
/* output the game name, file name, and length (if applicable) */ // output the game name, file name, and length (if applicable)
if (output) if (string != NULL)
{ {
mame_printf_info("%-8s: %s", gamedrv->name, record->name); string->catprintf("%-12s: %s", m_enumerator.driver().name, record->name());
if (record->explength > 0) if (record->expected_length() > 0)
mame_printf_info(" (%d bytes)", record->explength); string->catprintf(" (%d bytes)", record->expected_length());
mame_printf_info(" - "); string->catprintf(" - ");
} }
/* use the substatus for finer details */ // use the substatus for finer details
switch (record->substatus) switch (record->substatus())
{ {
case SUBSTATUS_GOOD_NEEDS_REDUMP: case audit_record::SUBSTATUS_GOOD_NEEDS_REDUMP:
if (output) mame_printf_info("NEEDS REDUMP\n"); if (string != NULL) string->catprintf("NEEDS REDUMP\n");
best_new_status = BEST_AVAILABLE; best_new_status = BEST_AVAILABLE;
break; break;
case SUBSTATUS_FOUND_NODUMP: case audit_record::SUBSTATUS_FOUND_NODUMP:
if (output) mame_printf_info("NO GOOD DUMP KNOWN\n"); if (string != NULL) string->catprintf("NO GOOD DUMP KNOWN\n");
best_new_status = BEST_AVAILABLE; best_new_status = BEST_AVAILABLE;
break; break;
case SUBSTATUS_FOUND_BAD_CHECKSUM: case audit_record::SUBSTATUS_FOUND_BAD_CHECKSUM:
if (output) if (string != NULL)
{ {
astring tempstr; astring tempstr;
mame_printf_info("INCORRECT CHECKSUM:\n"); string->catprintf("INCORRECT CHECKSUM:\n");
mame_printf_info("EXPECTED: %s\n", record->exphashes.macro_string(tempstr)); string->catprintf("EXPECTED: %s\n", record->expected_hashes().macro_string(tempstr));
mame_printf_info(" FOUND: %s\n", record->hashes.macro_string(tempstr)); string->catprintf(" FOUND: %s\n", record->actual_hashes().macro_string(tempstr));
} }
break; break;
case SUBSTATUS_FOUND_WRONG_LENGTH: case audit_record::SUBSTATUS_FOUND_WRONG_LENGTH:
if (output) mame_printf_info("INCORRECT LENGTH: %d bytes\n", record->length); if (string != NULL) string->catprintf("INCORRECT LENGTH: %d bytes\n", record->actual_length());
break; break;
case SUBSTATUS_NOT_FOUND: case audit_record::SUBSTATUS_NOT_FOUND:
if (output) mame_printf_info("NOT FOUND\n"); if (string != NULL) string->catprintf("NOT FOUND\n");
break; break;
case SUBSTATUS_NOT_FOUND_NODUMP: case audit_record::SUBSTATUS_NOT_FOUND_NODUMP:
if (output) mame_printf_info("NOT FOUND - NO GOOD DUMP KNOWN\n"); if (string != NULL) string->catprintf("NOT FOUND - NO GOOD DUMP KNOWN\n");
best_new_status = BEST_AVAILABLE; best_new_status = BEST_AVAILABLE;
break; break;
case SUBSTATUS_NOT_FOUND_OPTIONAL: case audit_record::SUBSTATUS_NOT_FOUND_OPTIONAL:
if (output) mame_printf_info("NOT FOUND BUT OPTIONAL\n"); if (string != NULL) string->catprintf("NOT FOUND BUT OPTIONAL\n");
best_new_status = BEST_AVAILABLE; best_new_status = BEST_AVAILABLE;
break; break;
case SUBSTATUS_NOT_FOUND_PARENT: case audit_record::SUBSTATUS_NOT_FOUND_PARENT:
if (output) mame_printf_info("NOT FOUND (shared with parent)\n"); if (string != NULL) string->catprintf("NOT FOUND (shared with parent)\n");
break; break;
case SUBSTATUS_NOT_FOUND_BIOS: case audit_record::SUBSTATUS_NOT_FOUND_BIOS:
if (output) mame_printf_info("NOT FOUND (BIOS)\n"); if (string != NULL) string->catprintf("NOT FOUND (BIOS)\n");
break; break;
default:
assert(false);
} }
/* downgrade the overall status if necessary */ // downgrade the overall status if necessary
overall_status = MAX(overall_status, best_new_status); overall_status = MAX(overall_status, best_new_status);
} }
return overall_status; return overall_status;
} }
//-------------------------------------------------
// audit_one_rom - validate a single ROM entry
//-------------------------------------------------
/*************************************************************************** audit_record *media_auditor::audit_one_rom(const rom_entry *rom)
UTILITIES
***************************************************************************/
/*-------------------------------------------------
audit_one_rom - validate a single ROM entry
-------------------------------------------------*/
static void audit_one_rom(emu_options &options, const rom_entry *rom, const char *regiontag, const game_driver *gamedrv, const char *validation, audit_record *record)
{ {
const game_driver *drv; // allocate and append a new record
audit_record &record = m_record_list.append(*global_alloc(audit_record(*rom, audit_record::MEDIA_ROM)));
// see if we have a CRC and extract it if so
UINT32 crc = 0; UINT32 crc = 0;
bool has_crc = record.expected_hashes().crc(crc);
/* fill in the record basics */ // find the file and checksum it, getting the file length along the way
record->type = AUDIT_FILE_ROM; emu_file file(m_enumerator.options().media_path(), OPEN_FLAG_READ | OPEN_FLAG_NO_PRELOAD);
record->name = ROM_GETNAME(rom); path_iterator path(m_searchpath);
record->exphashes.from_internal_string(ROM_GETHASHDATA(rom)); astring curpath;
record->length = 0; while (path.next(curpath, record.name()))
record->explength = rom_file_size(rom);
/* see if we have a CRC and extract it if so */
bool has_crc = record->exphashes.crc(crc);
/* find the file and checksum it, getting the file length along the way */
for (drv = gamedrv; drv != NULL; drv = driver_get_clone(drv))
{ {
emu_file file(options.media_path(), OPEN_FLAG_READ | OPEN_FLAG_NO_PRELOAD); // open the file if we can
/* open the file if we can */
file_error filerr; file_error filerr;
if (has_crc) if (has_crc)
filerr = file.open(drv->name, PATH_SEPARATOR, ROM_GETNAME(rom), crc); filerr = file.open(curpath, crc);
else else
filerr = file.open(drv->name, PATH_SEPARATOR, ROM_GETNAME(rom)); filerr = file.open(curpath);
// if it worked, get the actual length and hashes, then stop
if (filerr == FILERR_NONE) if (filerr == FILERR_NONE)
{ {
record->hashes = file.hashes(validation); record.set_actual(file.hashes(m_validation), file.size());
record->length = (UINT32)file.size();
break; break;
} }
} }
/* if not found, check the region as a backup */ // compute the final status
if (record->length == 0 && regiontag != NULL) compute_status(record, rom, record.actual_length() != 0);
{ return &record;
emu_file file(options.media_path(), OPEN_FLAG_READ | OPEN_FLAG_NO_PRELOAD);
/* open the file if we can */
file_error filerr;
if (has_crc)
filerr = file.open(regiontag, PATH_SEPARATOR, ROM_GETNAME(rom), crc);
else
filerr = file.open(regiontag, PATH_SEPARATOR, ROM_GETNAME(rom));
if (filerr == FILERR_NONE)
{
record->hashes = file.hashes(validation);
record->length = (UINT32)file.size();
}
}
/* if we failed to find the file, set the appropriate status */
if (record->length == 0)
{
const game_driver *parent;
/* no good dump */
if (record->exphashes.flag(hash_collection::FLAG_NO_DUMP))
set_status(record, AUDIT_STATUS_NOT_FOUND, SUBSTATUS_NOT_FOUND_NODUMP);
/* optional ROM */
else if (ROM_ISOPTIONAL(rom))
set_status(record, AUDIT_STATUS_NOT_FOUND, SUBSTATUS_NOT_FOUND_OPTIONAL);
/* not found and used by parent */
else if (rom_used_by_parent(options, gamedrv, record->exphashes, &parent))
set_status(record, AUDIT_STATUS_NOT_FOUND, (parent->flags & GAME_IS_BIOS_ROOT) ? SUBSTATUS_NOT_FOUND_BIOS : SUBSTATUS_NOT_FOUND_PARENT);
/* just plain old not found */
else
set_status(record, AUDIT_STATUS_NOT_FOUND, SUBSTATUS_NOT_FOUND);
}
/* if we did find the file, do additional verification */
else
{
/* length mismatch */
if (record->explength != record->length)
set_status(record, AUDIT_STATUS_FOUND_INVALID, SUBSTATUS_FOUND_WRONG_LENGTH);
/* found but needs a dump */
else if (record->exphashes.flag(hash_collection::FLAG_NO_DUMP))
set_status(record, AUDIT_STATUS_GOOD, SUBSTATUS_FOUND_NODUMP);
/* incorrect hash */
else if (record->exphashes != record->hashes)
set_status(record, AUDIT_STATUS_FOUND_INVALID, SUBSTATUS_FOUND_BAD_CHECKSUM);
/* correct hash but needs a redump */
else if (record->exphashes.flag(hash_collection::FLAG_BAD_DUMP))
set_status(record, AUDIT_STATUS_GOOD, SUBSTATUS_GOOD_NEEDS_REDUMP);
/* just plain old good */
else
set_status(record, AUDIT_STATUS_GOOD, SUBSTATUS_GOOD);
}
} }
/*------------------------------------------------- //-------------------------------------------------
audit_one_disk - validate a single disk entry // audit_one_disk - validate a single disk entry
-------------------------------------------------*/ //-------------------------------------------------
static void audit_one_disk(emu_options &options, const rom_entry *rom, const game_driver *gamedrv, const char *validation, audit_record *record) audit_record *media_auditor::audit_one_disk(const rom_entry *rom)
{ {
// allocate and append a new record
audit_record &record = m_record_list.append(*global_alloc(audit_record(*rom, audit_record::MEDIA_DISK)));
// open the disk
emu_file *source_file; emu_file *source_file;
chd_file *source; chd_file *source;
chd_error err; chd_error err = open_disk_image(m_enumerator.options(), &m_enumerator.driver(), rom, &source_file, &source, NULL);
/* fill in the record basics */ // if we succeeded, get the hashes
record->type = AUDIT_FILE_DISK; if (err == CHDERR_NONE)
record->name = ROM_GETNAME(rom);
record->exphashes.from_internal_string(ROM_GETHASHDATA(rom));
/* open the disk */
err = open_disk_image(options, gamedrv, rom, &source_file, &source, NULL);
/* if we failed, report the error */
if (err != CHDERR_NONE)
{
/* out of memory */
if (err == CHDERR_OUT_OF_MEMORY)
set_status(record, AUDIT_STATUS_ERROR, SUBSTATUS_ERROR);
/* not found but it's not good anyway */
else if (record->exphashes.flag(hash_collection::FLAG_NO_DUMP))
set_status(record, AUDIT_STATUS_NOT_FOUND, SUBSTATUS_NOT_FOUND_NODUMP);
/* not found but optional */
else if (DISK_ISOPTIONAL(rom))
set_status(record, AUDIT_STATUS_NOT_FOUND, SUBSTATUS_NOT_FOUND_OPTIONAL);
/* not found at all */
else
set_status(record, AUDIT_STATUS_NOT_FOUND, SUBSTATUS_NOT_FOUND);
}
/* if we succeeded, validate it */
else
{ {
static const UINT8 nullhash[20] = { 0 }; static const UINT8 nullhash[20] = { 0 };
chd_header header = *chd_get_header(source); chd_header header = *chd_get_header(source);
hash_collection hashes;
/* if there's an MD5 or SHA1 hash, add them to the output hash */ // if there's an MD5 or SHA1 hash, add them to the output hash
if (memcmp(nullhash, header.md5, sizeof(header.md5)) != 0) if (memcmp(nullhash, header.md5, sizeof(header.md5)) != 0)
record->hashes.add_from_buffer(hash_collection::HASH_MD5, header.md5, sizeof(header.md5)); hashes.add_from_buffer(hash_collection::HASH_MD5, header.md5, sizeof(header.md5));
if (memcmp(nullhash, header.sha1, sizeof(header.sha1)) != 0) if (memcmp(nullhash, header.sha1, sizeof(header.sha1)) != 0)
record->hashes.add_from_buffer(hash_collection::HASH_SHA1, header.sha1, sizeof(header.sha1)); hashes.add_from_buffer(hash_collection::HASH_SHA1, header.sha1, sizeof(header.sha1));
/* found but needs a dump */ // update the actual values
if (record->exphashes.flag(hash_collection::FLAG_NO_DUMP)) record.set_actual(hashes);
set_status(record, AUDIT_STATUS_GOOD, SUBSTATUS_FOUND_NODUMP);
/* incorrect hash */
else if (record->exphashes != record->hashes)
set_status(record, AUDIT_STATUS_FOUND_INVALID, SUBSTATUS_FOUND_BAD_CHECKSUM);
/* correct hash but needs a redump */
else if (record->exphashes.flag(hash_collection::FLAG_BAD_DUMP))
set_status(record, AUDIT_STATUS_GOOD, SUBSTATUS_GOOD_NEEDS_REDUMP);
/* just plain good */
else
set_status(record, AUDIT_STATUS_GOOD, SUBSTATUS_GOOD);
// close the file and release the source
chd_close(source); chd_close(source);
global_free(source_file); global_free(source_file);
} }
// compute the final status
compute_status(record, rom, record.actual_length() != 0);
return &record;
} }
/*------------------------------------------------- //-------------------------------------------------
rom_used_by_parent - determine if a given // compute_status - compute a detailed status
ROM is also used by the parent // based on the information we have
-------------------------------------------------*/ //-------------------------------------------------
static int rom_used_by_parent(emu_options &options, const game_driver *gamedrv, const hash_collection &romhashes, const game_driver **parent) void media_auditor::compute_status(audit_record &record, const rom_entry *rom, bool found)
{ {
const game_driver *drv; // if not found, provide more details
if (!found)
/* iterate up the parent chain */
for (drv = driver_get_clone(gamedrv); drv != NULL; drv = driver_get_clone(drv))
{ {
machine_config config(*drv, options); int parent;
const rom_entry *region;
const rom_entry *rom; // no good dump
if (record.expected_hashes().flag(hash_collection::FLAG_NO_DUMP))
record.set_status(audit_record::STATUS_NOT_FOUND, audit_record::SUBSTATUS_NOT_FOUND_NODUMP);
/* see if the parent has the same ROM or not */ // optional ROM
for (const rom_source *source = rom_first_source(config); source != NULL; source = rom_next_source(*source)) else if (ROM_ISOPTIONAL(rom))
for (region = rom_first_region(*source); region; region = rom_next_region(region)) record.set_status(audit_record::STATUS_NOT_FOUND, audit_record::SUBSTATUS_NOT_FOUND_OPTIONAL);
for (rom = rom_first_file(region); rom; rom = rom_next_file(rom))
// not found and used by parent
else if ((parent = also_used_by_parent(record.expected_hashes())) != -1)
{
if (m_enumerator.driver(parent).flags & GAME_IS_BIOS_ROOT)
record.set_status(audit_record::STATUS_NOT_FOUND, audit_record::SUBSTATUS_NOT_FOUND_BIOS);
else
record.set_status(audit_record::STATUS_NOT_FOUND, audit_record::SUBSTATUS_NOT_FOUND_PARENT);
}
// just plain old not found
else
record.set_status(audit_record::STATUS_NOT_FOUND, audit_record::SUBSTATUS_NOT_FOUND);
}
// if found, provide more details
else
{
// length mismatch
if (record.expected_length() != record.actual_length())
record.set_status(audit_record::STATUS_FOUND_INVALID, audit_record::SUBSTATUS_FOUND_WRONG_LENGTH);
// found but needs a dump
else if (record.expected_hashes().flag(hash_collection::FLAG_NO_DUMP))
record.set_status(audit_record::STATUS_GOOD, audit_record::SUBSTATUS_FOUND_NODUMP);
// incorrect hash
else if (record.expected_hashes() != record.actual_hashes())
record.set_status(audit_record::STATUS_FOUND_INVALID, audit_record::SUBSTATUS_FOUND_BAD_CHECKSUM);
// correct hash but needs a redump
else if (record.expected_hashes().flag(hash_collection::FLAG_BAD_DUMP))
record.set_status(audit_record::STATUS_GOOD, audit_record::SUBSTATUS_GOOD_NEEDS_REDUMP);
// just plain old good
else
record.set_status(audit_record::STATUS_GOOD, audit_record::SUBSTATUS_GOOD);
}
}
//-------------------------------------------------
// also_used_by_parent - return the index in the
// enumerator of the parent who also owns a media
// entry with the same hashes
//-------------------------------------------------
int media_auditor::also_used_by_parent(const hash_collection &romhashes)
{
// iterate up the parent chain
for (int drvindex = m_enumerator.find(m_enumerator.driver().parent); drvindex != -1; drvindex = m_enumerator.find(m_enumerator.driver(drvindex).parent))
// see if the parent has the same ROM or not
for (const rom_source *source = rom_first_source(m_enumerator.config(drvindex)); source != NULL; source = rom_next_source(*source))
for (const rom_entry *region = rom_first_region(*source); region; region = rom_next_region(region))
for (const rom_entry *rom = rom_first_file(region); rom; rom = rom_next_file(rom))
{ {
hash_collection hashes(ROM_GETHASHDATA(rom)); hash_collection hashes(ROM_GETHASHDATA(rom));
if (!hashes.flag(hash_collection::FLAG_NO_DUMP) && hashes == romhashes) if (!hashes.flag(hash_collection::FLAG_NO_DUMP) && hashes == romhashes)
{ return drvindex;
if (parent != NULL)
*parent = drv;
return TRUE;
}
} }
}
return FALSE; // nope, return -1
return -1;
}
//-------------------------------------------------
// audit_record - constructor
//-------------------------------------------------
audit_record::audit_record(const rom_entry &media, media_type type)
: m_next(NULL),
m_type(type),
m_status(STATUS_ERROR),
m_substatus(SUBSTATUS_ERROR),
m_name(ROM_GETNAME(&media)),
m_explength(rom_file_size(&media)),
m_length(0)
{
m_exphashes.from_internal_string(ROM_GETHASHDATA(&media));
}
audit_record::audit_record(const char *name, media_type type)
: m_next(NULL),
m_type(type),
m_status(STATUS_ERROR),
m_substatus(SUBSTATUS_ERROR),
m_name(name),
m_explength(0),
m_length(0)
{
} }

View File

@ -4,8 +4,36 @@
ROM, disk, and sample auditing functions. ROM, disk, and sample auditing functions.
Copyright Nicola Salmoria and the MAME Team. ****************************************************************************
Visit http://mamedev.org for licensing and usage restrictions.
Copyright Aaron Giles
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are
met:
* Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in
the documentation and/or other materials provided with the
distribution.
* Neither the name 'MAME' nor the names of its contributors may be
used to endorse or promote products derived from this software
without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY AARON GILES ''AS IS'' AND ANY EXPRESS OR
IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL AARON GILES BE LIABLE FOR ANY DIRECT,
INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
POSSIBILITY OF SUCH DAMAGE.
***************************************************************************/ ***************************************************************************/
@ -18,84 +46,145 @@
/*************************************************************************** //**************************************************************************
CONSTANTS // CONSTANTS
***************************************************************************/ //**************************************************************************
/* hashes to use for validation */ // hashes to use for validation
#define AUDIT_VALIDATE_FAST "R" /* CRC only */ #define AUDIT_VALIDATE_FAST "R" /* CRC only */
#define AUDIT_VALIDATE_FULL "RS" /* CRC + SHA1 */ #define AUDIT_VALIDATE_FULL "RS" /* CRC + SHA1 */
/* return values from audit_verify_roms and audit_verify_samples */
enum
{
CORRECT = 0,
BEST_AVAILABLE,
INCORRECT,
NOTFOUND
};
/* image types for audit_record.type */
enum
{
AUDIT_FILE_ROM = 0,
AUDIT_FILE_DISK,
AUDIT_FILE_SAMPLE
};
/* status values for audit_record.status */ //**************************************************************************
enum // TYPE DEFINITIONS
{ //**************************************************************************
AUDIT_STATUS_GOOD = 0,
AUDIT_STATUS_FOUND_INVALID,
AUDIT_STATUS_NOT_FOUND,
AUDIT_STATUS_ERROR
};
/* substatus values for audit_record.substatus */
enum // ======================> audit_record
// holds the result of auditing a single item
class audit_record
{ {
SUBSTATUS_GOOD = 0, friend class simple_list<audit_record>;
SUBSTATUS_GOOD_NEEDS_REDUMP,
SUBSTATUS_FOUND_NODUMP, public:
SUBSTATUS_FOUND_BAD_CHECKSUM, // media types
SUBSTATUS_FOUND_WRONG_LENGTH, enum media_type
SUBSTATUS_NOT_FOUND, {
SUBSTATUS_NOT_FOUND_NODUMP, MEDIA_ROM = 0,
SUBSTATUS_NOT_FOUND_OPTIONAL, MEDIA_DISK,
SUBSTATUS_NOT_FOUND_PARENT, MEDIA_SAMPLE
SUBSTATUS_NOT_FOUND_BIOS, };
SUBSTATUS_ERROR = 100
// status values
enum audit_status
{
STATUS_GOOD = 0,
STATUS_FOUND_INVALID,
STATUS_NOT_FOUND,
STATUS_ERROR
};
// substatus values
enum audit_substatus
{
SUBSTATUS_GOOD = 0,
SUBSTATUS_GOOD_NEEDS_REDUMP,
SUBSTATUS_FOUND_NODUMP,
SUBSTATUS_FOUND_BAD_CHECKSUM,
SUBSTATUS_FOUND_WRONG_LENGTH,
SUBSTATUS_NOT_FOUND,
SUBSTATUS_NOT_FOUND_NODUMP,
SUBSTATUS_NOT_FOUND_OPTIONAL,
SUBSTATUS_NOT_FOUND_PARENT,
SUBSTATUS_NOT_FOUND_BIOS,
SUBSTATUS_ERROR = 100
};
// construction/destruction
audit_record(const rom_entry &media, media_type type);
audit_record(const char *name, media_type type);
// getters
audit_record *next() const { return m_next; }
media_type type() const { return m_type; }
audit_status status() const { return m_status; }
audit_substatus substatus() const { return m_substatus; }
const char *name() const { return m_name; }
UINT64 expected_length() const { return m_explength; }
UINT64 actual_length() const { return m_length; }
const hash_collection &expected_hashes() const { return m_exphashes; }
const hash_collection &actual_hashes() const { return m_hashes; }
// setters
void set_status(audit_status status, audit_substatus substatus)
{
m_status = status;
m_substatus = substatus;
}
void set_actual(const hash_collection &hashes, UINT64 length = 0)
{
m_hashes = hashes;
m_length = length;
}
private:
// internal state
audit_record * m_next;
media_type m_type; /* type of item that was audited */
audit_status m_status; /* status of audit on this item */
audit_substatus m_substatus; /* finer-detail status */
const char * m_name; /* name of item */
UINT64 m_explength; /* expected length of item */
UINT64 m_length; /* actual length of item */
hash_collection m_exphashes; /* expected hash data */
hash_collection m_hashes; /* actual hash information */
}; };
// ======================> media_auditor
/*************************************************************************** // class which manages auditing of items
TYPE DEFINITIONS class media_auditor
***************************************************************************/
typedef struct _audit_record audit_record;
struct _audit_record
{ {
UINT8 type; /* type of item that was audited */ public:
UINT8 status; /* status of audit on this item */ // summary values
UINT8 substatus; /* finer-detail status */ enum summary
const char * name; /* name of item */ {
UINT32 explength; /* expected length of item */ CORRECT = 0,
UINT32 length; /* actual length of item */ NONE_NEEDED,
hash_collection exphashes; /* expected hash data */ BEST_AVAILABLE,
hash_collection hashes; /* actual hash information */ INCORRECT,
NOTFOUND
};
// construction/destruction
media_auditor(const driver_enumerator &enumerator);
// getters
audit_record *first() const { return m_record_list.first(); }
int count() const { return m_record_list.count(); }
// audit operations
summary audit_media(const char *validation = AUDIT_VALIDATE_FULL);
summary audit_samples();
summary summarize(astring *output = NULL);
private:
// internal helpers
audit_record *audit_one_rom(const rom_entry *rom);
audit_record *audit_one_disk(const rom_entry *rom);
void compute_status(audit_record &record, const rom_entry *rom, bool found);
int also_used_by_parent(const hash_collection &romhashes);
// internal state
simple_list<audit_record> m_record_list;
const driver_enumerator & m_enumerator;
const char * m_validation;
const char * m_searchpath;
}; };
/***************************************************************************
FUNCTION PROTOTYPES
***************************************************************************/
int audit_images(emu_options &options, const game_driver *gamedrv, const char *validation, audit_record **audit);
int audit_samples(emu_options &options, const game_driver *gamedrv, audit_record **audit);
int audit_summary(const game_driver *gamedrv, int count, const audit_record *records, int output);
#endif /* __AUDIT_H__ */ #endif /* __AUDIT_H__ */

File diff suppressed because it is too large Load Diff

View File

@ -80,6 +80,7 @@
// TYPE DEFINITIONS // TYPE DEFINITIONS
//************************************************************************** //**************************************************************************
// cli_options wraps the general emu options with CLI-specific additions
class cli_options : public emu_options class cli_options : public emu_options
{ {
public: public:
@ -91,22 +92,75 @@ private:
}; };
// cli_frontend handles command-line processing and emulator execution
class cli_frontend
{
public:
// construction/destruction
cli_frontend(cli_options &options, osd_interface &osd);
~cli_frontend();
// execute based on the incoming argc/argv
int execute(int argc, char **argv);
// direct access to the command operations
void listxml(const char *gamename = "*");
void listfull(const char *gamename = "*");
void listsource(const char *gamename = "*");
void listclones(const char *gamename = "*");
void listbrothers(const char *gamename = "*");
void listcrc(const char *gamename = "*");
void listroms(const char *gamename = "*");
void listsamples(const char *gamename = "*");
void listdevices(const char *gamename = "*");
void listmedia(const char *gamename = "*");
void verifyroms(const char *gamename = "*");
void verifysamples(const char *gamename = "*");
void romident(const char *filename);
/*************************************************************************** private:
FUNCTION PROTOTYPES // internal helpers
***************************************************************************/ void execute_commands(const char *exename);
void display_help();
void display_suggestions(const char *gamename);
// internal state
cli_options & m_options;
osd_interface & m_osd;
int m_result;
};
// media_identifier class identifies media by hash via a search in
// the driver database
class media_identifier
{
public:
// construction/destruction
media_identifier(cli_options &options);
// getters
const char *result() const { return m_result; }
int total() const { return m_total; }
int matches() const { return m_matches; }
int nonroms() const { return m_nonroms; }
// operations
void reset() { m_total = m_matches = m_nonroms = 0; m_result.reset(); }
void identify(const char *name);
void identify_file(const char *name);
void identify_data(const char *name, const UINT8 *data, int length);
int find_by_hash(const hash_collection &hashes, int length);
private:
// internal state
driver_enumerator m_drivlist;
astring m_result;
int m_total;
int m_matches;
int m_nonroms;
};
int cli_execute(cli_options &options, osd_interface &osd, int argc, char **argv);
/* informational functions */
void cli_info_listxml(emu_options &options, const char *gamename);
void cli_info_listfull(emu_options &options, const char *gamename);
void cli_info_listsource(emu_options &options, const char *gamename);
void cli_info_listclones(emu_options &options, const char *gamename);
void cli_info_listbrothers(emu_options &options, const char *gamename);
void cli_info_listcrc(emu_options &options, const char *gamename);
void cli_info_listroms(emu_options &options, const char *gamename);
void cli_info_listsamples(emu_options &options, const char *gamename);
void cli_info_listdevices(emu_options &options, const char *gamename);
#endif /* __CLIFRONT_H__ */ #endif /* __CLIFRONT_H__ */

View File

@ -235,13 +235,13 @@ static int config_load_xml(running_machine &machine, emu_file &file, int which_t
case CONFIG_TYPE_CONTROLLER: case CONFIG_TYPE_CONTROLLER:
{ {
const game_driver *clone_of; int clone_of;
/* match on: default, game name, source file name, parent name, grandparent name */ /* match on: default, game name, source file name, parent name, grandparent name */
if (strcmp(name, "default") != 0 && if (strcmp(name, "default") != 0 &&
strcmp(name, machine.system().name) != 0 && strcmp(name, machine.system().name) != 0 &&
strcmp(name, srcfile) != 0 && strcmp(name, srcfile) != 0 &&
((clone_of = driver_get_clone(&machine.system())) == NULL || strcmp(name, clone_of->name) != 0) && ((clone_of = driver_list::clone(machine.system())) == -1 || strcmp(name, driver_list::driver(clone_of).name) != 0) &&
(clone_of == NULL || ((clone_of = driver_get_clone(clone_of)) == NULL) || strcmp(name, clone_of->name) != 0)) (clone_of == -1 || ((clone_of = driver_list::clone(clone_of)) == -1) || strcmp(name, driver_list::driver(clone_of).name) != 0))
continue; continue;
break; break;
} }

View File

@ -336,6 +336,12 @@ void *malloc_file_line(size_t size, const char *file, int line)
return osd_malloc(size); return osd_malloc(size);
} }
void *malloc_array_file_line(size_t size, const char *file, int line)
{
// allocate the memory and fail if we can't
return osd_malloc_array(size);
}
void free_file_line( void *memory, const char *file, int line ) void free_file_line( void *memory, const char *file, int line )
{ {
osd_free( memory ); osd_free( memory );

View File

@ -93,7 +93,7 @@ text_buffer *text_buffer_alloc(UINT32 bytes, UINT32 lines)
return NULL; return NULL;
/* allocate memory for the buffer itself */ /* allocate memory for the buffer itself */
text->buffer = (char *)osd_malloc(bytes); text->buffer = (char *)osd_malloc_array(bytes);
if (!text->buffer) if (!text->buffer)
{ {
osd_free(text); osd_free(text);
@ -101,7 +101,7 @@ text_buffer *text_buffer_alloc(UINT32 bytes, UINT32 lines)
} }
/* allocate memory for the lines array */ /* allocate memory for the lines array */
text->lineoffs = (INT32 *)osd_malloc(lines * sizeof(text->lineoffs[0])); text->lineoffs = (INT32 *)osd_malloc_array(lines * sizeof(text->lineoffs[0]));
if (!text->lineoffs) if (!text->lineoffs)
{ {
osd_free(text->buffer); osd_free(text->buffer);

View File

@ -88,6 +88,7 @@ legacy_cpu_device_config::legacy_cpu_device_config(const machine_config &mconfig
// set the real name // set the real name
m_name = get_legacy_config_string(DEVINFO_STR_NAME); m_name = get_legacy_config_string(DEVINFO_STR_NAME);
m_shortname = get_legacy_config_string(DEVINFO_STR_SHORTNAME); m_shortname = get_legacy_config_string(DEVINFO_STR_SHORTNAME);
m_searchpath = m_shortname;
} }

View File

@ -307,6 +307,30 @@ device_config::device_config(const machine_config &mconfig, device_type type, co
} }
device_config::device_config(const machine_config &mconfig, device_type type, const char *name, const char *shortname, const char *tag, const device_config *owner, UINT32 clock, UINT32 param)
: m_next(NULL),
m_owner(const_cast<device_config *>(owner)),
m_interface_list(NULL),
m_type(type),
m_clock(clock),
m_machine_config(mconfig),
m_static_config(NULL),
m_input_defaults(NULL),
m_name(name),
m_shortname(shortname),
m_searchpath(shortname),
m_tag(tag),
m_config_complete(false)
{
// derive the clock from our owner if requested
if ((m_clock & 0xff000000) == 0xff000000)
{
assert(m_owner != NULL);
m_clock = m_owner->m_clock * ((m_clock >> 12) & 0xfff) / ((m_clock >> 0) & 0xfff);
}
}
//------------------------------------------------- //-------------------------------------------------
// ~device_config - destructor // ~device_config - destructor
//------------------------------------------------- //-------------------------------------------------

View File

@ -262,6 +262,7 @@ class device_config
protected: protected:
// construction/destruction // construction/destruction
device_config(const machine_config &mconfig, device_type type, const char *name, const char *tag, const device_config *owner, UINT32 clock, UINT32 param = 0); device_config(const machine_config &mconfig, device_type type, const char *name, const char *tag, const device_config *owner, UINT32 clock, UINT32 param = 0);
device_config(const machine_config &mconfig, device_type type, const char *name, const char *shortname, const char *tag, const device_config *owner, UINT32 clock, UINT32 param = 0);
virtual ~device_config(); virtual ~device_config();
public: public:
@ -289,6 +290,7 @@ public:
UINT32 clock() const { return m_clock; } UINT32 clock() const { return m_clock; }
const char *name() const { return m_name; } const char *name() const { return m_name; }
const char *shortname() const { return m_shortname; } const char *shortname() const { return m_shortname; }
const char *searchpath() const { return m_searchpath; }
const char *tag() const { return m_tag; } const char *tag() const { return m_tag; }
const void *static_config() const { return m_static_config; } const void *static_config() const { return m_static_config; }
const machine_config &mconfig() const { return m_machine_config; } const machine_config &mconfig() const { return m_machine_config; }
@ -336,7 +338,9 @@ protected:
const input_device_default *m_input_defaults; // devices input ports default overrides const input_device_default *m_input_defaults; // devices input ports default overrides
astring m_name; // name of the device astring m_name; // name of the device
astring m_shortname; // short name of the device, used for potential romload astring m_shortname; // short name of the device
astring m_searchpath; // search path, used for media loading
private: private:
astring m_tag; // tag for this instance astring m_tag; // tag for this instance
bool m_config_complete; // have we completed our configuration? bool m_config_complete; // have we completed our configuration?

View File

@ -62,6 +62,7 @@ legacy_device_config_base::legacy_device_config_base(const machine_config &mconf
// set the proper name // set the proper name
m_name = get_legacy_config_string(DEVINFO_STR_NAME); m_name = get_legacy_config_string(DEVINFO_STR_NAME);
m_shortname = get_legacy_config_string(DEVINFO_STR_SHORTNAME); m_shortname = get_legacy_config_string(DEVINFO_STR_SHORTNAME);
m_searchpath = m_shortname;
} }

View File

@ -126,7 +126,7 @@ enum
DEVINFO_STR_FIRST = 0x30000, DEVINFO_STR_FIRST = 0x30000,
DEVINFO_STR_NAME = DEVINFO_STR_FIRST, // R/O: name of the device DEVINFO_STR_NAME = DEVINFO_STR_FIRST, // R/O: name of the device
DEVINFO_STR_SHORTNAME, // R/O: short name of device, used in case of romload DEVINFO_STR_SHORTNAME, // R/O: search path of device, used for media loading
DEVINFO_STR_FAMILY, // R/O: family of the device DEVINFO_STR_FAMILY, // R/O: family of the device
DEVINFO_STR_VERSION, // R/O: version of the device DEVINFO_STR_VERSION, // R/O: version of the device
DEVINFO_STR_SOURCE_FILE, // R/O: file containing the device implementation DEVINFO_STR_SOURCE_FILE, // R/O: file containing the device implementation

View File

@ -383,7 +383,6 @@ bool device_image_interface::try_change_working_directory(const char *subdir)
void device_image_interface::setup_working_directory() void device_image_interface::setup_working_directory()
{ {
const game_driver *gamedrv;
char *dst = NULL; char *dst = NULL;
osd_get_full_path(&dst,"."); osd_get_full_path(&dst,".");
@ -394,10 +393,10 @@ void device_image_interface::setup_working_directory()
if (try_change_working_directory("software")) if (try_change_working_directory("software"))
{ {
/* now down to a directory for this computer */ /* now down to a directory for this computer */
gamedrv = &device().machine().system(); int gamedrv = driver_list::find(device().machine().system());
while(gamedrv && !try_change_working_directory(gamedrv->name)) while(gamedrv != -1 && !try_change_working_directory(driver_list::driver(gamedrv).name))
{ {
gamedrv = driver_get_compatible(gamedrv); gamedrv = driver_list::compatible_with(gamedrv);
} }
} }
osd_free(dst); osd_free(dst);

View File

@ -2,10 +2,38 @@
driver.c driver.c
Driver construction helpers. Driver enumeration helpers.
Copyright Nicola Salmoria and the MAME Team. ****************************************************************************
Visit http://mamedev.org for licensing and usage restrictions.
Copyright Aaron Giles
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are
met:
* Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in
the documentation and/or other materials provided with the
distribution.
* Neither the name 'MAME' nor the names of its contributors may be
used to endorse or promote products derived from this software
without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY AARON GILES ''AS IS'' AND ANY EXPRESS OR
IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL AARON GILES BE LIABLE FOR ANY DIRECT,
INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
POSSIBILITY OF SUCH DAMAGE.
***************************************************************************/ ***************************************************************************/
@ -14,219 +42,74 @@
/*************************************************************************** //**************************************************************************
CONSTANTS // DRIVER LIST
***************************************************************************/ //**************************************************************************
#define DRIVER_LRU_SIZE 10 //-------------------------------------------------
// driver_list - constructor
//-------------------------------------------------
driver_list::driver_list()
/***************************************************************************
GLOBAL VARIABLES
***************************************************************************/
static int driver_lru[DRIVER_LRU_SIZE];
/***************************************************************************
FUNCTION PROTOTYPES
***************************************************************************/
static int penalty_compare(const char *source, const char *target);
/***************************************************************************
MISC FUNCTIONS
***************************************************************************/
/*-------------------------------------------------
driver_get_name - return a pointer to a
driver given its name
-------------------------------------------------*/
const game_driver *driver_get_name(const char *name)
{ {
int lurnum, drvnum;
/* scan the LRU list first */
for (lurnum = 0; lurnum < DRIVER_LRU_SIZE; lurnum++)
if (mame_stricmp(drivers[driver_lru[lurnum]]->name, name) == 0)
{
/* if not first, swap with the head */
if (lurnum != 0)
{
int temp = driver_lru[0];
driver_lru[0] = driver_lru[lurnum];
driver_lru[lurnum] = temp;
}
return drivers[driver_lru[0]];
}
/* scan for a match in the drivers -- slow! */
for (drvnum = 0; drivers[drvnum] != NULL; drvnum++)
if (mame_stricmp(drivers[drvnum]->name, name) == 0)
{
memmove((void *)&driver_lru[1], (void *)&driver_lru[0], sizeof(driver_lru[0]) * (DRIVER_LRU_SIZE - 1));
driver_lru[0] = drvnum;
return drivers[drvnum];
}
return NULL;
} }
/*------------------------------------------------- //-------------------------------------------------
driver_get_clone - return a pointer to the // find - find a driver by name
clone of a game driver. //-------------------------------------------------
-------------------------------------------------*/
const game_driver *driver_get_clone(const game_driver *driver) int driver_list::find(const char *name)
{ {
/* if no clone, easy out */ // if no name, bail
if (driver->parent == NULL || (driver->parent[0] == '0' && driver->parent[1] == 0)) if (name == NULL)
return NULL; return -1;
/* convert the name to a game_driver */ // create a dummy item for comparison purposes
return driver_get_name(driver->parent); game_driver driver;
driver.name = name;
game_driver *driverptr = &driver;
// binary search to find it
const game_driver **result = reinterpret_cast<const game_driver **>(bsearch(&driverptr, s_drivers_sorted, s_driver_count, sizeof(*s_drivers_sorted), driver_sort_callback));
return (result == NULL) ? -1 : result - s_drivers_sorted;
} }
/*------------------------------------------------- //-------------------------------------------------
driver_get_searchpath - return a search path // driver_sort_callback - compare two items in
for a given driver // an array of game_driver pointers
-------------------------------------------------*/ //-------------------------------------------------
const char *driver_get_searchpath(const game_driver &driver, astring &string) int driver_list::driver_sort_callback(const void *elem1, const void *elem2)
{ {
// create the search path consisting of gamedrv[;parent[;...]] const game_driver * const *item1 = reinterpret_cast<const game_driver * const *>(elem1);
string = driver.name; const game_driver * const *item2 = reinterpret_cast<const game_driver * const *>(elem2);
for (const game_driver *parent = driver_get_clone(&driver); parent != NULL; parent = driver_get_clone(parent)) return mame_stricmp((*item1)->name, (*item2)->name);
string.cat(";").cat(parent->name);
return string;
} }
/*------------------------------------------------- //-------------------------------------------------
driver_list_get_approx_matches - find the best // penalty_compare - compare two strings for
n matches to a driver name. // closeness and assign a score.
-------------------------------------------------*/ //-------------------------------------------------
void driver_list_get_approx_matches(const game_driver * const driverlist[], const char *name, int matches, const game_driver **list) int driver_list::penalty_compare(const char *source, const char *target)
{
#undef rand
int matchnum, drvnum;
int *penalty;
/* if no name, pick random entries */
if (name == NULL || name[0] == 0)
{
const game_driver **templist;
int driver_count;
int shufnum;
/* allocate a temporary list */
templist = global_alloc_array(const game_driver *, driver_list_get_count(driverlist));
/* build up a list of valid entries */
for (drvnum = driver_count = 0; driverlist[drvnum] != NULL; drvnum++)
if ((driverlist[drvnum]->flags & GAME_NO_STANDALONE) == 0)
templist[driver_count++] = driverlist[drvnum];
/* seed the RNG first */
srand(osd_ticks());
/* shuffle */
for (shufnum = 0; shufnum < 4 * driver_count; shufnum++)
{
int item1 = rand() % driver_count;
int item2 = rand() % driver_count;
const game_driver *temp;
temp = templist[item1];
templist[item1] = templist[item2];
templist[item2] = temp;
}
/* copy out the first few entries */
for (matchnum = 0; matchnum < matches; matchnum++)
list[matchnum] = templist[matchnum % driver_count];
global_free(templist);
return;
}
/* allocate some temp memory */
penalty = global_alloc_array(int, matches);
/* initialize everyone's states */
for (matchnum = 0; matchnum < matches; matchnum++)
{
penalty[matchnum] = 9999;
list[matchnum] = NULL;
}
/* scan the entire drivers array */
for (drvnum = 0; driverlist[drvnum] != NULL; drvnum++)
{
int curpenalty, tmp;
/* skip things that can't run */
if ((driverlist[drvnum]->flags & GAME_NO_STANDALONE) != 0)
continue;
/* pick the best match between driver name and description */
curpenalty = penalty_compare(name, driverlist[drvnum]->description);
tmp = penalty_compare(name, driverlist[drvnum]->name);
curpenalty = MIN(curpenalty, tmp);
/* insert into the sorted table of matches */
for (matchnum = matches - 1; matchnum >= 0; matchnum--)
{
/* stop if we're worse than the current entry */
if (curpenalty >= penalty[matchnum])
break;
/* as lng as this isn't the last entry, bump this one down */
if (matchnum < matches - 1)
{
penalty[matchnum + 1] = penalty[matchnum];
list[matchnum + 1] = list[matchnum];
}
list[matchnum] = driverlist[drvnum];
penalty[matchnum] = curpenalty;
}
}
/* free our temp memory */
global_free(penalty);
}
/*-------------------------------------------------
penalty_compare - compare two strings for
closeness and assign a score.
-------------------------------------------------*/
static int penalty_compare(const char *source, const char *target)
{ {
int gaps = 1; int gaps = 1;
int last = TRUE; bool last = true;
/* scan the strings */ // scan the strings
for ( ; *source && *target; target++) for ( ; *source && *target; target++)
{ {
/* do a case insensitive match */ // do a case insensitive match
int match = (tolower((UINT8)*source) == tolower((UINT8)*target)); bool match = (tolower((UINT8)*source) == tolower((UINT8)*target));
/* if we matched, advance the source */ // if we matched, advance the source
if (match) if (match)
source++; source++;
/* if the match state changed, count gaps */ // if the match state changed, count gaps
if (match != last) if (match != last)
{ {
last = match; last = match;
@ -235,11 +118,11 @@ static int penalty_compare(const char *source, const char *target)
} }
} }
/* penalty if short string does not completely fit in */ // penalty if short string does not completely fit in
for ( ; *source; source++) for ( ; *source; source++)
gaps++; gaps++;
/* if we matched perfectly, gaps == 0 */ // if we matched perfectly, gaps == 0
if (gaps == 1 && *source == 0 && *target == 0) if (gaps == 1 && *source == 0 && *target == 0)
gaps = 0; gaps = 0;
@ -247,31 +130,244 @@ static int penalty_compare(const char *source, const char *target)
} }
/*-------------------------------------------------
driver_list_get_count - returns the amount of
drivers
-------------------------------------------------*/
int driver_list_get_count(const game_driver * const driverlist[]) //**************************************************************************
// DRIVER ENUMERATOR
//**************************************************************************
//-------------------------------------------------
// driver_enumerator - constructor
//-------------------------------------------------
driver_enumerator::driver_enumerator(emu_options &options)
: m_current(-1),
m_filtered_count(0),
m_options(options),
m_included(global_alloc_array(UINT8, s_driver_count)),
m_config(global_alloc_array_clear(machine_config *, s_driver_count))
{ {
int count; include_all();
for (count = 0; driverlist[count] != NULL; count++) ;
return count;
} }
/*-------------------------------------------------
driver_get_compatible - return a pointer to the
compatible driver.
-------------------------------------------------*/
const game_driver *driver_get_compatible(const game_driver *drv) driver_enumerator::driver_enumerator(emu_options &options, const char *string)
: m_current(-1),
m_filtered_count(0),
m_options(options),
m_included(global_alloc_array(UINT8, s_driver_count)),
m_config(global_alloc_array_clear(machine_config *, s_driver_count))
{ {
if (driver_get_clone(drv)) filter(string);
drv = driver_get_clone(drv); }
else if (drv->compatible_with)
drv = driver_get_name(drv->compatible_with);
else driver_enumerator::driver_enumerator(emu_options &options, const game_driver &driver)
drv = NULL; : m_current(-1),
return drv; m_filtered_count(0),
m_options(options),
m_included(global_alloc_array(UINT8, s_driver_count)),
m_config(global_alloc_array_clear(machine_config *, s_driver_count))
{
filter(driver);
}
//-------------------------------------------------
// ~driver_enumerator - destructor
//-------------------------------------------------
driver_enumerator::~driver_enumerator()
{
// free any configs
for (int index = 0; index < s_driver_count; index++)
global_free(m_config[index]);
// free the arrays
global_free(m_included);
global_free(m_config);
}
//-------------------------------------------------
// config - return a machine_config for the given
// driver, allocating on demand if needed
//-------------------------------------------------
machine_config &driver_enumerator::config(int index) const
{
assert(index >= 0 && index < s_driver_count);
if (m_config[index] == NULL)
m_config[index] = global_alloc(machine_config(*s_drivers_sorted[index], m_options));
return *m_config[index];
}
//-------------------------------------------------
// filter - filter the driver list against the
// given string
//-------------------------------------------------
int driver_enumerator::filter(const char *filterstring)
{
// reset the count
exclude_all();
// match name against each driver in the list
for (int index = 0; index < s_driver_count; index++)
if (matches(filterstring, s_drivers_sorted[index]->name))
include(index);
return m_filtered_count;
}
//-------------------------------------------------
// filter - filter the driver list against the
// given driver
//-------------------------------------------------
int driver_enumerator::filter(const game_driver &driver)
{
// reset the count
exclude_all();
// match name against each driver in the list
for (int index = 0; index < s_driver_count; index++)
if (s_drivers_sorted[index] == &driver)
include(index);
return m_filtered_count;
}
//-------------------------------------------------
// next - get the next driver matching the given
// filter
//-------------------------------------------------
bool driver_enumerator::next()
{
// always advance one
m_current++;
// if we have a filter, scan forward to the next match
while (m_current < s_driver_count)
{
if (m_included[m_current])
break;
m_current++;
}
// return true if we end up in range
return (m_current >= 0 && m_current < s_driver_count);
}
//-------------------------------------------------
// next_excluded - get the next driver that is
// not currently included in the list
//-------------------------------------------------
bool driver_enumerator::next_excluded()
{
// always advance one
m_current++;
// if we have a filter, scan forward to the next match
while (m_current < s_driver_count)
{
if (!m_included[m_current])
break;
m_current++;
}
// return true if we end up in range
return (m_current >= 0 && m_current < s_driver_count);
}
//-------------------------------------------------
// driver_sort_callback - compare two items in
// an array of game_driver pointers
//-------------------------------------------------
void driver_enumerator::find_approximate_matches(const char *string, int count, int *results)
{
#undef rand
// if no name, pick random entries
if (string == NULL || string[0] == 0)
{
// seed the RNG first
srand(osd_ticks());
// allocate a temporary list
int *templist = global_alloc_array(int, m_filtered_count);
int arrayindex = 0;
for (int index = 0; index < s_driver_count; index++)
if (m_included[index])
templist[arrayindex++] = index;
assert(arrayindex == m_filtered_count);
// shuffle
for (int shufnum = 0; shufnum < 4 * s_driver_count; shufnum++)
{
int item1 = rand() % m_filtered_count;
int item2 = rand() % m_filtered_count;
int temp = templist[item1];
templist[item1] = templist[item2];
templist[item2] = temp;
}
// copy out the first few entries
for (int matchnum = 0; matchnum < count; matchnum++)
results[matchnum] = templist[matchnum % m_filtered_count];
global_free(templist);
return;
}
// allocate memory to track the penalty value
int *penalty = global_alloc_array(int, count);
// initialize everyone's states
for (int matchnum = 0; matchnum < count; matchnum++)
{
penalty[matchnum] = 9999;
results[matchnum] = -1;
}
// scan the entire drivers array
for (int index = 0; index < s_driver_count; index++)
if (m_included[index])
{
// skip things that can't run
if ((s_drivers_sorted[index]->flags & GAME_NO_STANDALONE) != 0)
continue;
// pick the best match between driver name and description
int curpenalty = penalty_compare(string, s_drivers_sorted[index]->description);
int tmp = penalty_compare(string, s_drivers_sorted[index]->name);
curpenalty = MIN(curpenalty, tmp);
// insert into the sorted table of matches
for (int matchnum = count - 1; matchnum >= 0; matchnum--)
{
// stop if we're worse than the current entry
if (curpenalty >= penalty[matchnum])
break;
// as long as this isn't the last entry, bump this one down
if (matchnum < count - 1)
{
penalty[matchnum + 1] = penalty[matchnum];
results[matchnum + 1] = results[matchnum];
}
results[matchnum] = index;
penalty[matchnum] = curpenalty;
}
}
// free our temp memory
global_free(penalty);
} }

View File

@ -2,10 +2,38 @@
driver.h driver.h
Definitions relating to game drivers. Driver enumeration helpers.
Copyright Nicola Salmoria and the MAME Team. ****************************************************************************
Visit http://mamedev.org for licensing and usage restrictions.
Copyright Aaron Giles
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are
met:
* Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in
the documentation and/or other materials provided with the
distribution.
* Neither the name 'MAME' nor the names of its contributors may be
used to endorse or promote products derived from this software
without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY AARON GILES ''AS IS'' AND ANY EXPRESS OR
IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL AARON GILES BE LIABLE FOR ANY DIRECT,
INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
POSSIBILITY OF SUCH DAMAGE.
***************************************************************************/ ***************************************************************************/
@ -81,6 +109,108 @@ struct game_driver
}; };
// driver_list is a purely static class that wraps the global driver list
class driver_list
{
DISABLE_COPYING(driver_list);
protected:
// construction/destruction
driver_list();
public:
// getters
static int total() { return s_driver_count; }
// any item by index
static const game_driver &driver(int index) { assert(index >= 0 && index < s_driver_count); return *s_drivers_sorted[index]; }
static int clone(int index) { return find(driver(index).parent); }
static int non_bios_clone(int index) { int result = find(driver(index).parent); return (result != -1 && (driver(result).flags & GAME_IS_BIOS_ROOT) == 0) ? result : -1; }
static int compatible_with(int index) { int result = clone(index); return (result != -1) ? result : find(driver(index).compatible_with); }
// any item by driver
static int clone(const game_driver &driver) { int index = find(driver); assert(index != -1); return clone(index); }
static int non_bios_clone(const game_driver &driver) { int index = find(driver); assert(index != -1); return non_bios_clone(index); }
static int compatible_with(const game_driver &driver) { int index = find(driver); assert(index != -1); return compatible_with(index); }
// general helpers
static int find(const char *name);
static int find(const game_driver &driver) { return find(driver.name); }
// static helpers
static bool matches(const char *wildstring, const char *string) { return (wildstring == NULL || mame_strwildcmp(wildstring, string) == 0); }
protected:
// internal helpers
static int driver_sort_callback(const void *elem1, const void *elem2);
static int penalty_compare(const char *source, const char *target);
// internal state
static int s_driver_count;
static const game_driver * const s_drivers_sorted[];
};
// driver_enumerator enables efficient iteration through the driver list
class driver_enumerator : public driver_list
{
DISABLE_COPYING(driver_enumerator);
public:
// construction/destruction
driver_enumerator(emu_options &options);
driver_enumerator(emu_options &options, const char *filter);
driver_enumerator(emu_options &options, const game_driver &filter);
~driver_enumerator();
// getters
int count() const { return m_filtered_count; }
int current() const { return m_current; }
emu_options &options() const { return m_options; }
// current item
const game_driver &driver() const { return driver_list::driver(m_current); }
machine_config &config() const { return config(m_current); }
int clone() { return driver_list::clone(m_current); }
int non_bios_clone() { return driver_list::non_bios_clone(m_current); }
int compatible_with() { return driver_list::compatible_with(m_current); }
void include() { include(m_current); }
void exclude() { exclude(m_current); }
// any item by index
bool included(int index) const { assert(index >= 0 && index < s_driver_count); return m_included[index]; }
bool excluded(int index) const { assert(index >= 0 && index < s_driver_count); return !m_included[index]; }
machine_config &config(int index) const;
void include(int index) { assert(index >= 0 && index < s_driver_count); if (!m_included[index]) { m_included[index] = true; m_filtered_count++; } }
void exclude(int index) { assert(index >= 0 && index < s_driver_count); if (m_included[index]) { m_included[index] = false; m_filtered_count--; } }
using driver_list::driver;
using driver_list::clone;
using driver_list::non_bios_clone;
using driver_list::compatible_with;
// filtering/iterating
int filter(const char *string = NULL);
int filter(const game_driver &driver);
void include_all() { memset(m_included, 1, sizeof(m_included[0]) * s_driver_count); m_filtered_count = s_driver_count; }
void exclude_all() { memset(m_included, 0, sizeof(m_included[0]) * s_driver_count); m_filtered_count = 0; }
void reset() { m_current = -1; }
bool next();
bool next_excluded();
// general helpers
void set_current(int index) { assert(index >= -1 && index <= s_driver_count); m_current = index; }
void find_approximate_matches(const char *string, int count, int *results);
private:
// internal state
int m_current;
int m_filtered_count;
emu_options & m_options;
UINT8 * m_included;
machine_config ** m_config;
};
/*************************************************************************** /***************************************************************************
MACROS FOR BUILDING GAME DRIVERS MACROS FOR BUILDING GAME DRIVERS
@ -176,24 +306,8 @@ extern const game_driver GAME_NAME(NAME) = \
GLOBAL VARIABLES GLOBAL VARIABLES
***************************************************************************/ ***************************************************************************/
extern const game_driver * const drivers[]; GAME_EXTERN(___empty);
GAME_EXTERN(empty);
/***************************************************************************
FUNCTION PROTOTYPES
***************************************************************************/
const game_driver *driver_get_name(const char *name);
const game_driver *driver_get_clone(const game_driver *driver);
const game_driver *driver_get_compatible(const game_driver *drv);
const char *driver_get_searchpath(const game_driver &driver, astring &string);
void driver_list_get_approx_matches(const game_driver * const driverlist[], const char *name, int matches, const game_driver **list);
int driver_list_get_count(const game_driver * const driverlist[]);
#endif #endif

View File

@ -20,7 +20,7 @@
* *
*************************************/ *************************************/
static MACHINE_START( empty ) static MACHINE_START( ___empty )
{ {
/* force the UI to show the game select screen */ /* force the UI to show the game select screen */
ui_menu_force_game_select(machine, &machine.render().ui_container()); ui_menu_force_game_select(machine, &machine.render().ui_container());
@ -34,9 +34,9 @@ static MACHINE_START( empty )
* *
*************************************/ *************************************/
static MACHINE_CONFIG_START( empty, driver_device ) static MACHINE_CONFIG_START( ___empty, driver_device )
MCFG_MACHINE_START(empty) MCFG_MACHINE_START(___empty)
/* video hardware */ /* video hardware */
MCFG_SCREEN_ADD("screen", RASTER) MCFG_SCREEN_ADD("screen", RASTER)
@ -54,8 +54,8 @@ MACHINE_CONFIG_END
* *
*************************************/ *************************************/
ROM_START( empty ) ROM_START( ___empty )
ROM_REGION( 0x10, "user1", 0 ) ROM_REGION( 0x10, "user1", ROMREGION_ERASEFF )
ROM_END ROM_END
@ -66,4 +66,4 @@ ROM_END
* *
*************************************/ *************************************/
GAME( 2007, empty, 0, empty, 0, 0, ROT0, "MAME", "No Driver Loaded", 0 ) GAME( 2007, ___empty, 0, ___empty, 0, 0, ROT0, "MAME", "No Driver Loaded", GAME_NO_SOUND )

View File

@ -338,5 +338,6 @@ $(EMUOBJ)/rendlay.o: $(EMULAYOUT)/dualhovu.lh \
$(EMULAYOUT)/voffff20.lh \ $(EMULAYOUT)/voffff20.lh \
$(EMULAYOUT)/lcd.lh \ $(EMULAYOUT)/lcd.lh \
$(EMULAYOUT)/lcd_rot.lh \ $(EMULAYOUT)/lcd_rot.lh \
$(EMULAYOUT)/pinball.lh \
$(EMUOBJ)/video.o: $(EMULAYOUT)/snap.lh $(EMUOBJ)/video.o: $(EMULAYOUT)/snap.lh

View File

@ -92,6 +92,7 @@ public:
static UINT64 s_curid; // current ID static UINT64 s_curid; // current ID
static osd_lock * s_lock; // lock for managing the list static osd_lock * s_lock; // lock for managing the list
static bool s_lock_alloc; // set to true temporarily during lock allocation static bool s_lock_alloc; // set to true temporarily during lock allocation
static bool s_tracking; // set to true when tracking is live
static memory_entry *s_hash[k_hash_prime];// hash table based on pointer static memory_entry *s_hash[k_hash_prime];// hash table based on pointer
static memory_entry *s_freehead; // pointer to the head of the free list static memory_entry *s_freehead; // pointer to the head of the free list
@ -118,9 +119,10 @@ resource_pool global_resource_pool;
const zeromem_t zeromem = { }; const zeromem_t zeromem = { };
// globals for memory_entry // globals for memory_entry
UINT64 memory_entry::s_curid = 0; UINT64 memory_entry::s_curid = 1;
osd_lock *memory_entry::s_lock = NULL; osd_lock *memory_entry::s_lock = NULL;
bool memory_entry::s_lock_alloc = false; bool memory_entry::s_lock_alloc = false;
bool memory_entry::s_tracking = false;
memory_entry *memory_entry::s_hash[memory_entry::k_hash_prime] = { NULL }; memory_entry *memory_entry::s_hash[memory_entry::k_hash_prime] = { NULL };
memory_entry *memory_entry::s_freehead = NULL; memory_entry *memory_entry::s_freehead = NULL;
@ -154,6 +156,31 @@ void *malloc_file_line(size_t size, const char *file, int line)
} }
//-------------------------------------------------
// malloc_array_file_line - allocate memory with
// file and line number information, and a hint
// that this object is an array
//-------------------------------------------------
void *malloc_array_file_line(size_t size, const char *file, int line)
{
// allocate the memory and fail if we can't
void *result = osd_malloc_array(size);
if (result == NULL)
return NULL;
// add a new entry
memory_entry::allocate(size, result, file, line);
#ifdef MAME_DEBUG
// randomize the memory
rand_memory(result, size);
#endif
return result;
}
//------------------------------------------------- //-------------------------------------------------
// free_file_line - free memory with file // free_file_line - free memory with file
// and line number information // and line number information
@ -189,7 +216,19 @@ void free_file_line(void *memory, const char *file, int line)
// memory // memory
//------------------------------------------------- //-------------------------------------------------
void dump_unfreed_mem(void) void track_memory(bool track)
{
memory_entry::s_tracking = track;
}
//-------------------------------------------------
// dump_unfreed_mem - called from the exit path
// of any code that wants to check for unfreed
// memory
//-------------------------------------------------
void dump_unfreed_mem()
{ {
#ifdef MAME_DEBUG #ifdef MAME_DEBUG
memory_entry::report_unfreed(); memory_entry::report_unfreed();
@ -446,7 +485,7 @@ memory_entry *memory_entry::allocate(size_t size, void *base, const char *file,
if (s_freehead == NULL) if (s_freehead == NULL)
{ {
// create a new chunk, and fail if we can't // create a new chunk, and fail if we can't
memory_entry *entry = reinterpret_cast<memory_entry *>(osd_malloc(memory_block_alloc_chunk * sizeof(memory_entry))); memory_entry *entry = reinterpret_cast<memory_entry *>(osd_malloc_array(memory_block_alloc_chunk * sizeof(memory_entry)));
if (entry == NULL) if (entry == NULL)
{ {
release_lock(); release_lock();
@ -468,8 +507,8 @@ memory_entry *memory_entry::allocate(size_t size, void *base, const char *file,
// populate it // populate it
entry->m_size = size; entry->m_size = size;
entry->m_base = base; entry->m_base = base;
entry->m_file = file; entry->m_file = s_tracking ? file : NULL;
entry->m_line = line; entry->m_line = s_tracking ? line : 0;
entry->m_id = s_curid++; entry->m_id = s_curid++;
if (LOG_ALLOCS) if (LOG_ALLOCS)
fprintf(stderr, "#%06d, alloc %d bytes (%s:%d)\n", (UINT32)entry->m_id, static_cast<UINT32>(entry->m_size), entry->m_file, (int)entry->m_line); fprintf(stderr, "#%06d, alloc %d bytes (%s:%d)\n", (UINT32)entry->m_id, static_cast<UINT32>(entry->m_size), entry->m_file, (int)entry->m_line);
@ -561,5 +600,5 @@ void memory_entry::report_unfreed()
release_lock(); release_lock();
if (total > 0) if (total > 0)
fprintf(stderr, "a total of %d bytes were not free()'d\n", total); fprintf(stderr, "a total of %d bytes were not freed\n", total);
} }

View File

@ -46,10 +46,26 @@
#include "osdcore.h" #include "osdcore.h"
//**************************************************************************
// DEBUGGING
//**************************************************************************
// set to 1 to track memory allocated by emualloc.h itself as well
#define TRACK_SELF_MEMORY (0)
//************************************************************************** //**************************************************************************
// MACROS // MACROS
//************************************************************************** //**************************************************************************
// self-allocation helpers
#if TRACK_SELF_MEMORY
#define EMUALLOC_SELF_NEW new(__FILE__, __LINE__)
#else
#define EMUALLOC_SELF_NEW new
#endif
// pool allocation helpers // pool allocation helpers
#define pool_alloc(_pool, _type) (_pool).add_object(new(__FILE__, __LINE__) _type) #define pool_alloc(_pool, _type) (_pool).add_object(new(__FILE__, __LINE__) _type)
#define pool_alloc_clear(_pool, _type) (_pool).add_object(new(__FILE__, __LINE__, zeromem) _type) #define pool_alloc_clear(_pool, _type) (_pool).add_object(new(__FILE__, __LINE__, zeromem) _type)
@ -72,11 +88,13 @@
// allocate memory with file and line number information // allocate memory with file and line number information
void *malloc_file_line(size_t size, const char *file, int line); void *malloc_file_line(size_t size, const char *file, int line);
void *malloc_array_file_line(size_t size, const char *file, int line);
// free memory with file and line number information // free memory with file and line number information
void free_file_line(void *memory, const char *file, int line); void free_file_line(void *memory, const char *file, int line);
// called from the exit path of any code that wants to check for unfreed memory // called from the exit path of any code that wants to check for unfreed memory
void track_memory(bool track);
void dump_unfreed_mem(); void dump_unfreed_mem();
@ -100,7 +118,7 @@ ATTR_FORCE_INLINE inline void *operator new(std::size_t size) throw (std::bad_al
ATTR_FORCE_INLINE inline void *operator new[](std::size_t size) throw (std::bad_alloc) ATTR_FORCE_INLINE inline void *operator new[](std::size_t size) throw (std::bad_alloc)
{ {
void *result = malloc_file_line(size, NULL, 0); void *result = malloc_array_file_line(size, NULL, 0);
if (result == NULL) if (result == NULL)
throw std::bad_alloc(); throw std::bad_alloc();
return result; return result;
@ -130,7 +148,7 @@ ATTR_FORCE_INLINE inline void *operator new(std::size_t size, const char *file,
ATTR_FORCE_INLINE inline void *operator new[](std::size_t size, const char *file, int line) throw (std::bad_alloc) ATTR_FORCE_INLINE inline void *operator new[](std::size_t size, const char *file, int line) throw (std::bad_alloc)
{ {
void *result = malloc_file_line(size, file, line); void *result = malloc_array_file_line(size, file, line);
if (result == NULL) if (result == NULL)
throw std::bad_alloc(); throw std::bad_alloc();
return result; return result;
@ -161,7 +179,7 @@ ATTR_FORCE_INLINE inline void *operator new(std::size_t size, const char *file,
ATTR_FORCE_INLINE inline void *operator new[](std::size_t size, const char *file, int line, const zeromem_t &) throw (std::bad_alloc) ATTR_FORCE_INLINE inline void *operator new[](std::size_t size, const char *file, int line, const zeromem_t &) throw (std::bad_alloc)
{ {
void *result = malloc_file_line(size, file, line); void *result = malloc_array_file_line(size, file, line);
if (result == NULL) if (result == NULL)
throw std::bad_alloc(); throw std::bad_alloc();
memset(result, 0, size); memset(result, 0, size);
@ -270,8 +288,8 @@ public:
bool contains(void *ptrstart, void *ptrend); bool contains(void *ptrstart, void *ptrend);
void clear(); void clear();
template<class T> T *add_object(T* object) { add(*new(__FILE__, __LINE__) resource_pool_object<T>(object)); return object; } template<class T> T *add_object(T* object) { add(*EMUALLOC_SELF_NEW resource_pool_object<T>(object)); return object; }
template<class T> T *add_array(T* array, int count) { add(*new(__FILE__, __LINE__) resource_pool_array<T>(array, count)); return array; } template<class T> T *add_array(T* array, int count) { add(*EMUALLOC_SELF_NEW resource_pool_array<T>(array, count)); return array; }
private: private:
static const int k_hash_prime = 193; static const int k_hash_prime = 193;
@ -306,7 +324,7 @@ extern const zeromem_t zeromem;
#undef realloc #undef realloc
#undef free #undef free
#define malloc(x) malloc_file_line(x, __FILE__, __LINE__) #define malloc(x) malloc_array_file_line(x, __FILE__, __LINE__)
#define calloc(x,y) __error_use_auto_alloc_clear_or_global_alloc_clear_instead__ #define calloc(x,y) __error_use_auto_alloc_clear_or_global_alloc_clear_instead__
#define realloc(x,y) __error_realloc_is_dangerous__ #define realloc(x,y) __error_realloc_is_dangerous__
#define free(x) free_file_line(x, __FILE__, __LINE__) #define free(x) free_file_line(x, __FILE__, __LINE__)

View File

@ -349,12 +349,12 @@ void emu_options::parse_standard_inis(astring &error_string)
} }
// then parse the grandparent, parent, and system-specific INIs // then parse the grandparent, parent, and system-specific INIs
const game_driver *parent = driver_get_clone(cursystem); int parent = driver_list::clone(*cursystem);
const game_driver *gparent = (parent != NULL) ? driver_get_clone(parent) : NULL; int gparent = (parent != -1) ? driver_list::clone(parent) : -1;
if (gparent != NULL) if (gparent != -1)
parse_one_ini(gparent->name, OPTION_PRIORITY_GPARENT_INI, &error_string); parse_one_ini(driver_list::driver(gparent).name, OPTION_PRIORITY_GPARENT_INI, &error_string);
if (parent != NULL) if (parent != -1)
parse_one_ini(parent->name, OPTION_PRIORITY_PARENT_INI, &error_string); parse_one_ini(driver_list::driver(parent).name, OPTION_PRIORITY_PARENT_INI, &error_string);
parse_one_ini(cursystem->name, OPTION_PRIORITY_DRIVER_INI, &error_string); parse_one_ini(cursystem->name, OPTION_PRIORITY_DRIVER_INI, &error_string);
} }
@ -367,7 +367,8 @@ void emu_options::parse_standard_inis(astring &error_string)
const game_driver *emu_options::system() const const game_driver *emu_options::system() const
{ {
astring tempstr; astring tempstr;
return driver_get_name(*core_filename_extract_base(&tempstr, system_name(), TRUE)); int index = driver_list::find(*core_filename_extract_base(&tempstr, system_name(), TRUE));
return (index != -1) ? &driver_list::driver(index) : NULL;
} }

View File

@ -245,6 +245,37 @@ private:
}; };
// ======================> simple_list_wrapper
// a simple_list_wrapper wraps an existing object with a next pointer so it
// can live in a simple_list without requiring the object to have a next
// pointer
template<class T>
class simple_list_wrapper
{
public:
// construction/destruction
simple_list_wrapper(T *object)
: m_next(NULL),
m_object(object) { }
// operators
operator T *() { return m_object; }
operator T *() const { return m_object; }
T *operator *() { return m_object; }
T *operator *() const { return m_object; }
// getters
simple_list_wrapper *next() const { return m_next; }
T *object() const { return m_object; }
private:
// internal state
simple_list_wrapper * m_next;
T * m_object;
};
// ======================> fixed_allocator // ======================> fixed_allocator
// a fixed_allocator is a simple class that maintains a free pool of objects // a fixed_allocator is a simple class that maintains a free pool of objects

View File

@ -593,7 +593,7 @@ bool hash_collection::remove(char type)
// crc - return the CRC hash if present // crc - return the CRC hash if present
//------------------------------------------------- //-------------------------------------------------
bool hash_collection::crc(UINT32 &result) bool hash_collection::crc(UINT32 &result) const
{ {
// attempt to find the CRC hash; if we fail, return false // attempt to find the CRC hash; if we fail, return false
hash_base *crchash = hash(HASH_CRC); hash_base *crchash = hash(HASH_CRC);
@ -601,7 +601,7 @@ bool hash_collection::crc(UINT32 &result)
return false; return false;
// downcast to a hash_crc and convert to a UINT32 // downcast to a hash_crc and convert to a UINT32
result = *downcast<hash_crc *>(crchash); result = *downcast<const hash_crc *>(crchash);
return true; return true;
} }

View File

@ -161,7 +161,7 @@ public:
bool remove(char type); bool remove(char type);
// CRC-specific helpers // CRC-specific helpers
bool crc(UINT32 &result); bool crc(UINT32 &result) const;
hash_base *add_crc(UINT32 crc); hash_base *add_crc(UINT32 crc);
// string conversion // string conversion

File diff suppressed because it is too large Load Diff

View File

@ -4,8 +4,36 @@
Dumps the MAME internal data as an XML file. Dumps the MAME internal data as an XML file.
Copyright Nicola Salmoria and the MAME Team. ****************************************************************************
Visit http://mamedev.org for licensing and usage restrictions.
Copyright Aaron Giles
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are
met:
* Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in
the documentation and/or other materials provided with the
distribution.
* Neither the name 'MAME' nor the names of its contributors may be
used to endorse or promote products derived from this software
without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY AARON GILES ''AS IS'' AND ANY EXPRESS OR
IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL AARON GILES BE LIABLE FOR ANY DIRECT,
INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
POSSIBILITY OF SUCH DAMAGE.
***************************************************************************/ ***************************************************************************/
@ -15,12 +43,47 @@
#define __INFO_H__ #define __INFO_H__
/*************************************************************************** //**************************************************************************
FUNCTION PROTOTYPES // FUNCTION PROTOTYPES
***************************************************************************/ //**************************************************************************
/* print the MAME database in XML format */ // helper class to putput
void print_mame_xml(FILE* out, const game_driver* const games[], const char *gamename, emu_options &options); class info_xml_creator
{
public:
// construction/destruction
info_xml_creator(driver_enumerator &drivlist);
// output
void output(FILE *out);
private:
// internal helper
void output_one();
void output_sampleof();
void output_bios();
void output_rom();
void output_sample();
void output_chips();
void output_display();
void output_sound();
void output_input(const ioport_list &portlist);
void output_switches(const ioport_list &portlist, int type, const char *outertag, const char *innertag);
void output_adjusters(const ioport_list &portlist);
void output_categories(const ioport_list &portlist);
void output_driver();
void output_images();
void output_software_list();
void output_ramoptions();
const char *get_merge_name(const hash_collection &romhashes);
// internal state
FILE * m_output;
driver_enumerator & m_drivlist;
static const char s_dtd_string[];
};
#endif /* __INFO_H__ */ #endif /* __INFO_H__ */

View File

@ -943,8 +943,17 @@ driver_device_config_base::driver_device_config_base(const machine_config &mconf
void driver_device_config_base::static_set_game(device_config *device, const game_driver *game) void driver_device_config_base::static_set_game(device_config *device, const game_driver *game)
{ {
downcast<driver_device_config_base *>(device)->m_system = game; driver_device_config_base *base = downcast<driver_device_config_base *>(device);
downcast<driver_device_config_base *>(device)->m_shortname = game->name;
base->m_system = game;
// set the short name to the game's name
base->m_shortname = game->name;
// and set the search path to include all parents
base->m_searchpath = game->name;
for (int parent = driver_list::clone(*game); parent != -1; parent = driver_list::clone(parent))
base->m_searchpath.cat(";").cat(driver_list::driver(parent).name);
} }

View File

@ -157,7 +157,7 @@ int mame_execute(emu_options &options, osd_interface &osd)
const game_driver *system = options.system(); const game_driver *system = options.system();
if (system == NULL) if (system == NULL)
{ {
system = &GAME_NAME(empty); system = &GAME_NAME(___empty);
if (firstgame) if (firstgame)
started_empty = true; started_empty = true;
} }

View File

@ -1642,10 +1642,10 @@ void render_target::load_layout_files(const char *layoutfile, bool singlefile)
load_layout_file(NULL, m_manager.machine().config().m_default_layout); load_layout_file(NULL, m_manager.machine().config().m_default_layout);
// try to load another file based on the parent driver name // try to load another file based on the parent driver name
const game_driver *cloneof = driver_get_clone(&system); int cloneof = driver_list::clone(system);
if (cloneof != NULL) if (cloneof != -1)
if (!load_layout_file(cloneof->name, cloneof->name)) if (!load_layout_file(driver_list::driver(cloneof).name, driver_list::driver(cloneof).name))
load_layout_file(cloneof->name, "default"); load_layout_file(driver_list::driver(cloneof).name, "default");
// now do the built-in layouts for single-screen games // now do the built-in layouts for single-screen games
if (m_manager.machine().m_devicelist.count(SCREEN) == 1) if (m_manager.machine().m_devicelist.count(SCREEN) == 1)

View File

@ -117,6 +117,10 @@
#include "lcd.lh" #include "lcd.lh"
#include "lcd_rot.lh" #include "lcd_rot.lh"
// generic dummy pinball layout
#include "pinball.lh"
//************************************************************************** //**************************************************************************
// CONSTANTS // CONSTANTS

View File

@ -614,7 +614,6 @@ static int open_rom_file(rom_load_data *romdata, const char *regiontag, const ro
{ {
file_error filerr = FILERR_NOT_FOUND; file_error filerr = FILERR_NOT_FOUND;
UINT32 romsize = rom_file_size(romp); UINT32 romsize = rom_file_size(romp);
const game_driver *drv;
/* update status display */ /* update status display */
display_loading_rom_message(romdata, ROM_GETNAME(romp)); display_loading_rom_message(romdata, ROM_GETNAME(romp));
@ -626,9 +625,8 @@ static int open_rom_file(rom_load_data *romdata, const char *regiontag, const ro
/* attempt reading up the chain through the parents. It automatically also /* attempt reading up the chain through the parents. It automatically also
attempts any kind of load by checksum supported by the archives. */ attempts any kind of load by checksum supported by the archives. */
romdata->file = NULL; romdata->file = NULL;
for (drv = &romdata->machine().system(); romdata->file == NULL && drv != NULL; drv = driver_get_clone(drv)) for (int drv = driver_list::find(romdata->machine().system()); romdata->file == NULL && drv != -1; drv = driver_list::clone(drv))
if (drv->name != NULL && *drv->name != 0) filerr = common_process_file(romdata->machine().options(), driver_list::driver(drv).name, has_crc, crc, romp, &romdata->file);
filerr = common_process_file(romdata->machine().options(), drv->name, has_crc, crc, romp, &romdata->file);
/* if the region is load by name, load the ROM from there */ /* if the region is load by name, load the ROM from there */
if (romdata->file == NULL && regiontag != NULL) if (romdata->file == NULL && regiontag != NULL)
@ -1007,7 +1005,6 @@ static void process_rom_entries(rom_load_data *romdata, const char *regiontag, c
chd_error open_disk_image(emu_options &options, const game_driver *gamedrv, const rom_entry *romp, emu_file **image_file, chd_file **image_chd, const char *locationtag) chd_error open_disk_image(emu_options &options, const game_driver *gamedrv, const rom_entry *romp, emu_file **image_file, chd_file **image_chd, const char *locationtag)
{ {
const game_driver *drv, *searchdrv;
const rom_entry *region, *rom; const rom_entry *region, *rom;
const rom_source *source; const rom_source *source;
file_error filerr; file_error filerr;
@ -1018,8 +1015,8 @@ chd_error open_disk_image(emu_options &options, const game_driver *gamedrv, cons
/* attempt to open the properly named file, scanning up through parent directories */ /* attempt to open the properly named file, scanning up through parent directories */
filerr = FILERR_NOT_FOUND; filerr = FILERR_NOT_FOUND;
for (searchdrv = gamedrv; searchdrv != NULL && filerr != FILERR_NONE; searchdrv = driver_get_clone(searchdrv)) for (int searchdrv = driver_list::find(*gamedrv); searchdrv != -1 && filerr != FILERR_NONE; searchdrv = driver_list::clone(searchdrv))
filerr = common_process_file(options, searchdrv->name, ".chd", romp, image_file); filerr = common_process_file(options, driver_list::driver(searchdrv).name, ".chd", romp, image_file);
if (filerr != FILERR_NONE) if (filerr != FILERR_NONE)
filerr = common_process_file(options, NULL, ".chd", romp, image_file); filerr = common_process_file(options, NULL, ".chd", romp, image_file);
@ -1114,9 +1111,9 @@ chd_error open_disk_image(emu_options &options, const game_driver *gamedrv, cons
/* otherwise, look at our parents for a CHD with an identical checksum */ /* otherwise, look at our parents for a CHD with an identical checksum */
/* and try to open that */ /* and try to open that */
hash_collection romphashes(ROM_GETHASHDATA(romp)); hash_collection romphashes(ROM_GETHASHDATA(romp));
for (drv = gamedrv; drv != NULL; drv = driver_get_clone(drv)) for (int drv = driver_list::find(*gamedrv); drv != -1; drv = driver_list::clone(drv))
{ {
machine_config config(*drv, options); machine_config config(driver_list::driver(drv), options);
for (source = rom_first_source(config); source != NULL; source = rom_next_source(*source)) for (source = rom_first_source(config); source != NULL; source = rom_next_source(*source))
for (region = rom_first_region(*source); region != NULL; region = rom_next_region(region)) for (region = rom_first_region(*source); region != NULL; region = rom_next_region(region))
if (ROMREGION_ISDISKDATA(region)) if (ROMREGION_ISDISKDATA(region))
@ -1128,8 +1125,8 @@ chd_error open_disk_image(emu_options &options, const game_driver *gamedrv, cons
{ {
/* attempt to open the properly named file, scanning up through parent directories */ /* attempt to open the properly named file, scanning up through parent directories */
filerr = FILERR_NOT_FOUND; filerr = FILERR_NOT_FOUND;
for (searchdrv = drv; searchdrv != NULL && filerr != FILERR_NONE; searchdrv = driver_get_clone(searchdrv)) for (int searchdrv = drv; searchdrv != -1 && filerr != FILERR_NONE; searchdrv = driver_list::clone(searchdrv))
filerr = common_process_file(options, searchdrv->name, ".chd", rom, image_file); filerr = common_process_file(options, driver_list::driver(searchdrv).name, ".chd", rom, image_file);
if (filerr != FILERR_NONE) if (filerr != FILERR_NONE)
filerr = common_process_file(options, NULL, ".chd", rom, image_file); filerr = common_process_file(options, NULL, ".chd", rom, image_file);

View File

@ -107,13 +107,12 @@ ROM_END
//------------------------------------------------- //-------------------------------------------------
bsmt2000_device_config::bsmt2000_device_config(const machine_config &mconfig, const char *tag, const device_config *owner, UINT32 clock) bsmt2000_device_config::bsmt2000_device_config(const machine_config &mconfig, const char *tag, const device_config *owner, UINT32 clock)
: device_config(mconfig, static_alloc_device_config, "BSMT2000", tag, owner, clock), : device_config(mconfig, static_alloc_device_config, "BSMT2000", "bsmt2000", tag, owner, clock),
device_config_sound_interface(mconfig, *this), device_config_sound_interface(mconfig, *this),
device_config_memory_interface(mconfig, *this), device_config_memory_interface(mconfig, *this),
m_space_config("samples", ENDIANNESS_LITTLE, 8, 32, 0, NULL, *ADDRESS_MAP_NAME(bsmt2000)), m_space_config("samples", ENDIANNESS_LITTLE, 8, 32, 0, NULL, *ADDRESS_MAP_NAME(bsmt2000)),
m_ready_callback(NULL) m_ready_callback(NULL)
{ {
m_shortname = "bsmt2000";
} }

View File

@ -126,7 +126,7 @@ void wav_add_data_32(wav_file *wav, INT32 *data, int samples, int shift)
if (!wav) return; if (!wav) return;
/* allocate temp memory */ /* allocate temp memory */
temp = (INT16 *)osd_malloc(samples * sizeof(temp[0])); temp = (INT16 *)osd_malloc_array(samples * sizeof(temp[0]));
if (!temp) if (!temp)
return; return;
@ -154,7 +154,7 @@ void wav_add_data_16lr(wav_file *wav, INT16 *left, INT16 *right, int samples)
if (!wav) return; if (!wav) return;
/* allocate temp memory */ /* allocate temp memory */
temp = (INT16 *)osd_malloc(samples * 2 * sizeof(temp[0])); temp = (INT16 *)osd_malloc_array(samples * 2 * sizeof(temp[0]));
if (!temp) if (!temp)
return; return;
@ -179,7 +179,7 @@ void wav_add_data_32lr(wav_file *wav, INT32 *left, INT32 *right, int samples, in
if (!wav) return; if (!wav) return;
/* allocate temp memory */ /* allocate temp memory */
temp = (INT16 *)osd_malloc(samples * 2 * sizeof(temp[0])); temp = (INT16 *)osd_malloc_array(samples * 2 * sizeof(temp[0]));
if (!temp) if (!temp)
return; return;

View File

@ -280,7 +280,7 @@ int ui_display_startup_screens(running_machine &machine, int first_time, int sho
/* disable everything if we are using -str for 300 or fewer seconds, or if we're the empty driver, /* disable everything if we are using -str for 300 or fewer seconds, or if we're the empty driver,
or if we are debugging */ or if we are debugging */
if (!first_time || (str > 0 && str < 60*5) || &machine.system() == &GAME_NAME(empty) || (machine.debug_flags & DEBUG_FLAG_ENABLED) != 0) if (!first_time || (str > 0 && str < 60*5) || &machine.system() == &GAME_NAME(___empty) || (machine.debug_flags & DEBUG_FLAG_ENABLED) != 0)
show_gameinfo = show_warnings = show_disclaimer = FALSE; show_gameinfo = show_warnings = show_disclaimer = FALSE;
/* initialize the on-screen display system */ /* initialize the on-screen display system */
@ -907,8 +907,6 @@ static astring &warnings_string(running_machine &machine, astring &string)
GAME_IMPERFECT_GRAPHICS | \ GAME_IMPERFECT_GRAPHICS | \
GAME_NO_COCKTAIL) GAME_NO_COCKTAIL)
int i;
string.reset(); string.reset();
/* if no warnings, nothing to return */ /* if no warnings, nothing to return */
@ -955,10 +953,6 @@ static astring &warnings_string(running_machine &machine, astring &string)
/* if there's a NOT WORKING, UNEMULATED PROTECTION or GAME MECHANICAL warning, make it stronger */ /* if there's a NOT WORKING, UNEMULATED PROTECTION or GAME MECHANICAL warning, make it stronger */
if (machine.system().flags & (GAME_NOT_WORKING | GAME_UNEMULATED_PROTECTION | GAME_MECHANICAL)) if (machine.system().flags & (GAME_NOT_WORKING | GAME_UNEMULATED_PROTECTION | GAME_MECHANICAL))
{ {
const game_driver *maindrv;
const game_driver *clone_of;
int foundworking;
/* add the strings for these warnings */ /* add the strings for these warnings */
if (machine.system().flags & GAME_UNEMULATED_PROTECTION) if (machine.system().flags & GAME_UNEMULATED_PROTECTION)
string.cat("The game has protection which isn't fully emulated.\n"); string.cat("The game has protection which isn't fully emulated.\n");
@ -970,25 +964,25 @@ static astring &warnings_string(running_machine &machine, astring &string)
"It is not possible to fully play this " GAMENOUN ".\n"); "It is not possible to fully play this " GAMENOUN ".\n");
/* find the parent of this driver */ /* find the parent of this driver */
clone_of = driver_get_clone(&machine.system()); driver_enumerator drivlist(machine.options());
if (clone_of != NULL && !(clone_of->flags & GAME_IS_BIOS_ROOT)) int maindrv = drivlist.find(machine.system());
int clone_of = drivlist.non_bios_clone(maindrv);
if (clone_of != -1)
maindrv = clone_of; maindrv = clone_of;
else
maindrv = &machine.system();
/* scan the driver list for any working clones and add them */ /* scan the driver list for any working clones and add them */
foundworking = FALSE; bool foundworking = false;
for (i = 0; drivers[i] != NULL; i++) while (drivlist.next())
if (drivers[i] == maindrv || driver_get_clone(drivers[i]) == maindrv) if (drivlist.current() == maindrv || drivlist.clone() == maindrv)
if ((drivers[i]->flags & (GAME_NOT_WORKING | GAME_UNEMULATED_PROTECTION | GAME_MECHANICAL)) == 0) if ((drivlist.driver().flags & (GAME_NOT_WORKING | GAME_UNEMULATED_PROTECTION | GAME_MECHANICAL)) == 0)
{ {
/* this one works, add a header and display the name of the clone */ /* this one works, add a header and display the name of the clone */
if (!foundworking) if (!foundworking)
string.cat("\n\nThere are working clones of this game: "); string.cat("\n\nThere are working clones of this game: ");
else else
string.cat(", "); string.cat(", ");
string.cat(drivers[i]->name); string.cat(drivlist.driver().name);
foundworking = TRUE; foundworking = true;
} }
if (foundworking) if (foundworking)

View File

@ -208,7 +208,7 @@ struct _select_game_state
UINT8 error; UINT8 error;
UINT8 rerandomize; UINT8 rerandomize;
char search[40]; char search[40];
const game_driver * matchlist[VISIBLE_GAMES_IN_LIST]; int matchlist[VISIBLE_GAMES_IN_LIST];
const game_driver * driverlist[1]; const game_driver * driverlist[1];
}; };
@ -245,6 +245,9 @@ static const char priortext[] = "Return to Prior Menu";
static const char backtext[] = "Return to " CAPSTARTGAMENOUN; static const char backtext[] = "Return to " CAPSTARTGAMENOUN;
static const char exittext[] = "Exit"; static const char exittext[] = "Exit";
// temporary hack until this is C++-ified
static driver_enumerator *drivlist;
/*************************************************************************** /***************************************************************************
@ -299,7 +302,6 @@ static void menu_crosshair_populate(running_machine &machine, ui_menu *menu);
static void menu_quit_game(running_machine &machine, ui_menu *menu, void *parameter, void *state); static void menu_quit_game(running_machine &machine, ui_menu *menu, void *parameter, void *state);
static void menu_select_game(running_machine &machine, ui_menu *menu, void *parameter, void *state); static void menu_select_game(running_machine &machine, ui_menu *menu, void *parameter, void *state);
static void menu_select_game_populate(running_machine &machine, ui_menu *menu, select_game_state *menustate); static void menu_select_game_populate(running_machine &machine, ui_menu *menu, select_game_state *menustate);
static int CLIB_DECL menu_select_game_driver_compare(const void *elem1, const void *elem2);
static void menu_select_game_build_driver_list(ui_menu *menu, select_game_state *menustate); static void menu_select_game_build_driver_list(ui_menu *menu, select_game_state *menustate);
static void menu_select_game_custom_render(running_machine &machine, ui_menu *menu, void *state, void *selectedref, float top, float bottom, float x, float y, float x2, float y2); static void menu_select_game_custom_render(running_machine &machine, ui_menu *menu, void *state, void *selectedref, float top, float bottom, float x, float y, float x2, float y2);
@ -3426,9 +3428,10 @@ static void menu_select_game(running_machine &machine, ui_menu *menu, void *para
/* if no state, allocate some */ /* if no state, allocate some */
if (state == NULL) if (state == NULL)
{ {
state = ui_menu_alloc_state(menu, sizeof(*menustate) + sizeof(menustate->driverlist) * driver_list_get_count(drivers), NULL); state = ui_menu_alloc_state(menu, sizeof(*menustate) + sizeof(menustate->driverlist) * driver_list::total(), NULL);
if (parameter != NULL) if (parameter != NULL)
strcpy(((select_game_state *)state)->search, (const char *)parameter); strcpy(((select_game_state *)state)->search, (const char *)parameter);
((select_game_state *)state)->matchlist[0] = -1;
} }
menustate = (select_game_state *)state; menustate = (select_game_state *)state;
@ -3459,24 +3462,20 @@ static void menu_select_game(running_machine &machine, ui_menu *menu, void *para
/* anything else is a driver */ /* anything else is a driver */
else else
{ {
audit_record *audit; // audit the game first to see if we're going to work
int audit_records; driver_enumerator enumerator(machine.options(), *driver);
int audit_result; enumerator.next();
media_auditor auditor(enumerator);
media_auditor::summary summary = auditor.audit_media(AUDIT_VALIDATE_FAST);
/* audit the game first to see if we're going to work */ // if everything looks good, schedule the new driver
audit_records = audit_images(menu->machine().options(), driver, AUDIT_VALIDATE_FAST, &audit); if (summary == media_auditor::CORRECT || summary == media_auditor::BEST_AVAILABLE)
audit_result = audit_summary(driver, audit_records, audit, FALSE);
if (audit_records > 0)
global_free(audit);
/* if everything looks good, schedule the new driver */
if (audit_result == CORRECT || audit_result == BEST_AVAILABLE)
{ {
machine.schedule_new_driver(*driver); machine.schedule_new_driver(*driver);
ui_menu_stack_reset(machine); ui_menu_stack_reset(machine);
} }
/* otherwise, display an error */ // otherwise, display an error
else else
{ {
ui_menu_reset(menu, UI_MENU_RESET_REMEMBER_REF); ui_menu_reset(menu, UI_MENU_RESET_REMEMBER_REF);
@ -3551,18 +3550,19 @@ static void menu_select_game_populate(running_machine &machine, ui_menu *menu, s
} }
/* otherwise, rebuild the match list */ /* otherwise, rebuild the match list */
if (menustate->search[0] != 0 || menustate->matchlist[0] == NULL || menustate->rerandomize) assert(drivlist != NULL);
driver_list_get_approx_matches(menustate->driverlist, menustate->search, matchcount, menustate->matchlist); if (menustate->search[0] != 0 || menustate->matchlist[0] == -1 || menustate->rerandomize)
drivlist->find_approximate_matches(menustate->search, matchcount, menustate->matchlist);
menustate->rerandomize = FALSE; menustate->rerandomize = FALSE;
/* iterate over entries */ /* iterate over entries */
for (curitem = 0; curitem < matchcount; curitem++) for (curitem = 0; curitem < matchcount; curitem++)
{ {
const game_driver *driver = menustate->matchlist[curitem]; int curmatch = menustate->matchlist[curitem];
if (driver != NULL) if (curmatch != -1)
{ {
const game_driver *cloneof = driver_get_clone(driver); int cloneof = drivlist->non_bios_clone(curmatch);
ui_menu_item_append(menu, driver->name, driver->description, (cloneof == NULL || (cloneof->flags & GAME_IS_BIOS_ROOT)) ? 0 : MENU_FLAG_INVERT, (void *)driver); ui_menu_item_append(menu, drivlist->driver(curmatch).name, drivlist->driver(curmatch).description, (cloneof == -1) ? 0 : MENU_FLAG_INVERT, (void *)&drivlist->driver(curmatch));
} }
} }
@ -3578,24 +3578,6 @@ static void menu_select_game_populate(running_machine &machine, ui_menu *menu, s
} }
/*-------------------------------------------------
menu_select_game_driver_compare - compare the
names of two drivers
-------------------------------------------------*/
static int CLIB_DECL menu_select_game_driver_compare(const void *elem1, const void *elem2)
{
const game_driver **driver1_ptr = (const game_driver **)elem1;
const game_driver **driver2_ptr = (const game_driver **)elem2;
const char *driver1 = (*driver1_ptr)->name;
const char *driver2 = (*driver2_ptr)->name;
while (*driver1 == *driver2 && *driver1 != 0)
driver1++, driver2++;
return *driver1 - *driver2;
}
/*------------------------------------------------- /*-------------------------------------------------
menu_select_game_build_driver_list - build a menu_select_game_build_driver_list - build a
list of available drivers list of available drivers
@ -3603,17 +3585,11 @@ static int CLIB_DECL menu_select_game_driver_compare(const void *elem1, const vo
static void menu_select_game_build_driver_list(ui_menu *menu, select_game_state *menustate) static void menu_select_game_build_driver_list(ui_menu *menu, select_game_state *menustate)
{ {
int driver_count = driver_list_get_count(drivers); // start with an empty list
int drivnum, listnum; // hack alert: use new directly here to avoid reporting this one-time static memory as unfreed
UINT8 *found; if (drivlist == NULL)
drivlist = new driver_enumerator(menu->machine().options());
/* create a sorted copy of the main driver list */ drivlist->exclude_all();
memcpy((void *)menustate->driverlist, drivers, driver_count * sizeof(menustate->driverlist[0]));
qsort((void *)menustate->driverlist, driver_count, sizeof(menustate->driverlist[0]), menu_select_game_driver_compare);
/* allocate a temporary array to track which ones we found */
found = (UINT8 *)ui_menu_pool_alloc(menu, (driver_count + 7) / 8);
memset(found, 0, (driver_count + 7) / 8);
/* open a path to the ROMs and find them in the array */ /* open a path to the ROMs and find them in the array */
file_enumerator path(menu->machine().options().media_path()); file_enumerator path(menu->machine().options().media_path());
@ -3622,9 +3598,6 @@ static void menu_select_game_build_driver_list(ui_menu *menu, select_game_state
/* iterate while we get new objects */ /* iterate while we get new objects */
while ((dir = path.next()) != NULL) while ((dir = path.next()) != NULL)
{ {
game_driver tempdriver;
game_driver *tempdriver_ptr;
const game_driver **found_driver;
char drivername[50]; char drivername[50];
char *dst = drivername; char *dst = drivername;
const char *src; const char *src;
@ -3634,23 +3607,16 @@ static void menu_select_game_build_driver_list(ui_menu *menu, select_game_state
*dst++ = tolower((UINT8)*src); *dst++ = tolower((UINT8)*src);
*dst = 0; *dst = 0;
/* find it in the array */ int drivnum = drivlist->find(drivername);
tempdriver.name = drivername; if (drivnum != -1)
tempdriver_ptr = &tempdriver; drivlist->include(drivnum);
found_driver = (const game_driver **)bsearch(&tempdriver_ptr, menustate->driverlist, driver_count, sizeof(*menustate->driverlist), menu_select_game_driver_compare);
/* if found, mark the corresponding entry in the array */
if (found_driver != NULL)
{
int index = found_driver - menustate->driverlist;
found[index / 8] |= 1 << (index % 8);
}
} }
/* now build the final list */ /* now build the final list */
for (drivnum = listnum = 0; drivnum < driver_count; drivnum++) drivlist->reset();
if (found[drivnum / 8] & (1 << (drivnum % 8))) int listnum = 0;
menustate->driverlist[listnum++] = menustate->driverlist[drivnum]; while (drivlist->next())
menustate->driverlist[listnum++] = &drivlist->driver();
/* NULL-terminate */ /* NULL-terminate */
menustate->driverlist[listnum] = NULL; menustate->driverlist[listnum] = NULL;

View File

@ -314,12 +314,11 @@ static bool validate_inlines(void)
information information
-------------------------------------------------*/ -------------------------------------------------*/
static bool validate_driver(const machine_config &config, game_driver_map &names, game_driver_map &descriptions) static bool validate_driver(driver_enumerator &drivlist, game_driver_map &names, game_driver_map &descriptions)
{ {
const game_driver &driver = config.gamedrv(); const game_driver &driver = drivlist.driver();
const game_driver *clone_of; const machine_config &config = drivlist.config();
const char *compatible_with; const char *compatible_with;
const game_driver *other_drv;
bool error = FALSE, is_clone; bool error = FALSE, is_clone;
const char *s; const char *s;
@ -343,27 +342,27 @@ static bool validate_driver(const machine_config &config, game_driver_map &names
/* determine the clone */ /* determine the clone */
is_clone = (strcmp(driver.parent, "0") != 0); is_clone = (strcmp(driver.parent, "0") != 0);
clone_of = driver_get_clone(&driver); int clone_of = drivlist.clone(driver);
if (clone_of && (clone_of->flags & GAME_IS_BIOS_ROOT)) if (clone_of != -1 && (drivlist.driver(clone_of).flags & GAME_IS_BIOS_ROOT))
is_clone = false; is_clone = false;
/* if we have at least 100 drivers, validate the clone */ /* if we have at least 100 drivers, validate the clone */
/* (100 is arbitrary, but tries to avoid tiny.mak dependencies) */ /* (100 is arbitrary, but tries to avoid tiny.mak dependencies) */
if (driver_list_get_count(drivers) > 100 && !clone_of && is_clone) if (driver_list::total() > 100 && clone_of == -1 && is_clone)
{ {
mame_printf_error("%s: %s is a non-existant clone\n", driver.source_file, driver.parent); mame_printf_error("%s: %s is a non-existant clone\n", driver.source_file, driver.parent);
error = true; error = true;
} }
/* look for recursive cloning */ /* look for recursive cloning */
if (clone_of == &driver) if (clone_of != -1 && &drivlist.driver(clone_of) == &driver)
{ {
mame_printf_error("%s: %s is set as a clone of itself\n", driver.source_file, driver.name); mame_printf_error("%s: %s is set as a clone of itself\n", driver.source_file, driver.name);
error = true; error = true;
} }
/* look for clones that are too deep */ /* look for clones that are too deep */
if (clone_of != NULL && (clone_of = driver_get_clone(clone_of)) != NULL && (clone_of->flags & GAME_IS_BIOS_ROOT) == 0) if (clone_of != -1 && (clone_of = drivlist.non_bios_clone(clone_of)) != -1)
{ {
mame_printf_error("%s: %s is a clone of a clone\n", driver.source_file, driver.name); mame_printf_error("%s: %s is a clone of a clone\n", driver.source_file, driver.name);
error = true; error = true;
@ -392,23 +391,23 @@ static bool validate_driver(const machine_config &config, game_driver_map &names
compatible_with = NULL; compatible_with = NULL;
/* check for this driver being compatible with a non-existant driver */ /* check for this driver being compatible with a non-existant driver */
if ((compatible_with != NULL) && (driver_get_name(driver.compatible_with) == NULL)) if ((compatible_with != NULL) && (drivlist.find(driver.compatible_with) == -1))
{ {
mame_printf_error("%s: is compatible with %s, which is not in drivers[]\n", driver.name, driver.compatible_with); mame_printf_error("%s: is compatible with %s, which is not in drivers[]\n", driver.name, driver.compatible_with);
error = true; error = true;
} }
/* check for clone_of and compatible_with being specified at the same time */ /* check for clone_of and compatible_with being specified at the same time */
if ((driver_get_clone(&driver) != NULL) && (compatible_with != NULL)) if ((drivlist.clone(driver) != -1) && (compatible_with != NULL))
{ {
mame_printf_error("%s: both compatible_with and clone_of are specified\n", driver.name); mame_printf_error("%s: both compatible_with and clone_of are specified\n", driver.name);
error = true; error = true;
} }
/* find any recursive dependencies on the current driver */ /* find any recursive dependencies on the current driver */
for (other_drv = driver_get_compatible(&driver); other_drv != NULL; other_drv = driver_get_compatible(other_drv)) for (int other_drv = drivlist.compatible_with(driver); other_drv != -1; other_drv = drivlist.compatible_with(other_drv))
{ {
if (&driver == other_drv) if (&driver == &drivlist.driver(other_drv))
{ {
mame_printf_error("%s: recursive compatibility\n", driver.name); mame_printf_error("%s: recursive compatibility\n", driver.name);
error = true; error = true;
@ -432,9 +431,10 @@ static bool validate_driver(const machine_config &config, game_driver_map &names
validate_roms - validate ROM definitions validate_roms - validate ROM definitions
-------------------------------------------------*/ -------------------------------------------------*/
static bool validate_roms(const machine_config &config, region_array *rgninfo, game_driver_map &roms) static bool validate_roms(driver_enumerator &drivlist, region_array *rgninfo, game_driver_map &roms)
{ {
const game_driver &driver = config.gamedrv(); const game_driver &driver = drivlist.driver();
const machine_config &config = drivlist.config();
int bios_flags = 0, last_bios = 0; int bios_flags = 0, last_bios = 0;
const char *last_rgnname = "???"; const char *last_rgnname = "???";
const char *last_name = "???"; const char *last_name = "???";
@ -579,9 +579,10 @@ static bool validate_roms(const machine_config &config, region_array *rgninfo, g
configurations configurations
-------------------------------------------------*/ -------------------------------------------------*/
static bool validate_display(const machine_config &config) static bool validate_display(driver_enumerator &drivlist)
{ {
const game_driver &driver = config.gamedrv(); const game_driver &driver = drivlist.driver();
const machine_config &config = drivlist.config();
bool palette_modes = false; bool palette_modes = false;
bool error = false; bool error = false;
@ -605,9 +606,10 @@ static bool validate_display(const machine_config &config)
configuration configuration
-------------------------------------------------*/ -------------------------------------------------*/
static bool validate_gfx(const machine_config &config, region_array *rgninfo) static bool validate_gfx(driver_enumerator &drivlist, region_array *rgninfo)
{ {
const game_driver &driver = config.gamedrv(); const game_driver &driver = drivlist.driver();
const machine_config &config = drivlist.config();
bool error = false; bool error = false;
int gfxnum; int gfxnum;
@ -939,12 +941,13 @@ static void validate_dip_settings(const input_field_config *field, const game_dr
validate_inputs - validate input configuration validate_inputs - validate input configuration
-------------------------------------------------*/ -------------------------------------------------*/
static bool validate_inputs(const machine_config &config, int_map &defstr_map, ioport_list &portlist) static bool validate_inputs(driver_enumerator &drivlist, int_map &defstr_map, ioport_list &portlist)
{ {
const input_port_config *scanport; const input_port_config *scanport;
const input_port_config *port; const input_port_config *port;
const input_field_config *field; const input_field_config *field;
const game_driver &driver = config.gamedrv(); const game_driver &driver = drivlist.driver();
const machine_config &config = drivlist.config();
int empty_string_found = FALSE; int empty_string_found = FALSE;
char errorbuf[1024]; char errorbuf[1024];
bool error = false; bool error = false;
@ -1088,10 +1091,11 @@ static bool validate_inputs(const machine_config &config, int_map &defstr_map, i
checks checks
-------------------------------------------------*/ -------------------------------------------------*/
static bool validate_devices(const machine_config &config, const ioport_list &portlist, region_array *rgninfo) static bool validate_devices(driver_enumerator &drivlist, const ioport_list &portlist, region_array *rgninfo)
{ {
bool error = false; bool error = false;
const game_driver &driver = config.gamedrv(); const game_driver &driver = drivlist.driver();
const machine_config &config = drivlist.config();
for (const device_config *devconfig = config.m_devicelist.first(); devconfig != NULL; devconfig = devconfig->next()) for (const device_config *devconfig = config.m_devicelist.first(); devconfig != NULL; devconfig = devconfig->next())
{ {
@ -1126,7 +1130,6 @@ static bool validate_devices(const machine_config &config, const ioport_list &po
void validate_drivers(emu_options &options, const game_driver *curdriver) void validate_drivers(emu_options &options, const game_driver *curdriver)
{ {
osd_ticks_t prep = 0; osd_ticks_t prep = 0;
osd_ticks_t expansion = 0;
osd_ticks_t driver_checks = 0; osd_ticks_t driver_checks = 0;
osd_ticks_t rom_checks = 0; osd_ticks_t rom_checks = 0;
osd_ticks_t gfx_checks = 0; osd_ticks_t gfx_checks = 0;
@ -1186,9 +1189,10 @@ void validate_drivers(emu_options &options, const game_driver *curdriver)
prep += get_profile_ticks(); prep += get_profile_ticks();
/* iterate over all drivers */ /* iterate over all drivers */
for (int drivnum = 0; drivers[drivnum]; drivnum++) driver_enumerator drivlist(options);
while (drivlist.next())
{ {
const game_driver &driver = *drivers[drivnum]; const game_driver &driver = drivlist.driver();
ioport_list portlist; ioport_list portlist;
region_array rgninfo; region_array rgninfo;
@ -1198,39 +1202,34 @@ void validate_drivers(emu_options &options, const game_driver *curdriver)
try try
{ {
/* expand the machine driver */
expansion -= get_profile_ticks();
machine_config config(driver, options);
expansion += get_profile_ticks();
/* validate the driver entry */ /* validate the driver entry */
driver_checks -= get_profile_ticks(); driver_checks -= get_profile_ticks();
error = validate_driver(config, names, descriptions) || error; error = validate_driver(drivlist, names, descriptions) || error;
driver_checks += get_profile_ticks(); driver_checks += get_profile_ticks();
/* validate the ROM information */ /* validate the ROM information */
rom_checks -= get_profile_ticks(); rom_checks -= get_profile_ticks();
error = validate_roms(config, &rgninfo, roms) || error; error = validate_roms(drivlist, &rgninfo, roms) || error;
rom_checks += get_profile_ticks(); rom_checks += get_profile_ticks();
/* validate input ports */ /* validate input ports */
input_checks -= get_profile_ticks(); input_checks -= get_profile_ticks();
error = validate_inputs(config, defstr, portlist) || error; error = validate_inputs(drivlist, defstr, portlist) || error;
input_checks += get_profile_ticks(); input_checks += get_profile_ticks();
/* validate the display */ /* validate the display */
display_checks -= get_profile_ticks(); display_checks -= get_profile_ticks();
error = validate_display(config) || error; error = validate_display(drivlist) || error;
display_checks += get_profile_ticks(); display_checks += get_profile_ticks();
/* validate the graphics decoding */ /* validate the graphics decoding */
gfx_checks -= get_profile_ticks(); gfx_checks -= get_profile_ticks();
error = validate_gfx(config, &rgninfo) || error; error = validate_gfx(drivlist, &rgninfo) || error;
gfx_checks += get_profile_ticks(); gfx_checks += get_profile_ticks();
/* validate devices */ /* validate devices */
device_checks -= get_profile_ticks(); device_checks -= get_profile_ticks();
error = validate_devices(config, portlist, &rgninfo) || error; error = validate_devices(drivlist, portlist, &rgninfo) || error;
device_checks += get_profile_ticks(); device_checks += get_profile_ticks();
} }
catch (emu_fatalerror &err) catch (emu_fatalerror &err)
@ -1241,7 +1240,6 @@ void validate_drivers(emu_options &options, const game_driver *curdriver)
#if (REPORT_TIMES) #if (REPORT_TIMES)
mame_printf_info("Prep: %8dm\n", (int)(prep / 1000000)); mame_printf_info("Prep: %8dm\n", (int)(prep / 1000000));
mame_printf_info("Expansion: %8dm\n", (int)(expansion / 1000000));
mame_printf_info("Driver: %8dm\n", (int)(driver_checks / 1000000)); mame_printf_info("Driver: %8dm\n", (int)(driver_checks / 1000000));
mame_printf_info("ROM: %8dm\n", (int)(rom_checks / 1000000)); mame_printf_info("ROM: %8dm\n", (int)(rom_checks / 1000000));
mame_printf_info("CPU: %8dm\n", (int)(cpu_checks / 1000000)); mame_printf_info("CPU: %8dm\n", (int)(cpu_checks / 1000000));

View File

@ -318,6 +318,7 @@ public:
astring(const char *str1, const char *str2, const char *str3, const char *str4) { init().cpy(str1).cat(str2).cat(str3).cat(str4); } astring(const char *str1, const char *str2, const char *str3, const char *str4) { init().cpy(str1).cat(str2).cat(str3).cat(str4); }
astring(const char *str1, const char *str2, const char *str3, const char *str4, const char *str5) { init().cpy(str1).cat(str2).cat(str3).cat(str4).cat(str5); } astring(const char *str1, const char *str2, const char *str3, const char *str4, const char *str5) { init().cpy(str1).cat(str2).cat(str3).cat(str4).cat(str5); }
astring(const astring &string) { init().cpy(string); } astring(const astring &string) { init().cpy(string); }
astring(const astring &string, int start, int count = -1) { init().cpysubstr(string, start, count); }
astring &operator=(const char *string) { return cpy(string); } astring &operator=(const char *string) { return cpy(string); }
astring &operator=(const astring &string) { return cpy(string); } astring &operator=(const astring &string) { return cpy(string); }

View File

@ -141,7 +141,7 @@ char *core_strdup(const char *str)
char *cpy = NULL; char *cpy = NULL;
if (str != NULL) if (str != NULL)
{ {
cpy = (char *)osd_malloc(strlen(str) + 1); cpy = (char *)osd_malloc_array(strlen(str) + 1);
if (cpy != NULL) if (cpy != NULL)
strcpy(cpy, str); strcpy(cpy, str);
} }

View File

@ -130,7 +130,7 @@ static osd_shared_mem *osd_sharedmem_alloc(const char *path, int create, size_t
if (create) if (create)
{ {
char *buf = (char *) osd_malloc(size); char *buf = (char *) osd_malloc_array(size);
memset(buf,0, size); memset(buf,0, size);
fd = open(path, O_RDWR | O_CREAT, S_IRWXU); fd = open(path, O_RDWR | O_CREAT, S_IRWXU);
@ -147,7 +147,7 @@ static osd_shared_mem *osd_sharedmem_alloc(const char *path, int create, size_t
} }
os_shmem->creator = 0; os_shmem->creator = 0;
} }
os_shmem->fn = (char *) osd_malloc(strlen(path)+1); os_shmem->fn = (char *) osd_malloc_array(strlen(path)+1);
strcpy(os_shmem->fn, path); strcpy(os_shmem->fn, path);
assert(fd != -1); assert(fd != -1);
@ -178,7 +178,7 @@ static osd_shared_mem *osd_sharedmem_alloc(const char *path, int create, size_t
os_shmem->creator = 0; os_shmem->creator = 0;
os_shmem->ptr = (void *) osd_malloc(size); os_shmem->ptr = (void *) osd_malloc_array(size);
os_shmem->size = size; os_shmem->size = size;
return os_shmem; return os_shmem;
} }

View File

@ -1589,7 +1589,7 @@ static int megadrive_load_nonlist(device_image_interface &image)
else if ((rawROM[0x2080] == 'E') && (rawROM[0x2081] == 'A') && else if ((rawROM[0x2080] == 'E') && (rawROM[0x2081] == 'A') &&
(rawROM[0x2082] == 'M' || rawROM[0x2082] == 'G')) (rawROM[0x2082] == 'M' || rawROM[0x2082] == 'G'))
{ {
tmpROMnew = (unsigned char *)osd_malloc(length); tmpROMnew = global_alloc_array(unsigned char, length);
secondhalf = &tmpROMnew[length >> 1]; secondhalf = &tmpROMnew[length >> 1];
if (!tmpROMnew) if (!tmpROMnew)
@ -1605,7 +1605,7 @@ static int megadrive_load_nonlist(device_image_interface &image)
ROM[ptr] = secondhalf[ptr >> 1]; ROM[ptr] = secondhalf[ptr >> 1];
ROM[ptr + 1] = tmpROMnew[ptr >> 1]; ROM[ptr + 1] = tmpROMnew[ptr >> 1];
} }
free(tmpROMnew); global_free(tmpROMnew);
#ifdef LSB_FIRST #ifdef LSB_FIRST
for (ptr = 0; ptr < length; ptr += 2) for (ptr = 0; ptr < length; ptr += 2)

12225
src/mame/mame.lst Normal file

File diff suppressed because it is too large Load Diff

View File

@ -235,11 +235,6 @@ SOUNDS += MAS3507D
# the list of drivers # the list of drivers
#------------------------------------------------- #-------------------------------------------------
ifeq ($(TARGET),mame)
DRVLIBS += \
$(MAMEOBJ)/mamedriv.o
endif
DRVLIBS += \ DRVLIBS += \
$(MAMEOBJ)/alba.a \ $(MAMEOBJ)/alba.a \
$(MAMEOBJ)/alliedl.a \ $(MAMEOBJ)/alliedl.a \

File diff suppressed because it is too large Load Diff

View File

@ -1,70 +0,0 @@
/******************************************************************************
tiny.c
mamedriv.c substitute file for "tiny" MAME builds.
Copyright Nicola Salmoria and the MAME Team.
Visit http://mamedev.org for licensing and usage restrictions.
The list of used drivers. Drivers have to be included here to be recognized
by the executable.
To save some typing, we use a hack here. This file is recursively #included
twice, with different definitions of the DRIVER() macro. The first one
declares external references to the drivers; the second one builds an array
storing all the drivers.
******************************************************************************/
#include "emu.h"
#ifndef DRIVER_RECURSIVE
#define DRIVER_RECURSIVE
/* step 1: declare all external references */
#define DRIVER(NAME) GAME_EXTERN(NAME);
#include "tiny.c"
/* step 2: define the drivers[] array */
#undef DRIVER
#define DRIVER(NAME) &GAME_NAME(NAME),
const game_driver * const drivers[] =
{
#include "tiny.c"
0 /* end of array */
};
#else /* DRIVER_RECURSIVE */
DRIVER( robby ) /* (c) 1981 Bally Midway */
DRIVER( gridlee ) /* [1983 Videa] prototype - no copyright notice */
DRIVER( alienar ) /* (c) 1985 Duncan Brown */
DRIVER( carpolo ) /* (c) 1977 Exidy */
DRIVER( sidetrac ) /* (c) 1979 Exidy */
DRIVER( targ ) /* (c) 1980 Exidy */
DRIVER( spectar ) /* (c) 1980 Exidy */
DRIVER( teetert ) /* (c) 1982 Exidy */
DRIVER( hardhat ) /* (c) 1982 */
DRIVER( fax ) /* (c) 1983 */
DRIVER( fax2 ) /* (c) 1983 */
DRIVER( circus ) /* (c) 1977 Exidy */
DRIVER( robotbwl ) /* (c) 197? Exidy */
DRIVER( crash ) /* (c) 1979 Exidy */
DRIVER( ripcord ) /* (c) 1979 Exidy */
DRIVER( starfire ) /* (c) 1979 Exidy */
DRIVER( starfirea ) /* (c) 1979 Exidy */
DRIVER( fireone ) /* (c) 1979 Exidy */
DRIVER( starfir2 ) /* (c) 1979 Exidy */
DRIVER( victory ) /* (c) 1982 */
DRIVER( victorba ) /* (c) 1982 */
DRIVER( topgunnr ) /* (c) 1986 */
DRIVER( looping ) /* (c) 1982 Video Games GMBH */
DRIVER( supertnk ) /* (c) 1981 VIDEO GAMES GmbH, W.-GERMANY */
DRIVER( wrally ) /* (c) 1993 - Ref 930705 */
#endif /* DRIVER_RECURSIVE */

68
src/mame/tiny.lst Normal file
View File

@ -0,0 +1,68 @@
/******************************************************************************
tiny.lst
List of all enabled drivers in the system. This file is parsed by
makelist.exe, sorted, and output as C code describing the drivers.
****************************************************************************
Copyright Aaron Giles
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are
met:
* Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in
the documentation and/or other materials provided with the
distribution.
* Neither the name 'MAME' nor the names of its contributors may be
used to endorse or promote products derived from this software
without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY AARON GILES ''AS IS'' AND ANY EXPRESS OR
IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL AARON GILES BE LIABLE FOR ANY DIRECT,
INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
POSSIBILITY OF SUCH DAMAGE.
******************************************************************************/
robby // (c) 1981 Bally Midway
gridlee // [1983 Videa] prototype - no copyright notice
alienar // (c) 1985 Duncan Brown
carpolo // (c) 1977 Exidy
sidetrac // (c) 1979 Exidy
targ // (c) 1980 Exidy
spectar // (c) 1980 Exidy
teetert // (c) 1982 Exidy
hardhat // (c) 1982
fax // (c) 1983
fax2 // (c) 1983
circus // (c) 1977 Exidy
robotbwl // (c) 197? Exidy
crash // (c) 1979 Exidy
ripcord // (c) 1979 Exidy
starfire // (c) 1979 Exidy
starfirea // (c) 1979 Exidy
fireone // (c) 1979 Exidy
starfir2 // (c) 1979 Exidy
victory // (c) 1982
victorba // (c) 1982
topgunnr // (c) 1986
looping // (c) 1982 Video Games GMBH
supertnk // (c) 1981 VIDEO GAMES GmbH, W.-GERMANY
wrally // (c) 1993 - Ref 930705

View File

@ -71,7 +71,6 @@ SOUNDS += CEM3394
#------------------------------------------------- #-------------------------------------------------
DRVLIBS = \ DRVLIBS = \
$(MAMEOBJ)/tiny.o \
$(EMUDRIVERS)/emudummy.o \ $(EMUDRIVERS)/emudummy.o \
$(MACHINE)/ticket.o \ $(MACHINE)/ticket.o \
$(DRIVERS)/carpolo.o $(MACHINE)/carpolo.o $(VIDEO)/carpolo.o \ $(DRIVERS)/carpolo.o $(MACHINE)/carpolo.o $(VIDEO)/carpolo.o \

View File

@ -723,7 +723,7 @@ void osd_work_item_release(osd_work_item *item);
***************************************************************************/ ***************************************************************************/
/*----------------------------------------------------------------------------- /*-----------------------------------------------------------------------------
osd_malloc: allocate memory that osd_malloc: allocate memory
Parameters: Parameters:
@ -741,6 +741,26 @@ void osd_work_item_release(osd_work_item *item);
void *osd_malloc(size_t size); void *osd_malloc(size_t size);
/*-----------------------------------------------------------------------------
osd_malloc_array: allocate memory, hinting tha this memory contains an
array
Parameters:
size - the number of bytes to allocate
Return value:
a pointer to the allocated memory
Notes:
This is just a hook to do OS-specific allocation trickery.
It can be safely written as a wrapper to malloc().
-----------------------------------------------------------------------------*/
void *osd_malloc_array(size_t size);
/*----------------------------------------------------------------------------- /*-----------------------------------------------------------------------------
osd_free: free memory allocated by osd_malloc osd_free: free memory allocated by osd_malloc

View File

@ -93,10 +93,12 @@ static INT32 keyboard_get_state(void *device_internal, void *item_internal);
int main(int argc, char *argv[]) int main(int argc, char *argv[])
{ {
// cli_execute does the heavy lifting; if we have osd-specific options, we // cli_frontend does the heavy lifting; if we have osd-specific options, we
// would pass them as the third parameter here // create a derivative of cli_options and add our own
cli_options options;
mini_osd_interface osd; mini_osd_interface osd;
return cli_execute(argc, argv, osd, NULL); cli_frontend frontend(options, osd);
return frontend.execute(argc, argv);
} }
@ -135,7 +137,7 @@ void mini_osd_interface::init(running_machine &machine)
// initialize the input system by adding devices // initialize the input system by adding devices
// let's pretend like we have a keyboard device // let's pretend like we have a keyboard device
keyboard_device = input_device_add(&machine, DEVICE_CLASS_KEYBOARD, "Keyboard", NULL); keyboard_device = input_device_add(machine, DEVICE_CLASS_KEYBOARD, "Keyboard", NULL);
if (keyboard_device == NULL) if (keyboard_device == NULL)
fatalerror("Error creating keyboard device"); fatalerror("Error creating keyboard device");

View File

@ -44,7 +44,7 @@
//============================================================ //============================================================
// osd_alloc // osd_malloc
//============================================================ //============================================================
void *osd_malloc(size_t size) void *osd_malloc(size_t size)
@ -53,6 +53,16 @@ void *osd_malloc(size_t size)
} }
//============================================================
// osd_malloc_array
//============================================================
void *osd_malloc_array(size_t size)
{
return malloc(size);
}
//============================================================ //============================================================
// osd_free // osd_free
//============================================================ //============================================================

View File

@ -964,7 +964,7 @@ static texture_info *texture_create(sdl_window_info *window, const render_texinf
if ( (texture->copyinfo->func != NULL) && (texture->sdl_access == SDL_TEXTUREACCESS_STATIC)) if ( (texture->copyinfo->func != NULL) && (texture->sdl_access == SDL_TEXTUREACCESS_STATIC))
{ {
texture->pixels = osd_malloc(texture->setup.rotwidth * texture->setup.rotheight * texture->copyinfo->dst_bpp); texture->pixels = osd_malloc_array(texture->setup.rotwidth * texture->setup.rotheight * texture->copyinfo->dst_bpp);
texture->pixels_own=TRUE; texture->pixels_own=TRUE;
} }
/* add us to the texture list */ /* add us to the texture list */

View File

@ -67,7 +67,7 @@ struct _osd_directory
static char *build_full_path(const char *path, const char *file) static char *build_full_path(const char *path, const char *file)
{ {
char *ret = (char *) osd_malloc(strlen(path)+strlen(file)+2); char *ret = (char *) osd_malloc_array(strlen(path)+strlen(file)+2);
char *p = ret; char *p = ret;
strcpy(p, path); strcpy(p, path);
@ -126,13 +126,13 @@ osd_directory *osd_opendir(const char *dirname)
dir->fd = NULL; dir->fd = NULL;
} }
tmpstr = (char *) osd_malloc(strlen(dirname)+1); tmpstr = (char *) osd_malloc_array(strlen(dirname)+1);
strcpy(tmpstr, dirname); strcpy(tmpstr, dirname);
if (tmpstr[0] == '$') if (tmpstr[0] == '$')
{ {
char *envval; char *envval;
envstr = (char *) osd_malloc(strlen(tmpstr)+1); envstr = (char *) osd_malloc_array(strlen(tmpstr)+1);
strcpy(envstr, tmpstr); strcpy(envstr, tmpstr);
@ -149,7 +149,7 @@ osd_directory *osd_opendir(const char *dirname)
{ {
j = strlen(envval) + strlen(tmpstr) + 1; j = strlen(envval) + strlen(tmpstr) + 1;
osd_free(tmpstr); osd_free(tmpstr);
tmpstr = (char *) osd_malloc(j); tmpstr = (char *) osd_malloc_array(j);
// start with the value of $HOME // start with the value of $HOME
strcpy(tmpstr, envval); strcpy(tmpstr, envval);

View File

@ -115,7 +115,7 @@ file_error osd_open(const char *path, UINT32 openflags, osd_file **file, UINT64
tmpstr = NULL; tmpstr = NULL;
// allocate a file object, plus space for the converted filename // allocate a file object, plus space for the converted filename
*file = (osd_file *) osd_malloc(sizeof(**file) + sizeof(char) * strlen(path)); *file = (osd_file *) osd_malloc_array(sizeof(**file) + sizeof(char) * strlen(path));
if (*file == NULL) if (*file == NULL)
{ {
filerr = FILERR_OUT_OF_MEMORY; filerr = FILERR_OUT_OF_MEMORY;
@ -160,14 +160,14 @@ file_error osd_open(const char *path, UINT32 openflags, osd_file **file, UINT64
goto error; goto error;
} }
tmpstr = (char *) osd_malloc(strlen((*file)->filename)+1); tmpstr = (char *) osd_malloc_array(strlen((*file)->filename)+1);
strcpy(tmpstr, (*file)->filename); strcpy(tmpstr, (*file)->filename);
// does path start with an environment variable? // does path start with an environment variable?
if (tmpstr[0] == '$') if (tmpstr[0] == '$')
{ {
char *envval; char *envval;
envstr = (char *) osd_malloc(strlen(tmpstr)+1); envstr = (char *) osd_malloc_array(strlen(tmpstr)+1);
strcpy(envstr, tmpstr); strcpy(envstr, tmpstr);
@ -184,7 +184,7 @@ file_error osd_open(const char *path, UINT32 openflags, osd_file **file, UINT64
{ {
j = strlen(envval) + strlen(tmpstr) + 1; j = strlen(envval) + strlen(tmpstr) + 1;
osd_free(tmpstr); osd_free(tmpstr);
tmpstr = (char *) osd_malloc(j); tmpstr = (char *) osd_malloc_array(j);
// start with the value of $HOME // start with the value of $HOME
strcpy(tmpstr, envval); strcpy(tmpstr, envval);

View File

@ -348,7 +348,8 @@ int main(int argc, char *argv[])
{ {
sdl_osd_interface osd; sdl_osd_interface osd;
sdl_options options; sdl_options options;
res = cli_execute(options, osd, argc, argv); cli_frontend frontend(options, osd);
res = frontend.execute(argc, argv);
} }
#ifdef MALLOC_DEBUG #ifdef MALLOC_DEBUG

View File

@ -176,6 +176,20 @@ void *osd_malloc(size_t size)
} }
//============================================================
// osd_malloc_array
//============================================================
void *osd_malloc_array(size_t size)
{
#ifndef MALLOC_DEBUG
return malloc(size);
#else
#error "MALLOC_DEBUG not yet supported"
#endif
}
//============================================================ //============================================================
// osd_free // osd_free
//============================================================ //============================================================
@ -277,7 +291,7 @@ char *osd_get_clipboard_text(void)
length = CFDataGetLength (data_ref); length = CFDataGetLength (data_ref);
range = CFRangeMake (0,length); range = CFRangeMake (0,length);
result = (char *)osd_malloc (length+1); result = (char *)osd_malloc_array (length+1);
if (result != NULL) if (result != NULL)
{ {
CFDataGetBytes (data_ref, range, (unsigned char *)result); CFDataGetBytes (data_ref, range, (unsigned char *)result);
@ -330,7 +344,7 @@ osd_directory_entry *osd_stat(const char *path)
// create an osd_directory_entry; be sure to make sure that the caller can // create an osd_directory_entry; be sure to make sure that the caller can
// free all resources by just freeing the resulting osd_directory_entry // free all resources by just freeing the resulting osd_directory_entry
result = (osd_directory_entry *) osd_malloc(sizeof(*result) + strlen(path) + 1); result = (osd_directory_entry *) osd_malloc_array(sizeof(*result) + strlen(path) + 1);
strcpy(((char *) result) + sizeof(*result), path); strcpy(((char *) result) + sizeof(*result), path);
result->name = ((char *) result) + sizeof(*result); result->name = ((char *) result) + sizeof(*result);
result->type = S_ISDIR(st.st_mode) ? ENTTYPE_DIR : ENTTYPE_FILE; result->type = S_ISDIR(st.st_mode) ? ENTTYPE_DIR : ENTTYPE_FILE;
@ -367,7 +381,7 @@ file_error osd_get_full_path(char **dst, const char *path)
} }
else else
{ {
*dst = (char *)osd_malloc(strlen(path_buffer)+strlen(path)+3); *dst = (char *)osd_malloc_array(strlen(path_buffer)+strlen(path)+3);
// if it's already a full path, just pass it through // if it's already a full path, just pass it through
if (path[0] == '/') if (path[0] == '/')

View File

@ -198,6 +198,20 @@ void *osd_malloc(size_t size)
} }
//============================================================
// osd_malloc_array
//============================================================
void *osd_malloc_array(size_t size)
{
#ifndef MALLOC_DEBUG
return malloc(size);
#else
#error "MALLOC_DEBUG not yet supported"
#endif
}
//============================================================ //============================================================
// osd_free // osd_free
//============================================================ //============================================================
@ -258,7 +272,7 @@ osd_directory_entry *osd_stat(const char *path)
// create an osd_directory_entry; be sure to make sure that the caller can // create an osd_directory_entry; be sure to make sure that the caller can
// free all resources by just freeing the resulting osd_directory_entry // free all resources by just freeing the resulting osd_directory_entry
result = (osd_directory_entry *) osd_malloc(sizeof(*result) + strlen(path) result = (osd_directory_entry *) osd_malloc_array(sizeof(*result) + strlen(path)
1); 1);
strcpy(((char *) result) + sizeof(*result), path); strcpy(((char *) result) + sizeof(*result), path);
result->name = ((char *) result) + sizeof(*result); result->name = ((char *) result) + sizeof(*result);
@ -300,7 +314,7 @@ const char *osd_get_volume_name(int idx)
file_error osd_get_full_path(char **dst, const char *path) file_error osd_get_full_path(char **dst, const char *path)
{ {
*dst = (char *)osd_malloc(CCHMAXPATH + 1); *dst = (char *)osd_malloc_array(CCHMAXPATH + 1);
if (*dst == NULL) if (*dst == NULL)
return FILERR_OUT_OF_MEMORY; return FILERR_OUT_OF_MEMORY;

View File

@ -92,6 +92,20 @@ void *osd_malloc(size_t size)
} }
//============================================================
// osd_malloc_array
//============================================================
void *osd_malloc_array(size_t size)
{
#ifndef MALLOC_DEBUG
return malloc(size);
#else
#error "MALLOC_DEBUG not yet supported"
#endif
}
//============================================================ //============================================================
// osd_free // osd_free
//============================================================ //============================================================
@ -207,7 +221,7 @@ char *osd_get_clipboard_text(void)
/* return a copy & free original */ /* return a copy & free original */
if (prop != NULL) if (prop != NULL)
{ {
result = (char *) osd_malloc(strlen((char *)prop)+1); result = (char *) osd_malloc_array(strlen((char *)prop)+1);
strcpy(result, (char *)prop); strcpy(result, (char *)prop);
} }
else else
@ -256,7 +270,7 @@ osd_directory_entry *osd_stat(const char *path)
// create an osd_directory_entry; be sure to make sure that the caller can // create an osd_directory_entry; be sure to make sure that the caller can
// free all resources by just freeing the resulting osd_directory_entry // free all resources by just freeing the resulting osd_directory_entry
result = (osd_directory_entry *) osd_malloc(sizeof(*result) + strlen(path) + 1); result = (osd_directory_entry *) osd_malloc_array(sizeof(*result) + strlen(path) + 1);
strcpy(((char *) result) + sizeof(*result), path); strcpy(((char *) result) + sizeof(*result), path);
result->name = ((char *) result) + sizeof(*result); result->name = ((char *) result) + sizeof(*result);
result->type = S_ISDIR(st.st_mode) ? ENTTYPE_DIR : ENTTYPE_FILE; result->type = S_ISDIR(st.st_mode) ? ENTTYPE_DIR : ENTTYPE_FILE;
@ -293,7 +307,7 @@ file_error osd_get_full_path(char **dst, const char *path)
} }
else else
{ {
*dst = (char *)osd_malloc(strlen(path_buffer)+strlen(path)+3); *dst = (char *)osd_malloc_array(strlen(path_buffer)+strlen(path)+3);
// if it's already a full path, just pass it through // if it's already a full path, just pass it through
if (path[0] == '/') if (path[0] == '/')

View File

@ -180,41 +180,54 @@ void *osd_malloc(size_t size)
#ifndef MALLOC_DEBUG #ifndef MALLOC_DEBUG
return HeapAlloc(GetProcessHeap(), 0, size); return HeapAlloc(GetProcessHeap(), 0, size);
#else #else
// add in space for the base pointer // add in space for the size
size += sizeof(size_t); size += sizeof(size_t);
// small items just come from the heap // basic objects just come from the heap
void *result; void *result = HeapAlloc(GetProcessHeap(), 0, size);
if (size < GUARD_PAGE_THRESH)
result = HeapAlloc(GetProcessHeap(), 0, size);
// large items get guard pages // store the size and return and pointer to the data afterward
else
{
// round the size up to a page boundary
size_t rounded_size = ((size + sizeof(void *) + PAGE_SIZE - 1) / PAGE_SIZE) * PAGE_SIZE;
// reserve that much memory, plus two guard pages
void *page_base = VirtualAlloc(NULL, rounded_size + 2 * PAGE_SIZE, MEM_RESERVE, PAGE_NOACCESS);
if (page_base == NULL)
return NULL;
// now allow access to everything but the first and last pages
page_base = VirtualAlloc(reinterpret_cast<UINT8 *>(page_base) + PAGE_SIZE, rounded_size, MEM_COMMIT, PAGE_READWRITE);
if (page_base == NULL)
return NULL;
// work backwards from the page base to get to the block base
result = GUARD_ALIGN_START ? page_base : (reinterpret_cast<UINT8 *>(page_base) + rounded_size - size);
}
// store the page_base at the start
*reinterpret_cast<size_t *>(result) = size; *reinterpret_cast<size_t *>(result) = size;
return reinterpret_cast<UINT8 *>(result) + sizeof(size_t); return reinterpret_cast<UINT8 *>(result) + sizeof(size_t);
#endif #endif
} }
//============================================================
// osd_malloc_array
//============================================================
void *osd_malloc_array(size_t size)
{
#ifndef MALLOC_DEBUG
return HeapAlloc(GetProcessHeap(), 0, size);
#else
// add in space for the size
size += sizeof(size_t);
// round the size up to a page boundary
size_t rounded_size = ((size + sizeof(void *) + PAGE_SIZE - 1) / PAGE_SIZE) * PAGE_SIZE;
// reserve that much memory, plus two guard pages
void *page_base = VirtualAlloc(NULL, rounded_size + 2 * PAGE_SIZE, MEM_RESERVE, PAGE_NOACCESS);
if (page_base == NULL)
return NULL;
// now allow access to everything but the first and last pages
page_base = VirtualAlloc(reinterpret_cast<UINT8 *>(page_base) + PAGE_SIZE, rounded_size, MEM_COMMIT, PAGE_READWRITE);
if (page_base == NULL)
return NULL;
// work backwards from the page base to get to the block base
void *result = GUARD_ALIGN_START ? page_base : (reinterpret_cast<UINT8 *>(page_base) + rounded_size - size);
// store the size at the start with a flag indicating it has a guard page
*reinterpret_cast<size_t *>(result) = size | 0x80000000;
return reinterpret_cast<UINT8 *>(result) + sizeof(size_t);
#endif
}
//============================================================ //============================================================
// osd_free // osd_free
//============================================================ //============================================================
@ -226,14 +239,14 @@ void osd_free(void *ptr)
#else #else
size_t size = reinterpret_cast<size_t *>(ptr)[-1]; size_t size = reinterpret_cast<size_t *>(ptr)[-1];
// small items just get freed // if no guard page, just free the pointer
if (size < GUARD_PAGE_THRESH) if ((size & 0x80000000) == 0)
HeapFree(GetProcessHeap(), 0, reinterpret_cast<UINT8 *>(ptr) - sizeof(size_t)); HeapFree(GetProcessHeap(), 0, reinterpret_cast<UINT8 *>(ptr) - sizeof(size_t));
// large items need more care // large items need more care
else else
{ {
FPTR page_base = (reinterpret_cast<FPTR>(ptr) - sizeof(size_t)) & ~(PAGE_SIZE - 1); ULONG_PTR page_base = (reinterpret_cast<ULONG_PTR>(ptr) - sizeof(size_t)) & ~(PAGE_SIZE - 1);
VirtualFree(reinterpret_cast<void *>(page_base - PAGE_SIZE), 0, MEM_RELEASE); VirtualFree(reinterpret_cast<void *>(page_base - PAGE_SIZE), 0, MEM_RELEASE);
} }
#endif #endif
@ -262,7 +275,7 @@ int osd_setenv(const char *name, const char *value, int overwrite)
if (osd_getenv(name) != NULL) if (osd_getenv(name) != NULL)
return 0; return 0;
} }
buf = (char *) osd_malloc(strlen(name)+strlen(value)+2); buf = (char *) osd_malloc_array(strlen(name)+strlen(value)+2);
sprintf(buf, "%s=%s", name, value); sprintf(buf, "%s=%s", name, value);
result = putenv(buf); result = putenv(buf);
@ -371,7 +384,7 @@ CHAR *astring_from_utf8(const char *utf8string)
// convert UTF-16 to "ANSI code page" string // convert UTF-16 to "ANSI code page" string
char_count = WideCharToMultiByte(CP_ACP, 0, wstring, -1, NULL, 0, NULL, NULL); char_count = WideCharToMultiByte(CP_ACP, 0, wstring, -1, NULL, 0, NULL, NULL);
result = (CHAR *)osd_malloc(char_count * sizeof(*result)); result = (CHAR *)osd_malloc_array(char_count * sizeof(*result));
if (result != NULL) if (result != NULL)
WideCharToMultiByte(CP_ACP, 0, wstring, -1, result, char_count, NULL, NULL); WideCharToMultiByte(CP_ACP, 0, wstring, -1, result, char_count, NULL, NULL);
@ -389,7 +402,7 @@ WCHAR *wstring_from_utf8(const char *utf8string)
// convert MAME string (UTF-8) to UTF-16 // convert MAME string (UTF-8) to UTF-16
char_count = MultiByteToWideChar(CP_UTF8, 0, utf8string, -1, NULL, 0); char_count = MultiByteToWideChar(CP_UTF8, 0, utf8string, -1, NULL, 0);
result = (WCHAR *)osd_malloc(char_count * sizeof(*result)); result = (WCHAR *)osd_malloc_array(char_count * sizeof(*result));
if (result != NULL) if (result != NULL)
MultiByteToWideChar(CP_UTF8, 0, utf8string, -1, result, char_count); MultiByteToWideChar(CP_UTF8, 0, utf8string, -1, result, char_count);

View File

@ -183,7 +183,7 @@ osd_work_queue *osd_work_queue_alloc(int flags)
queue->threads = MIN(queue->threads, WORK_MAX_THREADS); queue->threads = MIN(queue->threads, WORK_MAX_THREADS);
// allocate memory for thread array (+1 to count the calling thread) // allocate memory for thread array (+1 to count the calling thread)
queue->thread = (work_thread_info *)osd_malloc((queue->threads + 1) * sizeof(queue->thread[0])); queue->thread = (work_thread_info *)osd_malloc_array((queue->threads + 1) * sizeof(queue->thread[0]));
if (queue->thread == NULL) if (queue->thread == NULL)
goto error; goto error;
memset(queue->thread, 0, (queue->threads + 1) * sizeof(queue->thread[0])); memset(queue->thread, 0, (queue->threads + 1) * sizeof(queue->thread[0]));

View File

@ -38,7 +38,7 @@ char *utf8_from_astring(const CHAR *astring)
// convert UTF-16 to MAME string (UTF-8) // convert UTF-16 to MAME string (UTF-8)
char_count = WideCharToMultiByte(CP_UTF8, 0, wstring, -1, NULL, 0, NULL, NULL); char_count = WideCharToMultiByte(CP_UTF8, 0, wstring, -1, NULL, 0, NULL, NULL);
result = (CHAR *)osd_malloc(char_count * sizeof(*result)); result = (CHAR *)osd_malloc_array(char_count * sizeof(*result));
if (result != NULL) if (result != NULL)
WideCharToMultiByte(CP_UTF8, 0, wstring, -1, result, char_count, NULL, NULL); WideCharToMultiByte(CP_UTF8, 0, wstring, -1, result, char_count, NULL, NULL);
@ -56,7 +56,7 @@ char *utf8_from_wstring(const WCHAR *wstring)
// convert UTF-16 to MAME string (UTF-8) // convert UTF-16 to MAME string (UTF-8)
char_count = WideCharToMultiByte(CP_UTF8, 0, wstring, -1, NULL, 0, NULL, NULL); char_count = WideCharToMultiByte(CP_UTF8, 0, wstring, -1, NULL, 0, NULL, NULL);
result = (char *)osd_malloc(char_count * sizeof(*result)); result = (char *)osd_malloc_array(char_count * sizeof(*result));
if (result != NULL) if (result != NULL)
WideCharToMultiByte(CP_UTF8, 0, wstring, -1, result, char_count, NULL, NULL); WideCharToMultiByte(CP_UTF8, 0, wstring, -1, result, char_count, NULL, NULL);

View File

@ -65,7 +65,7 @@ CHAR *astring_from_utf8(const char *utf8string)
// convert UTF-16 to "ANSI code page" string // convert UTF-16 to "ANSI code page" string
char_count = WideCharToMultiByte(CP_ACP, 0, wstring, -1, NULL, 0, NULL, NULL); char_count = WideCharToMultiByte(CP_ACP, 0, wstring, -1, NULL, 0, NULL, NULL);
result = (CHAR *)osd_malloc(char_count * sizeof(*result)); result = (CHAR *)osd_malloc_array(char_count * sizeof(*result));
if (result != NULL) if (result != NULL)
WideCharToMultiByte(CP_ACP, 0, wstring, -1, result, char_count, NULL, NULL); WideCharToMultiByte(CP_ACP, 0, wstring, -1, result, char_count, NULL, NULL);
@ -90,7 +90,7 @@ char *utf8_from_astring(const CHAR *astring)
// convert UTF-16 to MAME string (UTF-8) // convert UTF-16 to MAME string (UTF-8)
char_count = WideCharToMultiByte(CP_UTF8, 0, wstring, -1, NULL, 0, NULL, NULL); char_count = WideCharToMultiByte(CP_UTF8, 0, wstring, -1, NULL, 0, NULL, NULL);
result = (CHAR *)osd_malloc(char_count * sizeof(*result)); result = (CHAR *)osd_malloc_array(char_count * sizeof(*result));
if (result != NULL) if (result != NULL)
WideCharToMultiByte(CP_UTF8, 0, wstring, -1, result, char_count, NULL, NULL); WideCharToMultiByte(CP_UTF8, 0, wstring, -1, result, char_count, NULL, NULL);
@ -109,7 +109,7 @@ WCHAR *wstring_from_utf8(const char *utf8string)
// convert MAME string (UTF-8) to UTF-16 // convert MAME string (UTF-8) to UTF-16
char_count = MultiByteToWideChar(CP_UTF8, 0, utf8string, -1, NULL, 0); char_count = MultiByteToWideChar(CP_UTF8, 0, utf8string, -1, NULL, 0);
result = (WCHAR *)osd_malloc(char_count * sizeof(*result)); result = (WCHAR *)osd_malloc_array(char_count * sizeof(*result));
if (result != NULL) if (result != NULL)
MultiByteToWideChar(CP_UTF8, 0, utf8string, -1, result, char_count); MultiByteToWideChar(CP_UTF8, 0, utf8string, -1, result, char_count);
@ -128,7 +128,7 @@ char *utf8_from_wstring(const WCHAR *wstring)
// convert UTF-16 to MAME string (UTF-8) // convert UTF-16 to MAME string (UTF-8)
char_count = WideCharToMultiByte(CP_UTF8, 0, wstring, -1, NULL, 0, NULL, NULL); char_count = WideCharToMultiByte(CP_UTF8, 0, wstring, -1, NULL, 0, NULL, NULL);
result = (char *)osd_malloc(char_count * sizeof(*result)); result = (char *)osd_malloc_array(char_count * sizeof(*result));
if (result != NULL) if (result != NULL)
WideCharToMultiByte(CP_UTF8, 0, wstring, -1, result, char_count, NULL, NULL); WideCharToMultiByte(CP_UTF8, 0, wstring, -1, result, char_count, NULL, NULL);

View File

@ -1,618 +0,0 @@
//============================================================
//
// winalloc.c - Win32 memory allocation routines
//
//============================================================
//
// Copyright Aaron Giles
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or
// without modification, are permitted provided that the
// following conditions are met:
//
// * Redistributions of source code must retain the above
// copyright notice, this list of conditions and the
// following disclaimer.
// * Redistributions in binary form must reproduce the
// above copyright notice, this list of conditions and
// the following disclaimer in the documentation and/or
// other materials provided with the distribution.
// * Neither the name 'MAME' nor the names of its
// contributors may be used to endorse or promote
// products derived from this software without specific
// prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY AARON GILES ''AS IS'' AND
// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
// FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
// EVENT SHALL AARON GILES BE LIABLE FOR ANY DIRECT,
// INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
// DAMAGE (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
// PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
// ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
// LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
// IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
//
//============================================================
// standard windows headers
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
#include <tchar.h>
// MAME headers
#include "osdcore.h"
// undefine any redefines we have in the prefix
#undef malloc
#undef calloc
#undef realloc
//============================================================
// CONSTANTS
//============================================================
#define OVERRIDE_STANDARD_CALLS (0)
#define PAGE_SIZE 4096
#define COOKIE_VAL 0x11335577
// set this to 1 to align memory blocks to the start of a page;
// otherwise, they are aligned to the end, thus catching array
// overruns
#define ALIGN_START 0
// set this to 1 to record all mallocs and frees in the logfile
#define LOG_CALLS 0
#if LOG_CALLS
#define LOG(x) do { if (LOG_CALLS) logerror x; } while (0)
void CLIB_DECL logerror(const char *text,...);
#else
#define LOG(x)
#endif
//============================================================
// TYPEDEFS
//============================================================
typedef struct _memory_entry memory_entry;
struct _memory_entry
{
memory_entry * next;
memory_entry * prev;
size_t size;
void * base;
const char * file;
int line;
int id;
};
//============================================================
// GLOBAL VARIABLES
//============================================================
int winalloc_in_main_code = FALSE;
//============================================================
// LOCAL VARIABLES
//============================================================
static memory_entry *alloc_list;
static memory_entry *free_list;
static int current_id;
static CRITICAL_SECTION memory_lock;
static UINT8 global_init_done = FALSE;
static UINT8 use_malloc_tracking = FALSE;
//============================================================
// PROTOTYPES
//============================================================
static memory_entry *allocate_entry(void);
static memory_entry *find_entry(void *pointer);
static void free_entry(memory_entry *entry);
static void global_init(void);
//============================================================
// INLINES
//============================================================
INLINE void global_init_if_not_done(void)
{
if (!global_init_done)
{
global_init_done = TRUE;
global_init();
}
}
INLINE void memory_lock_acquire(void)
{
EnterCriticalSection(&memory_lock);
}
INLINE void memory_lock_release(void)
{
LeaveCriticalSection(&memory_lock);
}
//============================================================
// IMPLEMENTATION
//============================================================
//============================================================
// malloc_file_line - debugging version of malloc which
// accepts filename and line number
//============================================================
void *malloc_file_line(size_t size, const char *file, int line)
{
UINT8 *block_base;
int id = current_id++;
// perform global intialization if not already done
global_init_if_not_done();
// only proceed if enabled
if (use_malloc_tracking)
{
UINT8 *page_base;
size_t rounded_size;
memory_entry *entry;
// round the size up to a page boundary
rounded_size = ((size + PAGE_SIZE - 1) / PAGE_SIZE) * PAGE_SIZE;
// reserve that much memory, plus two guard pages
page_base = (UINT8 *)VirtualAlloc(NULL, rounded_size + 2 * PAGE_SIZE, MEM_RESERVE, PAGE_NOACCESS);
if (page_base == NULL)
return NULL;
// now allow access to everything but the first and last pages
page_base = (UINT8 *)VirtualAlloc(page_base + PAGE_SIZE, rounded_size, MEM_COMMIT, PAGE_READWRITE);
if (page_base == NULL)
return NULL;
// work backwards from the page base to get to the block base
if (ALIGN_START)
block_base = page_base;
else
block_base = page_base + rounded_size - size;
// fill in the entry
entry = allocate_entry();
entry->size = size;
entry->base = block_base;
entry->file = file;
entry->line = line;
entry->id = id;
}
else
{
block_base = (UINT8 *)GlobalAlloc(GMEM_FIXED, size);
}
// logging
if (file != NULL)
LOG(("malloc #%06d size = %d (%s:%d)\n", id, size, file, line));
else
LOG(("malloc #%06d size = %d\n", id, size));
return block_base;
}
//============================================================
// malloc - override for the malloc() function
//============================================================
#if OVERRIDE_STANDARD_CALLS
void *CLIB_DECL malloc(size_t size)
{
return malloc_file_line(size, NULL, 0);
}
#endif
//============================================================
// calloc_file_line - debugging version of calloc which
// accepts filename and line number
//============================================================
void *calloc_file_line(size_t size, size_t count, const char *file, int line)
{
// first allocate the memory
void *memory = malloc_file_line(size * count, file, line);
if (memory == NULL)
return NULL;
// then memset it
memset(memory, 0, size * count);
return memory;
}
//============================================================
// calloc - override for the calloc() function
//============================================================
#if OVERRIDE_STANDARD_CALLS
void *CLIB_DECL calloc(size_t size, size_t count)
{
return calloc_file_line(size, count, NULL, 0);
}
#endif
//============================================================
// _calloc_crt - override for the _calloc_crt() function,
// which is called by beginthreadex
//============================================================
#if OVERRIDE_STANDARD_CALLS
void *CLIB_DECL _calloc_crt(size_t size, size_t count)
{
return calloc_file_line(size, count, NULL, 0);
}
#endif
//============================================================
// realloc_file_line - debugging version of realloc which
// accepts filename and line number
//============================================================
void *realloc_file_line(void *memory, size_t size, const char *file, int line)
{
void *newmemory = NULL;
// perform global intialization if not already done
global_init_if_not_done();
// only proceed if enabled
if (use_malloc_tracking)
{
// if size is non-zero, we need to reallocate memory
if (size != 0)
{
// allocate space for the new amount
newmemory = malloc_file_line(size, file, line);
if (newmemory == NULL)
return NULL;
// if we have an old pointer, copy it
if (memory != NULL)
{
memory_entry *entry = find_entry(memory);
if (entry == NULL)
{
if (winalloc_in_main_code)
{
fprintf(stderr, "Error: realloc a non-existant block (%s:%d)\n", file, line);
osd_break_into_debugger("Error: realloc a non-existant block\n");
}
}
else
memcpy(newmemory, memory, (size < entry->size) ? size : entry->size);
}
}
// if we have an original pointer, free it
if (memory != NULL)
free(memory);
}
else
{
if (memory != NULL)
newmemory = (void *) GlobalReAlloc(memory, size, GMEM_MOVEABLE);
else
newmemory = (void *) GlobalAlloc(GMEM_FIXED, size);
}
return newmemory;
}
//============================================================
// realloc - override for the realloc() function
//============================================================
#if OVERRIDE_STANDARD_CALLS
void *CLIB_DECL realloc(void *memory, size_t size)
{
return realloc_file_line(memory, size, NULL, 0);
}
#endif
//============================================================
// free_file_line - debugging version of free which
// accepts filename and line number
//============================================================
void CLIB_DECL free_file_line(void *memory, const char *file, int line)
{
memory_entry *entry;
// allow NULL frees
if (memory == NULL)
return;
// only proceed if enabled
if (use_malloc_tracking)
{
// error if no entry found
entry = find_entry(memory);
if (entry == NULL)
{
if (winalloc_in_main_code)
{
fprintf(stderr, "Error: free a non-existant block\n");
osd_break_into_debugger("Error: free a non-existant block");
}
return;
}
free_entry(entry);
// free the memory
VirtualFree((UINT8 *)memory - ((size_t)memory & (PAGE_SIZE-1)) - PAGE_SIZE, 0, MEM_RELEASE);
LOG(("free #%06d size = %d\n", entry->id, entry->size));
}
else
{
GlobalFree(memory);
}
}
//============================================================
// free - override for the free() function
//============================================================
#if OVERRIDE_STANDARD_CALLS
void CLIB_DECL free(void *memory)
{
free_file_line(memory, NULL, 0);
}
#endif
//============================================================
// _msize - internal MSVC routine that returns the size of
// a memory block
//============================================================
#if OVERRIDE_STANDARD_CALLS
size_t CLIB_DECL _msize(void *memory)
{
size_t result;
// only proceed if enabled
if (use_malloc_tracking)
{
memory_entry *entry = find_entry(memory);
if (entry == NULL)
{
if (winalloc_in_main_code)
{
fprintf(stderr, "Error: msize a non-existant block\n");
osd_break_into_debugger("Error: msize a non-existant block");
}
return 0;
}
result = entry->size;
}
else
{
result = GlobalSize(memory);
}
return result;
}
#endif
//============================================================
// check_unfreed_mem - called from the exit path of any
// code that wants to check for unfreed memory
//============================================================
void check_unfreed_mem(void)
{
memory_entry *entry;
int total = 0;
// only valid if we are tracking
if (use_malloc_tracking)
{
memory_lock_acquire();
// check for leaked memory
for (entry = alloc_list; entry; entry = entry->next)
if (entry->file != NULL)
{
if (total == 0)
fprintf(stderr, "--- memory leak warning ---\n");
total += entry->size;
fprintf(stderr, "allocation #%06d, %d bytes (%s:%d)\n", entry->id, entry->size, entry->file, (int)entry->line);
}
memory_lock_release();
if (total > 0)
fprintf(stderr, "a total of %d bytes were not free()'d\n", total);
}
}
//============================================================
// allocate_entry - allocate a new entry and link it into
// the list of allocated memory
//============================================================
static memory_entry *allocate_entry(void)
{
memory_entry *entry;
// always take the lock when allocating
memory_lock_acquire();
// if we're out of entries, allocate some more
if (free_list == NULL)
{
int entries_per_page = PAGE_SIZE / sizeof(memory_entry);
// allocate a new pages' worth of entry
entry = (memory_entry *)VirtualAlloc(NULL, PAGE_SIZE, MEM_COMMIT, PAGE_READWRITE);
if (entry == NULL)
{
memory_lock_release();
fprintf(stderr, "Out of memory for malloc tracking!\n");
exit(1);
}
// add all the entries to the list
while (entries_per_page--)
{
entry->next = free_list;
free_list = entry;
entry++;
}
}
// grab a free list entry
entry = free_list;
free_list = free_list->next;
// add ourselves to the alloc list
entry->next = alloc_list;
if (entry->next)
entry->next->prev = entry;
entry->prev = NULL;
alloc_list = entry;
// release the lock when finished
memory_lock_release();
return entry;
}
//============================================================
// find_entry - find a memory_object entry in the list that
// contains the given pointer
//============================================================
static memory_entry *find_entry(void *pointer)
{
memory_entry *entry;
// scan the list looking for a matching base
if (pointer)
{
memory_lock_acquire();
for (entry = alloc_list; entry; entry = entry->next)
if (entry->base == pointer)
break;
memory_lock_release();
return entry;
}
return NULL;
}
//============================================================
// free_entry - free a memory_entry object
//============================================================
static void free_entry(memory_entry *entry)
{
memory_lock_acquire();
// remove ourselves from the alloc list
if (entry->prev)
entry->prev->next = entry->next;
else
alloc_list = entry->next;
if (entry->next)
entry->next->prev = entry->prev;
// add ourself to the free list
entry->next = free_list;
free_list = entry;
memory_lock_release();
}
//============================================================
// global_init - global initialization of memory variables
//============================================================
static void global_init(void)
{
TCHAR *envstring;
// create the memory lock
InitializeCriticalSection(&memory_lock);
// determine if we enabled by default
if (win_is_gui_application()) {
use_malloc_tracking = FALSE;
} else {
use_malloc_tracking = TRUE;
}
// now allow overrides by the environment
envstring = _tgetenv(_T("OSDDEBUGMALLOC"));
if (envstring != NULL)
use_malloc_tracking = (_ttoi(envstring) != 0);
#ifdef PTR64
// 64-bit builds also can allocate everything under 4GB, unless disabled
envstring = _tgetenv(_T("OSDDEBUG4GB"));
if (envstring == NULL || _ttoi(envstring) != 0)
{
INT8 allocshift;
// loop from 256MB down to 4k (page size)
for (allocshift = 8 + 20; allocshift >= 12; allocshift--)
{
// keep allocating address space at that size until we get something >4gb
while ((UINT64)VirtualAlloc(NULL, (UINT64)1 << allocshift, MEM_RESERVE, PAGE_NOACCESS) < ((UINT64)1 << 32)) ;
}
// loop from 64k down
for (allocshift = 6 + 10; allocshift >= 1; allocshift--)
{
// keep allocating memory until we get something >4gb
while ((UINT64)GlobalAlloc(GMEM_FIXED, (UINT64)1 << allocshift) < ((UINT64)1 << 32)) ;
}
}
#endif
}

View File

@ -418,7 +418,8 @@ int main(int argc, char *argv[])
{ {
windows_options options; windows_options options;
windows_osd_interface osd; windows_osd_interface osd;
result = cli_execute(options, osd, argc, argv); cli_frontend frontend(options, osd);
frontend.execute(argc, argv);
} }
// free symbols // free symbols

View File

@ -45,7 +45,7 @@
#include <tchar.h> #include <tchar.h>
// MAME headers // MAME headers
#include "emucore.h" #include "osdcore.h"
// MAMEOS headers // MAMEOS headers
#include "winutf8.h" #include "winutf8.h"
@ -60,9 +60,6 @@
// presumed size of a page of memory // presumed size of a page of memory
#define PAGE_SIZE 4096 #define PAGE_SIZE 4096
// allocations this size and larger get guard pages
#define GUARD_PAGE_THRESH 32
// align allocations to start or end of the page? // align allocations to start or end of the page?
#define GUARD_ALIGN_START 0 #define GUARD_ALIGN_START 0
@ -85,41 +82,54 @@ void *osd_malloc(size_t size)
#ifndef MALLOC_DEBUG #ifndef MALLOC_DEBUG
return HeapAlloc(GetProcessHeap(), 0, size); return HeapAlloc(GetProcessHeap(), 0, size);
#else #else
// add in space for the base pointer // add in space for the size
size += sizeof(size_t); size += sizeof(size_t);
// small items just come from the heap // basic objects just come from the heap
void *result; void *result = HeapAlloc(GetProcessHeap(), 0, size);
if (size < GUARD_PAGE_THRESH)
result = HeapAlloc(GetProcessHeap(), 0, size);
// large items get guard pages // store the size and return and pointer to the data afterward
else
{
// round the size up to a page boundary
size_t rounded_size = ((size + sizeof(void *) + PAGE_SIZE - 1) / PAGE_SIZE) * PAGE_SIZE;
// reserve that much memory, plus two guard pages
void *page_base = VirtualAlloc(NULL, rounded_size + 2 * PAGE_SIZE, MEM_RESERVE, PAGE_NOACCESS);
if (page_base == NULL)
return NULL;
// now allow access to everything but the first and last pages
page_base = VirtualAlloc(reinterpret_cast<UINT8 *>(page_base) + PAGE_SIZE, rounded_size, MEM_COMMIT, PAGE_READWRITE);
if (page_base == NULL)
return NULL;
// work backwards from the page base to get to the block base
result = GUARD_ALIGN_START ? page_base : (reinterpret_cast<UINT8 *>(page_base) + rounded_size - size);
}
// store the page_base at the start
*reinterpret_cast<size_t *>(result) = size; *reinterpret_cast<size_t *>(result) = size;
return reinterpret_cast<UINT8 *>(result) + sizeof(size_t); return reinterpret_cast<UINT8 *>(result) + sizeof(size_t);
#endif #endif
} }
//============================================================
// osd_malloc_array
//============================================================
void *osd_malloc_array(size_t size)
{
#ifndef MALLOC_DEBUG
return HeapAlloc(GetProcessHeap(), 0, size);
#else
// add in space for the size
size += sizeof(size_t);
// round the size up to a page boundary
size_t rounded_size = ((size + sizeof(void *) + PAGE_SIZE - 1) / PAGE_SIZE) * PAGE_SIZE;
// reserve that much memory, plus two guard pages
void *page_base = VirtualAlloc(NULL, rounded_size + 2 * PAGE_SIZE, MEM_RESERVE, PAGE_NOACCESS);
if (page_base == NULL)
return NULL;
// now allow access to everything but the first and last pages
page_base = VirtualAlloc(reinterpret_cast<UINT8 *>(page_base) + PAGE_SIZE, rounded_size, MEM_COMMIT, PAGE_READWRITE);
if (page_base == NULL)
return NULL;
// work backwards from the page base to get to the block base
void *result = GUARD_ALIGN_START ? page_base : (reinterpret_cast<UINT8 *>(page_base) + rounded_size - size);
// store the size at the start with a flag indicating it has a guard page
*reinterpret_cast<size_t *>(result) = size | 0x80000000;
return reinterpret_cast<UINT8 *>(result) + sizeof(size_t);
#endif
}
//============================================================ //============================================================
// osd_free // osd_free
//============================================================ //============================================================
@ -131,14 +141,14 @@ void osd_free(void *ptr)
#else #else
size_t size = reinterpret_cast<size_t *>(ptr)[-1]; size_t size = reinterpret_cast<size_t *>(ptr)[-1];
// small items just get freed // if no guard page, just free the pointer
if (size < GUARD_PAGE_THRESH) if ((size & 0x80000000) == 0)
HeapFree(GetProcessHeap(), 0, reinterpret_cast<UINT8 *>(ptr) - sizeof(size_t)); HeapFree(GetProcessHeap(), 0, reinterpret_cast<UINT8 *>(ptr) - sizeof(size_t));
// large items need more care // large items need more care
else else
{ {
FPTR page_base = (reinterpret_cast<FPTR>(ptr) - sizeof(size_t)) & ~(PAGE_SIZE - 1); ULONG_PTR page_base = (reinterpret_cast<ULONG_PTR>(ptr) - sizeof(size_t)) & ~(PAGE_SIZE - 1);
VirtualFree(reinterpret_cast<void *>(page_base - PAGE_SIZE), 0, MEM_RELEASE); VirtualFree(reinterpret_cast<void *>(page_base - PAGE_SIZE), 0, MEM_RELEASE);
} }
#endif #endif