mirror of
https://github.com/holub/mame
synced 2025-06-05 04:16:28 +03:00
(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:
parent
f99e1a5da6
commit
00d745ca77
8
.gitattributes
vendored
8
.gitattributes
vendored
@ -10,6 +10,7 @@ hash/softwarelist.dtd svneol=native#text/plain
|
||||
src/build/build.mak svneol=native#text/plain
|
||||
src/build/file2str.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/verinfo.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/lcd.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/triphsxs.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_slots.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/pmpoker.lay svneol=native#text/plain
|
||||
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/zs01.c 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/mamedriv.c svneol=native#text/plain
|
||||
src/mame/tiny.c svneol=native#text/plain
|
||||
src/mame/tiny.lst svneol=native#text/plain
|
||||
src/mame/tiny.mak svneol=native#text/plain
|
||||
src/mame/video/1942.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/video.c 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/windir.c svneol=native#text/plain
|
||||
src/osd/windows/window.c svneol=native#text/plain
|
||||
|
12
makefile
12
makefile
@ -577,6 +577,8 @@ LIBOCORE = $(OBJ)/libocore.a
|
||||
LIBOSD = $(OBJ)/libosd.a
|
||||
|
||||
VERSIONOBJ = $(OBJ)/version.o
|
||||
DRIVLISTSRC = $(OBJ)/drivlist.c
|
||||
DRIVLISTOBJ = $(OBJ)/drivlist.o
|
||||
|
||||
|
||||
|
||||
@ -722,7 +724,7 @@ ifndef EXECUTABLE_DEFINED
|
||||
# always recompile the version string
|
||||
$(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 $@...
|
||||
$(LD) $(LDFLAGS) $(LDFLAGSEMULATOR) $^ $(LIBS) -o $@
|
||||
ifeq ($(TARGETOS),win32)
|
||||
@ -760,6 +762,14 @@ $(OBJ)/%.fh: $(SRC)/%.png $(PNG2BDC_TARGET) $(FILE2STR_TARGET)
|
||||
@$(PNG2BDC) $< $(OBJ)/temp.bdc
|
||||
@$(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:
|
||||
@echo Archiving $@...
|
||||
$(RM) $@
|
||||
|
@ -20,17 +20,20 @@ OBJDIRS += \
|
||||
|
||||
FILE2STR_TARGET = $(BUILDOUT)/file2str$(BUILD_EXE)
|
||||
MAKEDEP_TARGET = $(BUILDOUT)/makedep$(BUILD_EXE)
|
||||
MAKELIST_TARGET = $(BUILDOUT)/makelist$(BUILD_EXE)
|
||||
PNG2BDC_TARGET = $(BUILDOUT)/png2bdc$(BUILD_EXE)
|
||||
VERINFO_TARGET = $(BUILDOUT)/verinfo$(BUILD_EXE)
|
||||
|
||||
ifeq ($(TARGETOS),win32)
|
||||
FILE2STR = $(subst /,\,$(FILE2STR_TARGET))
|
||||
MAKEDEP = $(subst /,\,$(MAKEDEP_TARGET))
|
||||
MAKELIST = $(subst /,\,$(MAKELIST_TARGET))
|
||||
PNG2BDC = $(subst /,\,$(PNG2BDC_TARGET))
|
||||
VERINFO = $(subst /,\,$(VERINFO_TARGET))
|
||||
else
|
||||
FILE2STR = $(FILE2STR_TARGET)
|
||||
MAKEDEP = $(MAKEDEP_TARGET)
|
||||
MAKELIST = $(MAKELIST_TARGET)
|
||||
PNG2BDC = $(PNG2BDC_TARGET)
|
||||
VERINFO = $(VERINFO_TARGET)
|
||||
endif
|
||||
@ -39,6 +42,7 @@ ifneq ($(CROSS_BUILD),1)
|
||||
BUILD += \
|
||||
$(FILE2STR_TARGET) \
|
||||
$(MAKEDEP_TARGET) \
|
||||
$(MAKELIST_TARGET) \
|
||||
$(PNG2BDC_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
|
||||
#-------------------------------------------------
|
||||
|
203
src/build/makelist.c
Normal file
203
src/build/makelist.c
Normal 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;
|
||||
}
|
729
src/emu/audit.c
729
src/emu/audit.c
@ -4,8 +4,36 @@
|
||||
|
||||
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"
|
||||
|
||||
|
||||
//**************************************************************************
|
||||
// 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);
|
||||
static void audit_one_disk(emu_options &options, const rom_entry *rom, const game_driver *gamedrv, const char *validation, audit_record *record);
|
||||
static int rom_used_by_parent(emu_options &options, const game_driver *gamedrv, const hash_collection &romhashes, const game_driver **parent);
|
||||
|
||||
|
||||
|
||||
/***************************************************************************
|
||||
INLINE FUNCTIONS
|
||||
***************************************************************************/
|
||||
|
||||
/*-------------------------------------------------
|
||||
set_status - shortcut for setting status and
|
||||
substatus values
|
||||
-------------------------------------------------*/
|
||||
|
||||
INLINE void set_status(audit_record *record, UINT8 status, UINT8 substatus)
|
||||
media_auditor::media_auditor(const driver_enumerator &enumerator)
|
||||
: m_enumerator(enumerator),
|
||||
m_validation(AUDIT_VALIDATE_FULL),
|
||||
m_searchpath(NULL)
|
||||
{
|
||||
record->status = status;
|
||||
record->substatus = substatus;
|
||||
}
|
||||
|
||||
|
||||
//-------------------------------------------------
|
||||
// audit_media - audit the media described by the
|
||||
// currently-enumerated driver
|
||||
//-------------------------------------------------
|
||||
|
||||
/***************************************************************************
|
||||
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)
|
||||
media_auditor::summary media_auditor::audit_media(const char *validation)
|
||||
{
|
||||
machine_config config(*gamedrv, options);
|
||||
const rom_entry *region, *rom;
|
||||
const rom_source *source;
|
||||
audit_record *record;
|
||||
int anyfound = FALSE;
|
||||
int anyrequired = FALSE;
|
||||
int allshared = TRUE;
|
||||
int records;
|
||||
// start fresh
|
||||
m_record_list.reset();
|
||||
|
||||
/* determine the number of records we will generate */
|
||||
records = 0;
|
||||
bool source_is_gamedrv = true;
|
||||
for (source = rom_first_source(config); source != NULL; source = rom_next_source(*source))
|
||||
// store validation for later
|
||||
m_validation = validation;
|
||||
|
||||
// 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))
|
||||
for (rom = rom_first_file(region); rom != NULL; rom = rom_next_file(rom))
|
||||
if (ROMREGION_ISROMDATA(region) || ROMREGION_ISDISKDATA(region))
|
||||
{
|
||||
if (source_is_gamedrv && !ROM_ISOPTIONAL(rom))
|
||||
{
|
||||
hash_collection hashes(ROM_GETHASHDATA(rom));
|
||||
if (!hashes.flag(hash_collection::FLAG_NO_DUMP))
|
||||
{
|
||||
anyrequired = TRUE;
|
||||
if (allshared && !rom_used_by_parent(options, gamedrv, hashes, NULL))
|
||||
allshared = FALSE;
|
||||
}
|
||||
}
|
||||
records++;
|
||||
}
|
||||
// determine the search path for this source and iterate through the regions
|
||||
m_searchpath = source->searchpath();
|
||||
|
||||
// also determine if this is the driver's specific ROMs or not
|
||||
bool source_is_gamedrv = (dynamic_cast<const driver_device_config_base *>(source) != NULL);
|
||||
|
||||
// now iterate over regions and ROMs within
|
||||
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))
|
||||
{
|
||||
hash_collection hashes(ROM_GETHASHDATA(rom));
|
||||
|
||||
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)
|
||||
{
|
||||
/* allocate memory for the records */
|
||||
*audit = global_alloc_array_clear(audit_record, records);
|
||||
record = *audit;
|
||||
// if we found nothing, we don't have the set at all
|
||||
if (!anyfound && anyrequired)
|
||||
m_record_list.reset();
|
||||
|
||||
// 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;
|
||||
for (rom = rom_first_file(region); rom; rom = rom_next_file(rom))
|
||||
// by default we just search using the driver name
|
||||
astring searchpath(m_enumerator.driver().name);
|
||||
|
||||
// iterate over samples in this entry
|
||||
for (int sampnum = 0; intf->samplenames[sampnum] != NULL; sampnum++)
|
||||
{
|
||||
/* audit a file */
|
||||
if (ROMREGION_ISROMDATA(region))
|
||||
{
|
||||
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
|
||||
// starred entries indicate an additional searchpath
|
||||
if (intf->samplenames[sampnum][0] == '*')
|
||||
{
|
||||
searchpath.cat(";").cat(&intf->samplenames[sampnum][1]);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (source_is_gamedrv && record->status != AUDIT_STATUS_NOT_FOUND && (allshared || !rom_used_by_parent(options, gamedrv, record->exphashes, NULL)))
|
||||
anyfound = TRUE;
|
||||
|
||||
record++;
|
||||
|
||||
// create a new record
|
||||
audit_record &record = m_record_list.append(*global_alloc(audit_record(intf->samplenames[sampnum], audit_record::MEDIA_SAMPLE)));
|
||||
|
||||
// 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;
|
||||
}
|
||||
}
|
||||
|
||||
/* if we found nothing, we don't have the set at all */
|
||||
if (!anyfound && anyrequired)
|
||||
{
|
||||
global_free(*audit);
|
||||
*audit = NULL;
|
||||
records = 0;
|
||||
}
|
||||
|
||||
return records;
|
||||
|
||||
// return a summary
|
||||
return summarize();
|
||||
}
|
||||
|
||||
|
||||
/*-------------------------------------------------
|
||||
audit_samples - validate the samples for a
|
||||
game
|
||||
-------------------------------------------------*/
|
||||
//-------------------------------------------------
|
||||
// summary - generate a summary, with an optional
|
||||
// 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);
|
||||
audit_record *record;
|
||||
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)
|
||||
// no count AND no records means not found
|
||||
if (m_record_list.count() == 0)
|
||||
return NOTFOUND;
|
||||
|
||||
/* loop over records */
|
||||
for (recnum = 0; recnum < count; recnum++)
|
||||
// loop over records
|
||||
summary overall_status = CORRECT;
|
||||
for (audit_record *record = m_record_list.first(); record != NULL; record = record->next())
|
||||
{
|
||||
const audit_record *record = &records[recnum];
|
||||
int best_new_status = INCORRECT;
|
||||
summary best_new_status = INCORRECT;
|
||||
|
||||
/* skip anything that's fine */
|
||||
if (record->substatus == SUBSTATUS_GOOD)
|
||||
// skip anything that's fine
|
||||
if (record->substatus() == audit_record::SUBSTATUS_GOOD)
|
||||
continue;
|
||||
|
||||
/* output the game name, file name, and length (if applicable) */
|
||||
if (output)
|
||||
// output the game name, file name, and length (if applicable)
|
||||
if (string != NULL)
|
||||
{
|
||||
mame_printf_info("%-8s: %s", gamedrv->name, record->name);
|
||||
if (record->explength > 0)
|
||||
mame_printf_info(" (%d bytes)", record->explength);
|
||||
mame_printf_info(" - ");
|
||||
string->catprintf("%-12s: %s", m_enumerator.driver().name, record->name());
|
||||
if (record->expected_length() > 0)
|
||||
string->catprintf(" (%d bytes)", record->expected_length());
|
||||
string->catprintf(" - ");
|
||||
}
|
||||
|
||||
/* use the substatus for finer details */
|
||||
switch (record->substatus)
|
||||
// use the substatus for finer details
|
||||
switch (record->substatus())
|
||||
{
|
||||
case SUBSTATUS_GOOD_NEEDS_REDUMP:
|
||||
if (output) mame_printf_info("NEEDS REDUMP\n");
|
||||
case audit_record::SUBSTATUS_GOOD_NEEDS_REDUMP:
|
||||
if (string != NULL) string->catprintf("NEEDS REDUMP\n");
|
||||
best_new_status = BEST_AVAILABLE;
|
||||
break;
|
||||
|
||||
case SUBSTATUS_FOUND_NODUMP:
|
||||
if (output) mame_printf_info("NO GOOD DUMP KNOWN\n");
|
||||
case audit_record::SUBSTATUS_FOUND_NODUMP:
|
||||
if (string != NULL) string->catprintf("NO GOOD DUMP KNOWN\n");
|
||||
best_new_status = BEST_AVAILABLE;
|
||||
break;
|
||||
|
||||
case SUBSTATUS_FOUND_BAD_CHECKSUM:
|
||||
if (output)
|
||||
case audit_record::SUBSTATUS_FOUND_BAD_CHECKSUM:
|
||||
if (string != NULL)
|
||||
{
|
||||
astring tempstr;
|
||||
mame_printf_info("INCORRECT CHECKSUM:\n");
|
||||
mame_printf_info("EXPECTED: %s\n", record->exphashes.macro_string(tempstr));
|
||||
mame_printf_info(" FOUND: %s\n", record->hashes.macro_string(tempstr));
|
||||
string->catprintf("INCORRECT CHECKSUM:\n");
|
||||
string->catprintf("EXPECTED: %s\n", record->expected_hashes().macro_string(tempstr));
|
||||
string->catprintf(" FOUND: %s\n", record->actual_hashes().macro_string(tempstr));
|
||||
}
|
||||
break;
|
||||
|
||||
case SUBSTATUS_FOUND_WRONG_LENGTH:
|
||||
if (output) mame_printf_info("INCORRECT LENGTH: %d bytes\n", record->length);
|
||||
case audit_record::SUBSTATUS_FOUND_WRONG_LENGTH:
|
||||
if (string != NULL) string->catprintf("INCORRECT LENGTH: %d bytes\n", record->actual_length());
|
||||
break;
|
||||
|
||||
case SUBSTATUS_NOT_FOUND:
|
||||
if (output) mame_printf_info("NOT FOUND\n");
|
||||
case audit_record::SUBSTATUS_NOT_FOUND:
|
||||
if (string != NULL) string->catprintf("NOT FOUND\n");
|
||||
break;
|
||||
|
||||
case SUBSTATUS_NOT_FOUND_NODUMP:
|
||||
if (output) mame_printf_info("NOT FOUND - NO GOOD DUMP KNOWN\n");
|
||||
case audit_record::SUBSTATUS_NOT_FOUND_NODUMP:
|
||||
if (string != NULL) string->catprintf("NOT FOUND - NO GOOD DUMP KNOWN\n");
|
||||
best_new_status = BEST_AVAILABLE;
|
||||
break;
|
||||
|
||||
case SUBSTATUS_NOT_FOUND_OPTIONAL:
|
||||
if (output) mame_printf_info("NOT FOUND BUT OPTIONAL\n");
|
||||
case audit_record::SUBSTATUS_NOT_FOUND_OPTIONAL:
|
||||
if (string != NULL) string->catprintf("NOT FOUND BUT OPTIONAL\n");
|
||||
best_new_status = BEST_AVAILABLE;
|
||||
break;
|
||||
|
||||
case SUBSTATUS_NOT_FOUND_PARENT:
|
||||
if (output) mame_printf_info("NOT FOUND (shared with parent)\n");
|
||||
case audit_record::SUBSTATUS_NOT_FOUND_PARENT:
|
||||
if (string != NULL) string->catprintf("NOT FOUND (shared with parent)\n");
|
||||
break;
|
||||
|
||||
case SUBSTATUS_NOT_FOUND_BIOS:
|
||||
if (output) mame_printf_info("NOT FOUND (BIOS)\n");
|
||||
case audit_record::SUBSTATUS_NOT_FOUND_BIOS:
|
||||
if (string != NULL) string->catprintf("NOT FOUND (BIOS)\n");
|
||||
break;
|
||||
|
||||
default:
|
||||
assert(false);
|
||||
}
|
||||
|
||||
/* downgrade the overall status if necessary */
|
||||
// downgrade the overall status if necessary
|
||||
overall_status = MAX(overall_status, best_new_status);
|
||||
}
|
||||
|
||||
return overall_status;
|
||||
}
|
||||
|
||||
|
||||
//-------------------------------------------------
|
||||
// audit_one_rom - validate a single ROM entry
|
||||
//-------------------------------------------------
|
||||
|
||||
/***************************************************************************
|
||||
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)
|
||||
audit_record *media_auditor::audit_one_rom(const rom_entry *rom)
|
||||
{
|
||||
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;
|
||||
bool has_crc = record.expected_hashes().crc(crc);
|
||||
|
||||
/* fill in the record basics */
|
||||
record->type = AUDIT_FILE_ROM;
|
||||
record->name = ROM_GETNAME(rom);
|
||||
record->exphashes.from_internal_string(ROM_GETHASHDATA(rom));
|
||||
record->length = 0;
|
||||
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))
|
||||
// find the file and checksum it, getting the file length along the way
|
||||
emu_file file(m_enumerator.options().media_path(), OPEN_FLAG_READ | OPEN_FLAG_NO_PRELOAD);
|
||||
path_iterator path(m_searchpath);
|
||||
astring curpath;
|
||||
while (path.next(curpath, record.name()))
|
||||
{
|
||||
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;
|
||||
if (has_crc)
|
||||
filerr = file.open(drv->name, PATH_SEPARATOR, ROM_GETNAME(rom), crc);
|
||||
filerr = file.open(curpath, crc);
|
||||
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)
|
||||
{
|
||||
record->hashes = file.hashes(validation);
|
||||
record->length = (UINT32)file.size();
|
||||
record.set_actual(file.hashes(m_validation), file.size());
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* if not found, check the region as a backup */
|
||||
if (record->length == 0 && regiontag != NULL)
|
||||
{
|
||||
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);
|
||||
}
|
||||
|
||||
// compute the final status
|
||||
compute_status(record, rom, record.actual_length() != 0);
|
||||
return &record;
|
||||
}
|
||||
|
||||
|
||||
/*-------------------------------------------------
|
||||
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;
|
||||
chd_file *source;
|
||||
chd_error err;
|
||||
|
||||
/* fill in the record basics */
|
||||
record->type = AUDIT_FILE_DISK;
|
||||
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
|
||||
chd_error err = open_disk_image(m_enumerator.options(), &m_enumerator.driver(), rom, &source_file, &source, NULL);
|
||||
|
||||
// if we succeeded, get the hashes
|
||||
if (err == CHDERR_NONE)
|
||||
{
|
||||
static const UINT8 nullhash[20] = { 0 };
|
||||
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)
|
||||
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)
|
||||
record->hashes.add_from_buffer(hash_collection::HASH_SHA1, header.sha1, sizeof(header.sha1));
|
||||
|
||||
/* found but needs a dump */
|
||||
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 good */
|
||||
else
|
||||
set_status(record, AUDIT_STATUS_GOOD, SUBSTATUS_GOOD);
|
||||
hashes.add_from_buffer(hash_collection::HASH_SHA1, header.sha1, sizeof(header.sha1));
|
||||
|
||||
// update the actual values
|
||||
record.set_actual(hashes);
|
||||
|
||||
// close the file and release the source
|
||||
chd_close(source);
|
||||
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
|
||||
ROM is also used by the parent
|
||||
-------------------------------------------------*/
|
||||
//-------------------------------------------------
|
||||
// compute_status - compute a detailed status
|
||||
// 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;
|
||||
|
||||
/* iterate up the parent chain */
|
||||
for (drv = driver_get_clone(gamedrv); drv != NULL; drv = driver_get_clone(drv))
|
||||
// if not found, provide more details
|
||||
if (!found)
|
||||
{
|
||||
machine_config config(*drv, options);
|
||||
const rom_entry *region;
|
||||
const rom_entry *rom;
|
||||
int parent;
|
||||
|
||||
// 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 */
|
||||
for (const rom_source *source = rom_first_source(config); source != NULL; source = rom_next_source(*source))
|
||||
for (region = rom_first_region(*source); region; region = rom_next_region(region))
|
||||
for (rom = rom_first_file(region); rom; rom = rom_next_file(rom))
|
||||
// optional ROM
|
||||
else if (ROM_ISOPTIONAL(rom))
|
||||
record.set_status(audit_record::STATUS_NOT_FOUND, audit_record::SUBSTATUS_NOT_FOUND_OPTIONAL);
|
||||
|
||||
// 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));
|
||||
if (!hashes.flag(hash_collection::FLAG_NO_DUMP) && hashes == romhashes)
|
||||
{
|
||||
if (parent != NULL)
|
||||
*parent = drv;
|
||||
return TRUE;
|
||||
}
|
||||
return drvindex;
|
||||
}
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
}
|
||||
|
221
src/emu/audit.h
221
src/emu/audit.h
@ -4,8 +4,36 @@
|
||||
|
||||
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_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
|
||||
{
|
||||
AUDIT_STATUS_GOOD = 0,
|
||||
AUDIT_STATUS_FOUND_INVALID,
|
||||
AUDIT_STATUS_NOT_FOUND,
|
||||
AUDIT_STATUS_ERROR
|
||||
};
|
||||
//**************************************************************************
|
||||
// TYPE DEFINITIONS
|
||||
//**************************************************************************
|
||||
|
||||
/* substatus values for audit_record.substatus */
|
||||
enum
|
||||
|
||||
// ======================> audit_record
|
||||
|
||||
// holds the result of auditing a single item
|
||||
class audit_record
|
||||
{
|
||||
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
|
||||
friend class simple_list<audit_record>;
|
||||
|
||||
public:
|
||||
// media types
|
||||
enum media_type
|
||||
{
|
||||
MEDIA_ROM = 0,
|
||||
MEDIA_DISK,
|
||||
MEDIA_SAMPLE
|
||||
};
|
||||
|
||||
// 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
|
||||
|
||||
/***************************************************************************
|
||||
TYPE DEFINITIONS
|
||||
***************************************************************************/
|
||||
|
||||
typedef struct _audit_record audit_record;
|
||||
struct _audit_record
|
||||
// class which manages auditing of items
|
||||
class media_auditor
|
||||
{
|
||||
UINT8 type; /* type of item that was audited */
|
||||
UINT8 status; /* status of audit on this item */
|
||||
UINT8 substatus; /* finer-detail status */
|
||||
const char * name; /* name of item */
|
||||
UINT32 explength; /* expected length of item */
|
||||
UINT32 length; /* actual length of item */
|
||||
hash_collection exphashes; /* expected hash data */
|
||||
hash_collection hashes; /* actual hash information */
|
||||
public:
|
||||
// summary values
|
||||
enum summary
|
||||
{
|
||||
CORRECT = 0,
|
||||
NONE_NEEDED,
|
||||
BEST_AVAILABLE,
|
||||
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__ */
|
||||
|
2060
src/emu/clifront.c
2060
src/emu/clifront.c
File diff suppressed because it is too large
Load Diff
@ -80,6 +80,7 @@
|
||||
// TYPE DEFINITIONS
|
||||
//**************************************************************************
|
||||
|
||||
// cli_options wraps the general emu options with CLI-specific additions
|
||||
class cli_options : public emu_options
|
||||
{
|
||||
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);
|
||||
|
||||
/***************************************************************************
|
||||
FUNCTION PROTOTYPES
|
||||
***************************************************************************/
|
||||
private:
|
||||
// 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__ */
|
||||
|
@ -235,13 +235,13 @@ static int config_load_xml(running_machine &machine, emu_file &file, int which_t
|
||||
|
||||
case CONFIG_TYPE_CONTROLLER:
|
||||
{
|
||||
const game_driver *clone_of;
|
||||
int clone_of;
|
||||
/* match on: default, game name, source file name, parent name, grandparent name */
|
||||
if (strcmp(name, "default") != 0 &&
|
||||
strcmp(name, machine.system().name) != 0 &&
|
||||
strcmp(name, srcfile) != 0 &&
|
||||
((clone_of = driver_get_clone(&machine.system())) == NULL || strcmp(name, clone_of->name) != 0) &&
|
||||
(clone_of == NULL || ((clone_of = driver_get_clone(clone_of)) == 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 == -1 || ((clone_of = driver_list::clone(clone_of)) == -1) || strcmp(name, driver_list::driver(clone_of).name) != 0))
|
||||
continue;
|
||||
break;
|
||||
}
|
||||
|
@ -336,6 +336,12 @@ void *malloc_file_line(size_t size, const char *file, int line)
|
||||
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 )
|
||||
{
|
||||
osd_free( memory );
|
||||
|
@ -93,7 +93,7 @@ text_buffer *text_buffer_alloc(UINT32 bytes, UINT32 lines)
|
||||
return NULL;
|
||||
|
||||
/* allocate memory for the buffer itself */
|
||||
text->buffer = (char *)osd_malloc(bytes);
|
||||
text->buffer = (char *)osd_malloc_array(bytes);
|
||||
if (!text->buffer)
|
||||
{
|
||||
osd_free(text);
|
||||
@ -101,7 +101,7 @@ text_buffer *text_buffer_alloc(UINT32 bytes, UINT32 lines)
|
||||
}
|
||||
|
||||
/* 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)
|
||||
{
|
||||
osd_free(text->buffer);
|
||||
|
@ -88,6 +88,7 @@ legacy_cpu_device_config::legacy_cpu_device_config(const machine_config &mconfig
|
||||
// set the real name
|
||||
m_name = get_legacy_config_string(DEVINFO_STR_NAME);
|
||||
m_shortname = get_legacy_config_string(DEVINFO_STR_SHORTNAME);
|
||||
m_searchpath = m_shortname;
|
||||
}
|
||||
|
||||
|
||||
|
@ -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
|
||||
//-------------------------------------------------
|
||||
|
@ -262,6 +262,7 @@ class device_config
|
||||
protected:
|
||||
// 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 *shortname, const char *tag, const device_config *owner, UINT32 clock, UINT32 param = 0);
|
||||
virtual ~device_config();
|
||||
|
||||
public:
|
||||
@ -289,6 +290,7 @@ public:
|
||||
UINT32 clock() const { return m_clock; }
|
||||
const char *name() const { return m_name; }
|
||||
const char *shortname() const { return m_shortname; }
|
||||
const char *searchpath() const { return m_searchpath; }
|
||||
const char *tag() const { return m_tag; }
|
||||
const void *static_config() const { return m_static_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
|
||||
|
||||
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:
|
||||
astring m_tag; // tag for this instance
|
||||
bool m_config_complete; // have we completed our configuration?
|
||||
|
@ -62,6 +62,7 @@ legacy_device_config_base::legacy_device_config_base(const machine_config &mconf
|
||||
// set the proper name
|
||||
m_name = get_legacy_config_string(DEVINFO_STR_NAME);
|
||||
m_shortname = get_legacy_config_string(DEVINFO_STR_SHORTNAME);
|
||||
m_searchpath = m_shortname;
|
||||
}
|
||||
|
||||
|
||||
|
@ -126,7 +126,7 @@ enum
|
||||
DEVINFO_STR_FIRST = 0x30000,
|
||||
|
||||
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_VERSION, // R/O: version of the device
|
||||
DEVINFO_STR_SOURCE_FILE, // R/O: file containing the device implementation
|
||||
|
@ -383,7 +383,6 @@ bool device_image_interface::try_change_working_directory(const char *subdir)
|
||||
|
||||
void device_image_interface::setup_working_directory()
|
||||
{
|
||||
const game_driver *gamedrv;
|
||||
char *dst = NULL;
|
||||
|
||||
osd_get_full_path(&dst,".");
|
||||
@ -394,10 +393,10 @@ void device_image_interface::setup_working_directory()
|
||||
if (try_change_working_directory("software"))
|
||||
{
|
||||
/* now down to a directory for this computer */
|
||||
gamedrv = &device().machine().system();
|
||||
while(gamedrv && !try_change_working_directory(gamedrv->name))
|
||||
int gamedrv = driver_list::find(device().machine().system());
|
||||
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);
|
||||
|
520
src/emu/driver.c
520
src/emu/driver.c
@ -2,10 +2,38 @@
|
||||
|
||||
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
|
||||
//-------------------------------------------------
|
||||
|
||||
|
||||
|
||||
/***************************************************************************
|
||||
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)
|
||||
driver_list::driver_list()
|
||||
{
|
||||
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
|
||||
clone of a game driver.
|
||||
-------------------------------------------------*/
|
||||
//-------------------------------------------------
|
||||
// find - find a driver by name
|
||||
//-------------------------------------------------
|
||||
|
||||
const game_driver *driver_get_clone(const game_driver *driver)
|
||||
int driver_list::find(const char *name)
|
||||
{
|
||||
/* if no clone, easy out */
|
||||
if (driver->parent == NULL || (driver->parent[0] == '0' && driver->parent[1] == 0))
|
||||
return NULL;
|
||||
// if no name, bail
|
||||
if (name == NULL)
|
||||
return -1;
|
||||
|
||||
/* convert the name to a game_driver */
|
||||
return driver_get_name(driver->parent);
|
||||
// create a dummy item for comparison purposes
|
||||
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
|
||||
for a given driver
|
||||
-------------------------------------------------*/
|
||||
//-------------------------------------------------
|
||||
// driver_sort_callback - compare two items in
|
||||
// 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[;...]]
|
||||
string = driver.name;
|
||||
for (const game_driver *parent = driver_get_clone(&driver); parent != NULL; parent = driver_get_clone(parent))
|
||||
string.cat(";").cat(parent->name);
|
||||
return string;
|
||||
const game_driver * const *item1 = reinterpret_cast<const game_driver * const *>(elem1);
|
||||
const game_driver * const *item2 = reinterpret_cast<const game_driver * const *>(elem2);
|
||||
return mame_stricmp((*item1)->name, (*item2)->name);
|
||||
}
|
||||
|
||||
|
||||
/*-------------------------------------------------
|
||||
driver_list_get_approx_matches - find the best
|
||||
n matches to a driver name.
|
||||
-------------------------------------------------*/
|
||||
//-------------------------------------------------
|
||||
// penalty_compare - compare two strings for
|
||||
// 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)
|
||||
{
|
||||
#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 driver_list::penalty_compare(const char *source, const char *target)
|
||||
{
|
||||
int gaps = 1;
|
||||
int last = TRUE;
|
||||
bool last = true;
|
||||
|
||||
/* scan the strings */
|
||||
// scan the strings
|
||||
for ( ; *source && *target; target++)
|
||||
{
|
||||
/* do a case insensitive match */
|
||||
int match = (tolower((UINT8)*source) == tolower((UINT8)*target));
|
||||
// do a case insensitive match
|
||||
bool match = (tolower((UINT8)*source) == tolower((UINT8)*target));
|
||||
|
||||
/* if we matched, advance the source */
|
||||
// if we matched, advance the source
|
||||
if (match)
|
||||
source++;
|
||||
|
||||
/* if the match state changed, count gaps */
|
||||
// if the match state changed, count gaps
|
||||
if (match != last)
|
||||
{
|
||||
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++)
|
||||
gaps++;
|
||||
|
||||
/* if we matched perfectly, gaps == 0 */
|
||||
// if we matched perfectly, gaps == 0
|
||||
if (gaps == 1 && *source == 0 && *target == 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;
|
||||
|
||||
for (count = 0; driverlist[count] != NULL; count++) ;
|
||||
return count;
|
||||
include_all();
|
||||
}
|
||||
|
||||
/*-------------------------------------------------
|
||||
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))
|
||||
drv = driver_get_clone(drv);
|
||||
else if (drv->compatible_with)
|
||||
drv = driver_get_name(drv->compatible_with);
|
||||
else
|
||||
drv = NULL;
|
||||
return drv;
|
||||
filter(string);
|
||||
}
|
||||
|
||||
|
||||
driver_enumerator::driver_enumerator(emu_options &options, const game_driver &driver)
|
||||
: 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))
|
||||
{
|
||||
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);
|
||||
}
|
||||
|
154
src/emu/driver.h
154
src/emu/driver.h
@ -2,10 +2,38 @@
|
||||
|
||||
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
|
||||
@ -176,24 +306,8 @@ extern const game_driver GAME_NAME(NAME) = \
|
||||
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
|
||||
|
@ -20,7 +20,7 @@
|
||||
*
|
||||
*************************************/
|
||||
|
||||
static MACHINE_START( empty )
|
||||
static MACHINE_START( ___empty )
|
||||
{
|
||||
/* force the UI to show the game select screen */
|
||||
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 */
|
||||
MCFG_SCREEN_ADD("screen", RASTER)
|
||||
@ -54,8 +54,8 @@ MACHINE_CONFIG_END
|
||||
*
|
||||
*************************************/
|
||||
|
||||
ROM_START( empty )
|
||||
ROM_REGION( 0x10, "user1", 0 )
|
||||
ROM_START( ___empty )
|
||||
ROM_REGION( 0x10, "user1", ROMREGION_ERASEFF )
|
||||
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 )
|
||||
|
@ -338,5 +338,6 @@ $(EMUOBJ)/rendlay.o: $(EMULAYOUT)/dualhovu.lh \
|
||||
$(EMULAYOUT)/voffff20.lh \
|
||||
$(EMULAYOUT)/lcd.lh \
|
||||
$(EMULAYOUT)/lcd_rot.lh \
|
||||
$(EMULAYOUT)/pinball.lh \
|
||||
|
||||
$(EMUOBJ)/video.o: $(EMULAYOUT)/snap.lh
|
||||
|
@ -92,6 +92,7 @@ public:
|
||||
static UINT64 s_curid; // current ID
|
||||
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_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_freehead; // pointer to the head of the free list
|
||||
|
||||
@ -118,9 +119,10 @@ resource_pool global_resource_pool;
|
||||
const zeromem_t zeromem = { };
|
||||
|
||||
// globals for memory_entry
|
||||
UINT64 memory_entry::s_curid = 0;
|
||||
UINT64 memory_entry::s_curid = 1;
|
||||
osd_lock *memory_entry::s_lock = NULL;
|
||||
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_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
|
||||
// and line number information
|
||||
@ -189,7 +216,19 @@ void free_file_line(void *memory, const char *file, int line)
|
||||
// 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
|
||||
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)
|
||||
{
|
||||
// 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)
|
||||
{
|
||||
release_lock();
|
||||
@ -468,8 +507,8 @@ memory_entry *memory_entry::allocate(size_t size, void *base, const char *file,
|
||||
// populate it
|
||||
entry->m_size = size;
|
||||
entry->m_base = base;
|
||||
entry->m_file = file;
|
||||
entry->m_line = line;
|
||||
entry->m_file = s_tracking ? file : NULL;
|
||||
entry->m_line = s_tracking ? line : 0;
|
||||
entry->m_id = s_curid++;
|
||||
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);
|
||||
@ -561,5 +600,5 @@ void memory_entry::report_unfreed()
|
||||
release_lock();
|
||||
|
||||
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);
|
||||
}
|
||||
|
@ -46,10 +46,26 @@
|
||||
#include "osdcore.h"
|
||||
|
||||
|
||||
//**************************************************************************
|
||||
// DEBUGGING
|
||||
//**************************************************************************
|
||||
|
||||
// set to 1 to track memory allocated by emualloc.h itself as well
|
||||
#define TRACK_SELF_MEMORY (0)
|
||||
|
||||
|
||||
|
||||
//**************************************************************************
|
||||
// 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
|
||||
#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)
|
||||
@ -72,11 +88,13 @@
|
||||
|
||||
// allocate memory with file and line number information
|
||||
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
|
||||
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
|
||||
void track_memory(bool track);
|
||||
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)
|
||||
{
|
||||
void *result = malloc_file_line(size, NULL, 0);
|
||||
void *result = malloc_array_file_line(size, NULL, 0);
|
||||
if (result == NULL)
|
||||
throw std::bad_alloc();
|
||||
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)
|
||||
{
|
||||
void *result = malloc_file_line(size, file, line);
|
||||
void *result = malloc_array_file_line(size, file, line);
|
||||
if (result == NULL)
|
||||
throw std::bad_alloc();
|
||||
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)
|
||||
{
|
||||
void *result = malloc_file_line(size, file, line);
|
||||
void *result = malloc_array_file_line(size, file, line);
|
||||
if (result == NULL)
|
||||
throw std::bad_alloc();
|
||||
memset(result, 0, size);
|
||||
@ -270,8 +288,8 @@ public:
|
||||
bool contains(void *ptrstart, void *ptrend);
|
||||
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_array(T* array, int count) { add(*new(__FILE__, __LINE__) resource_pool_array<T>(array, count)); return array; }
|
||||
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(*EMUALLOC_SELF_NEW resource_pool_array<T>(array, count)); return array; }
|
||||
|
||||
private:
|
||||
static const int k_hash_prime = 193;
|
||||
@ -306,7 +324,7 @@ extern const zeromem_t zeromem;
|
||||
#undef realloc
|
||||
#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 realloc(x,y) __error_realloc_is_dangerous__
|
||||
#define free(x) free_file_line(x, __FILE__, __LINE__)
|
||||
|
@ -349,12 +349,12 @@ void emu_options::parse_standard_inis(astring &error_string)
|
||||
}
|
||||
|
||||
// then parse the grandparent, parent, and system-specific INIs
|
||||
const game_driver *parent = driver_get_clone(cursystem);
|
||||
const game_driver *gparent = (parent != NULL) ? driver_get_clone(parent) : NULL;
|
||||
if (gparent != NULL)
|
||||
parse_one_ini(gparent->name, OPTION_PRIORITY_GPARENT_INI, &error_string);
|
||||
if (parent != NULL)
|
||||
parse_one_ini(parent->name, OPTION_PRIORITY_PARENT_INI, &error_string);
|
||||
int parent = driver_list::clone(*cursystem);
|
||||
int gparent = (parent != -1) ? driver_list::clone(parent) : -1;
|
||||
if (gparent != -1)
|
||||
parse_one_ini(driver_list::driver(gparent).name, OPTION_PRIORITY_GPARENT_INI, &error_string);
|
||||
if (parent != -1)
|
||||
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);
|
||||
}
|
||||
|
||||
@ -367,7 +367,8 @@ void emu_options::parse_standard_inis(astring &error_string)
|
||||
const game_driver *emu_options::system() const
|
||||
{
|
||||
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;
|
||||
}
|
||||
|
||||
|
||||
|
@ -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
|
||||
|
||||
// a fixed_allocator is a simple class that maintains a free pool of objects
|
||||
|
@ -593,7 +593,7 @@ bool hash_collection::remove(char type)
|
||||
// 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
|
||||
hash_base *crchash = hash(HASH_CRC);
|
||||
@ -601,7 +601,7 @@ bool hash_collection::crc(UINT32 &result)
|
||||
return false;
|
||||
|
||||
// downcast to a hash_crc and convert to a UINT32
|
||||
result = *downcast<hash_crc *>(crchash);
|
||||
result = *downcast<const hash_crc *>(crchash);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -161,7 +161,7 @@ public:
|
||||
bool remove(char type);
|
||||
|
||||
// CRC-specific helpers
|
||||
bool crc(UINT32 &result);
|
||||
bool crc(UINT32 &result) const;
|
||||
hash_base *add_crc(UINT32 crc);
|
||||
|
||||
// string conversion
|
||||
|
1924
src/emu/info.c
1924
src/emu/info.c
File diff suppressed because it is too large
Load Diff
@ -4,8 +4,36 @@
|
||||
|
||||
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__
|
||||
|
||||
|
||||
/***************************************************************************
|
||||
FUNCTION PROTOTYPES
|
||||
***************************************************************************/
|
||||
//**************************************************************************
|
||||
// FUNCTION PROTOTYPES
|
||||
//**************************************************************************
|
||||
|
||||
/* print the MAME database in XML format */
|
||||
void print_mame_xml(FILE* out, const game_driver* const games[], const char *gamename, emu_options &options);
|
||||
// helper class to putput
|
||||
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__ */
|
||||
|
@ -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)
|
||||
{
|
||||
downcast<driver_device_config_base *>(device)->m_system = game;
|
||||
downcast<driver_device_config_base *>(device)->m_shortname = game->name;
|
||||
driver_device_config_base *base = downcast<driver_device_config_base *>(device);
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
|
||||
|
@ -157,7 +157,7 @@ int mame_execute(emu_options &options, osd_interface &osd)
|
||||
const game_driver *system = options.system();
|
||||
if (system == NULL)
|
||||
{
|
||||
system = &GAME_NAME(empty);
|
||||
system = &GAME_NAME(___empty);
|
||||
if (firstgame)
|
||||
started_empty = true;
|
||||
}
|
||||
|
@ -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);
|
||||
|
||||
// try to load another file based on the parent driver name
|
||||
const game_driver *cloneof = driver_get_clone(&system);
|
||||
if (cloneof != NULL)
|
||||
if (!load_layout_file(cloneof->name, cloneof->name))
|
||||
load_layout_file(cloneof->name, "default");
|
||||
int cloneof = driver_list::clone(system);
|
||||
if (cloneof != -1)
|
||||
if (!load_layout_file(driver_list::driver(cloneof).name, driver_list::driver(cloneof).name))
|
||||
load_layout_file(driver_list::driver(cloneof).name, "default");
|
||||
|
||||
// now do the built-in layouts for single-screen games
|
||||
if (m_manager.machine().m_devicelist.count(SCREEN) == 1)
|
||||
|
@ -117,6 +117,10 @@
|
||||
#include "lcd.lh"
|
||||
#include "lcd_rot.lh"
|
||||
|
||||
// generic dummy pinball layout
|
||||
#include "pinball.lh"
|
||||
|
||||
|
||||
|
||||
//**************************************************************************
|
||||
// CONSTANTS
|
||||
|
@ -614,7 +614,6 @@ static int open_rom_file(rom_load_data *romdata, const char *regiontag, const ro
|
||||
{
|
||||
file_error filerr = FILERR_NOT_FOUND;
|
||||
UINT32 romsize = rom_file_size(romp);
|
||||
const game_driver *drv;
|
||||
|
||||
/* update status display */
|
||||
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
|
||||
attempts any kind of load by checksum supported by the archives. */
|
||||
romdata->file = NULL;
|
||||
for (drv = &romdata->machine().system(); romdata->file == NULL && drv != NULL; drv = driver_get_clone(drv))
|
||||
if (drv->name != NULL && *drv->name != 0)
|
||||
filerr = common_process_file(romdata->machine().options(), drv->name, has_crc, crc, romp, &romdata->file);
|
||||
for (int drv = driver_list::find(romdata->machine().system()); romdata->file == NULL && drv != -1; drv = driver_list::clone(drv))
|
||||
filerr = common_process_file(romdata->machine().options(), driver_list::driver(drv).name, has_crc, crc, romp, &romdata->file);
|
||||
|
||||
/* if the region is load by name, load the ROM from there */
|
||||
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)
|
||||
{
|
||||
const game_driver *drv, *searchdrv;
|
||||
const rom_entry *region, *rom;
|
||||
const rom_source *source;
|
||||
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 */
|
||||
filerr = FILERR_NOT_FOUND;
|
||||
for (searchdrv = gamedrv; searchdrv != NULL && filerr != FILERR_NONE; searchdrv = driver_get_clone(searchdrv))
|
||||
filerr = common_process_file(options, searchdrv->name, ".chd", romp, image_file);
|
||||
for (int searchdrv = driver_list::find(*gamedrv); searchdrv != -1 && filerr != FILERR_NONE; searchdrv = driver_list::clone(searchdrv))
|
||||
filerr = common_process_file(options, driver_list::driver(searchdrv).name, ".chd", romp, image_file);
|
||||
|
||||
if (filerr != FILERR_NONE)
|
||||
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 */
|
||||
/* and try to open that */
|
||||
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 (region = rom_first_region(*source); region != NULL; region = rom_next_region(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 */
|
||||
filerr = FILERR_NOT_FOUND;
|
||||
for (searchdrv = drv; searchdrv != NULL && filerr != FILERR_NONE; searchdrv = driver_get_clone(searchdrv))
|
||||
filerr = common_process_file(options, searchdrv->name, ".chd", rom, image_file);
|
||||
for (int searchdrv = drv; searchdrv != -1 && filerr != FILERR_NONE; searchdrv = driver_list::clone(searchdrv))
|
||||
filerr = common_process_file(options, driver_list::driver(searchdrv).name, ".chd", rom, image_file);
|
||||
|
||||
if (filerr != FILERR_NONE)
|
||||
filerr = common_process_file(options, NULL, ".chd", rom, image_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)
|
||||
: 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_memory_interface(mconfig, *this),
|
||||
m_space_config("samples", ENDIANNESS_LITTLE, 8, 32, 0, NULL, *ADDRESS_MAP_NAME(bsmt2000)),
|
||||
m_ready_callback(NULL)
|
||||
{
|
||||
m_shortname = "bsmt2000";
|
||||
}
|
||||
|
||||
|
||||
|
@ -126,7 +126,7 @@ void wav_add_data_32(wav_file *wav, INT32 *data, int samples, int shift)
|
||||
if (!wav) return;
|
||||
|
||||
/* allocate temp memory */
|
||||
temp = (INT16 *)osd_malloc(samples * sizeof(temp[0]));
|
||||
temp = (INT16 *)osd_malloc_array(samples * sizeof(temp[0]));
|
||||
if (!temp)
|
||||
return;
|
||||
|
||||
@ -154,7 +154,7 @@ void wav_add_data_16lr(wav_file *wav, INT16 *left, INT16 *right, int samples)
|
||||
if (!wav) return;
|
||||
|
||||
/* allocate temp memory */
|
||||
temp = (INT16 *)osd_malloc(samples * 2 * sizeof(temp[0]));
|
||||
temp = (INT16 *)osd_malloc_array(samples * 2 * sizeof(temp[0]));
|
||||
if (!temp)
|
||||
return;
|
||||
|
||||
@ -179,7 +179,7 @@ void wav_add_data_32lr(wav_file *wav, INT32 *left, INT32 *right, int samples, in
|
||||
if (!wav) return;
|
||||
|
||||
/* allocate temp memory */
|
||||
temp = (INT16 *)osd_malloc(samples * 2 * sizeof(temp[0]));
|
||||
temp = (INT16 *)osd_malloc_array(samples * 2 * sizeof(temp[0]));
|
||||
if (!temp)
|
||||
return;
|
||||
|
||||
|
28
src/emu/ui.c
28
src/emu/ui.c
@ -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,
|
||||
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;
|
||||
|
||||
/* initialize the on-screen display system */
|
||||
@ -907,8 +907,6 @@ static astring &warnings_string(running_machine &machine, astring &string)
|
||||
GAME_IMPERFECT_GRAPHICS | \
|
||||
GAME_NO_COCKTAIL)
|
||||
|
||||
int i;
|
||||
|
||||
string.reset();
|
||||
|
||||
/* 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 (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 */
|
||||
if (machine.system().flags & GAME_UNEMULATED_PROTECTION)
|
||||
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");
|
||||
|
||||
/* find the parent of this driver */
|
||||
clone_of = driver_get_clone(&machine.system());
|
||||
if (clone_of != NULL && !(clone_of->flags & GAME_IS_BIOS_ROOT))
|
||||
driver_enumerator drivlist(machine.options());
|
||||
int maindrv = drivlist.find(machine.system());
|
||||
int clone_of = drivlist.non_bios_clone(maindrv);
|
||||
if (clone_of != -1)
|
||||
maindrv = clone_of;
|
||||
else
|
||||
maindrv = &machine.system();
|
||||
|
||||
/* scan the driver list for any working clones and add them */
|
||||
foundworking = FALSE;
|
||||
for (i = 0; drivers[i] != NULL; i++)
|
||||
if (drivers[i] == maindrv || driver_get_clone(drivers[i]) == maindrv)
|
||||
if ((drivers[i]->flags & (GAME_NOT_WORKING | GAME_UNEMULATED_PROTECTION | GAME_MECHANICAL)) == 0)
|
||||
bool foundworking = false;
|
||||
while (drivlist.next())
|
||||
if (drivlist.current() == maindrv || drivlist.clone() == maindrv)
|
||||
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 */
|
||||
if (!foundworking)
|
||||
string.cat("\n\nThere are working clones of this game: ");
|
||||
else
|
||||
string.cat(", ");
|
||||
string.cat(drivers[i]->name);
|
||||
foundworking = TRUE;
|
||||
string.cat(drivlist.driver().name);
|
||||
foundworking = true;
|
||||
}
|
||||
|
||||
if (foundworking)
|
||||
|
100
src/emu/uimenu.c
100
src/emu/uimenu.c
@ -208,7 +208,7 @@ struct _select_game_state
|
||||
UINT8 error;
|
||||
UINT8 rerandomize;
|
||||
char search[40];
|
||||
const game_driver * matchlist[VISIBLE_GAMES_IN_LIST];
|
||||
int matchlist[VISIBLE_GAMES_IN_LIST];
|
||||
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 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_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 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_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 (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)
|
||||
strcpy(((select_game_state *)state)->search, (const char *)parameter);
|
||||
((select_game_state *)state)->matchlist[0] = -1;
|
||||
}
|
||||
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 */
|
||||
else
|
||||
{
|
||||
audit_record *audit;
|
||||
int audit_records;
|
||||
int audit_result;
|
||||
// audit the game first to see if we're going to work
|
||||
driver_enumerator enumerator(machine.options(), *driver);
|
||||
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 */
|
||||
audit_records = audit_images(menu->machine().options(), driver, AUDIT_VALIDATE_FAST, &audit);
|
||||
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)
|
||||
// if everything looks good, schedule the new driver
|
||||
if (summary == media_auditor::CORRECT || summary == media_auditor::BEST_AVAILABLE)
|
||||
{
|
||||
machine.schedule_new_driver(*driver);
|
||||
ui_menu_stack_reset(machine);
|
||||
}
|
||||
|
||||
/* otherwise, display an error */
|
||||
// otherwise, display an error
|
||||
else
|
||||
{
|
||||
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 */
|
||||
if (menustate->search[0] != 0 || menustate->matchlist[0] == NULL || menustate->rerandomize)
|
||||
driver_list_get_approx_matches(menustate->driverlist, menustate->search, matchcount, menustate->matchlist);
|
||||
assert(drivlist != NULL);
|
||||
if (menustate->search[0] != 0 || menustate->matchlist[0] == -1 || menustate->rerandomize)
|
||||
drivlist->find_approximate_matches(menustate->search, matchcount, menustate->matchlist);
|
||||
menustate->rerandomize = FALSE;
|
||||
|
||||
/* iterate over entries */
|
||||
for (curitem = 0; curitem < matchcount; curitem++)
|
||||
{
|
||||
const game_driver *driver = menustate->matchlist[curitem];
|
||||
if (driver != NULL)
|
||||
int curmatch = menustate->matchlist[curitem];
|
||||
if (curmatch != -1)
|
||||
{
|
||||
const game_driver *cloneof = driver_get_clone(driver);
|
||||
ui_menu_item_append(menu, driver->name, driver->description, (cloneof == NULL || (cloneof->flags & GAME_IS_BIOS_ROOT)) ? 0 : MENU_FLAG_INVERT, (void *)driver);
|
||||
int cloneof = drivlist->non_bios_clone(curmatch);
|
||||
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
|
||||
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)
|
||||
{
|
||||
int driver_count = driver_list_get_count(drivers);
|
||||
int drivnum, listnum;
|
||||
UINT8 *found;
|
||||
|
||||
/* create a sorted copy of the main driver list */
|
||||
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);
|
||||
// start with an empty list
|
||||
// hack alert: use new directly here to avoid reporting this one-time static memory as unfreed
|
||||
if (drivlist == NULL)
|
||||
drivlist = new driver_enumerator(menu->machine().options());
|
||||
drivlist->exclude_all();
|
||||
|
||||
/* open a path to the ROMs and find them in the array */
|
||||
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 */
|
||||
while ((dir = path.next()) != NULL)
|
||||
{
|
||||
game_driver tempdriver;
|
||||
game_driver *tempdriver_ptr;
|
||||
const game_driver **found_driver;
|
||||
char drivername[50];
|
||||
char *dst = drivername;
|
||||
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 = 0;
|
||||
|
||||
/* find it in the array */
|
||||
tempdriver.name = drivername;
|
||||
tempdriver_ptr = &tempdriver;
|
||||
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);
|
||||
}
|
||||
int drivnum = drivlist->find(drivername);
|
||||
if (drivnum != -1)
|
||||
drivlist->include(drivnum);
|
||||
}
|
||||
|
||||
/* now build the final list */
|
||||
for (drivnum = listnum = 0; drivnum < driver_count; drivnum++)
|
||||
if (found[drivnum / 8] & (1 << (drivnum % 8)))
|
||||
menustate->driverlist[listnum++] = menustate->driverlist[drivnum];
|
||||
drivlist->reset();
|
||||
int listnum = 0;
|
||||
while (drivlist->next())
|
||||
menustate->driverlist[listnum++] = &drivlist->driver();
|
||||
|
||||
/* NULL-terminate */
|
||||
menustate->driverlist[listnum] = NULL;
|
||||
|
@ -314,12 +314,11 @@ static bool validate_inlines(void)
|
||||
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 *clone_of;
|
||||
const game_driver &driver = drivlist.driver();
|
||||
const machine_config &config = drivlist.config();
|
||||
const char *compatible_with;
|
||||
const game_driver *other_drv;
|
||||
bool error = FALSE, is_clone;
|
||||
const char *s;
|
||||
|
||||
@ -343,27 +342,27 @@ static bool validate_driver(const machine_config &config, game_driver_map &names
|
||||
|
||||
/* determine the clone */
|
||||
is_clone = (strcmp(driver.parent, "0") != 0);
|
||||
clone_of = driver_get_clone(&driver);
|
||||
if (clone_of && (clone_of->flags & GAME_IS_BIOS_ROOT))
|
||||
int clone_of = drivlist.clone(driver);
|
||||
if (clone_of != -1 && (drivlist.driver(clone_of).flags & GAME_IS_BIOS_ROOT))
|
||||
is_clone = false;
|
||||
|
||||
/* if we have at least 100 drivers, validate the clone */
|
||||
/* (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);
|
||||
error = true;
|
||||
}
|
||||
|
||||
/* 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);
|
||||
error = true;
|
||||
}
|
||||
|
||||
/* 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);
|
||||
error = true;
|
||||
@ -392,23 +391,23 @@ static bool validate_driver(const machine_config &config, game_driver_map &names
|
||||
compatible_with = NULL;
|
||||
|
||||
/* 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);
|
||||
error = true;
|
||||
}
|
||||
|
||||
/* 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);
|
||||
error = true;
|
||||
}
|
||||
|
||||
/* 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);
|
||||
error = true;
|
||||
@ -432,9 +431,10 @@ static bool validate_driver(const machine_config &config, game_driver_map &names
|
||||
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;
|
||||
const char *last_rgnname = "???";
|
||||
const char *last_name = "???";
|
||||
@ -579,9 +579,10 @@ static bool validate_roms(const machine_config &config, region_array *rgninfo, g
|
||||
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 error = false;
|
||||
|
||||
@ -605,9 +606,10 @@ static bool validate_display(const machine_config &config)
|
||||
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;
|
||||
int gfxnum;
|
||||
|
||||
@ -939,12 +941,13 @@ static void validate_dip_settings(const input_field_config *field, const game_dr
|
||||
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 *port;
|
||||
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;
|
||||
char errorbuf[1024];
|
||||
bool error = false;
|
||||
@ -1088,10 +1091,11 @@ static bool validate_inputs(const machine_config &config, int_map &defstr_map, i
|
||||
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;
|
||||
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())
|
||||
{
|
||||
@ -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)
|
||||
{
|
||||
osd_ticks_t prep = 0;
|
||||
osd_ticks_t expansion = 0;
|
||||
osd_ticks_t driver_checks = 0;
|
||||
osd_ticks_t rom_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();
|
||||
|
||||
/* 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;
|
||||
region_array rgninfo;
|
||||
|
||||
@ -1198,39 +1202,34 @@ void validate_drivers(emu_options &options, const game_driver *curdriver)
|
||||
|
||||
try
|
||||
{
|
||||
/* expand the machine driver */
|
||||
expansion -= get_profile_ticks();
|
||||
machine_config config(driver, options);
|
||||
expansion += get_profile_ticks();
|
||||
|
||||
/* validate the driver entry */
|
||||
driver_checks -= get_profile_ticks();
|
||||
error = validate_driver(config, names, descriptions) || error;
|
||||
error = validate_driver(drivlist, names, descriptions) || error;
|
||||
driver_checks += get_profile_ticks();
|
||||
|
||||
/* validate the ROM information */
|
||||
rom_checks -= get_profile_ticks();
|
||||
error = validate_roms(config, &rgninfo, roms) || error;
|
||||
error = validate_roms(drivlist, &rgninfo, roms) || error;
|
||||
rom_checks += get_profile_ticks();
|
||||
|
||||
/* validate input ports */
|
||||
input_checks -= get_profile_ticks();
|
||||
error = validate_inputs(config, defstr, portlist) || error;
|
||||
error = validate_inputs(drivlist, defstr, portlist) || error;
|
||||
input_checks += get_profile_ticks();
|
||||
|
||||
/* validate the display */
|
||||
display_checks -= get_profile_ticks();
|
||||
error = validate_display(config) || error;
|
||||
error = validate_display(drivlist) || error;
|
||||
display_checks += get_profile_ticks();
|
||||
|
||||
/* validate the graphics decoding */
|
||||
gfx_checks -= get_profile_ticks();
|
||||
error = validate_gfx(config, &rgninfo) || error;
|
||||
error = validate_gfx(drivlist, &rgninfo) || error;
|
||||
gfx_checks += get_profile_ticks();
|
||||
|
||||
/* validate devices */
|
||||
device_checks -= get_profile_ticks();
|
||||
error = validate_devices(config, portlist, &rgninfo) || error;
|
||||
error = validate_devices(drivlist, portlist, &rgninfo) || error;
|
||||
device_checks += get_profile_ticks();
|
||||
}
|
||||
catch (emu_fatalerror &err)
|
||||
@ -1241,7 +1240,6 @@ void validate_drivers(emu_options &options, const game_driver *curdriver)
|
||||
|
||||
#if (REPORT_TIMES)
|
||||
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("ROM: %8dm\n", (int)(rom_checks / 1000000));
|
||||
mame_printf_info("CPU: %8dm\n", (int)(cpu_checks / 1000000));
|
||||
|
@ -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, 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, int start, int count = -1) { init().cpysubstr(string, start, count); }
|
||||
|
||||
astring &operator=(const char *string) { return cpy(string); }
|
||||
astring &operator=(const astring &string) { return cpy(string); }
|
||||
|
@ -141,7 +141,7 @@ char *core_strdup(const char *str)
|
||||
char *cpy = NULL;
|
||||
if (str != NULL)
|
||||
{
|
||||
cpy = (char *)osd_malloc(strlen(str) + 1);
|
||||
cpy = (char *)osd_malloc_array(strlen(str) + 1);
|
||||
if (cpy != NULL)
|
||||
strcpy(cpy, str);
|
||||
}
|
||||
|
@ -130,7 +130,7 @@ static osd_shared_mem *osd_sharedmem_alloc(const char *path, int create, size_t
|
||||
|
||||
if (create)
|
||||
{
|
||||
char *buf = (char *) osd_malloc(size);
|
||||
char *buf = (char *) osd_malloc_array(size);
|
||||
memset(buf,0, size);
|
||||
|
||||
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->fn = (char *) osd_malloc(strlen(path)+1);
|
||||
os_shmem->fn = (char *) osd_malloc_array(strlen(path)+1);
|
||||
strcpy(os_shmem->fn, path);
|
||||
|
||||
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->ptr = (void *) osd_malloc(size);
|
||||
os_shmem->ptr = (void *) osd_malloc_array(size);
|
||||
os_shmem->size = size;
|
||||
return os_shmem;
|
||||
}
|
||||
|
@ -1589,7 +1589,7 @@ static int megadrive_load_nonlist(device_image_interface &image)
|
||||
else if ((rawROM[0x2080] == 'E') && (rawROM[0x2081] == 'A') &&
|
||||
(rawROM[0x2082] == 'M' || rawROM[0x2082] == 'G'))
|
||||
{
|
||||
tmpROMnew = (unsigned char *)osd_malloc(length);
|
||||
tmpROMnew = global_alloc_array(unsigned char, length);
|
||||
secondhalf = &tmpROMnew[length >> 1];
|
||||
|
||||
if (!tmpROMnew)
|
||||
@ -1605,7 +1605,7 @@ static int megadrive_load_nonlist(device_image_interface &image)
|
||||
ROM[ptr] = secondhalf[ptr >> 1];
|
||||
ROM[ptr + 1] = tmpROMnew[ptr >> 1];
|
||||
}
|
||||
free(tmpROMnew);
|
||||
global_free(tmpROMnew);
|
||||
|
||||
#ifdef LSB_FIRST
|
||||
for (ptr = 0; ptr < length; ptr += 2)
|
||||
|
12225
src/mame/mame.lst
Normal file
12225
src/mame/mame.lst
Normal file
File diff suppressed because it is too large
Load Diff
@ -235,11 +235,6 @@ SOUNDS += MAS3507D
|
||||
# the list of drivers
|
||||
#-------------------------------------------------
|
||||
|
||||
ifeq ($(TARGET),mame)
|
||||
DRVLIBS += \
|
||||
$(MAMEOBJ)/mamedriv.o
|
||||
endif
|
||||
|
||||
DRVLIBS += \
|
||||
$(MAMEOBJ)/alba.a \
|
||||
$(MAMEOBJ)/alliedl.a \
|
||||
|
12225
src/mame/mamedriv.c
12225
src/mame/mamedriv.c
File diff suppressed because it is too large
Load Diff
@ -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
68
src/mame/tiny.lst
Normal 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
|
@ -71,7 +71,6 @@ SOUNDS += CEM3394
|
||||
#-------------------------------------------------
|
||||
|
||||
DRVLIBS = \
|
||||
$(MAMEOBJ)/tiny.o \
|
||||
$(EMUDRIVERS)/emudummy.o \
|
||||
$(MACHINE)/ticket.o \
|
||||
$(DRIVERS)/carpolo.o $(MACHINE)/carpolo.o $(VIDEO)/carpolo.o \
|
||||
|
@ -723,7 +723,7 @@ void osd_work_item_release(osd_work_item *item);
|
||||
***************************************************************************/
|
||||
|
||||
/*-----------------------------------------------------------------------------
|
||||
osd_malloc: allocate memory that
|
||||
osd_malloc: allocate memory
|
||||
|
||||
Parameters:
|
||||
|
||||
@ -741,6 +741,26 @@ void osd_work_item_release(osd_work_item *item);
|
||||
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
|
||||
|
||||
|
@ -93,10 +93,12 @@ static INT32 keyboard_get_state(void *device_internal, void *item_internal);
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
// cli_execute does the heavy lifting; if we have osd-specific options, we
|
||||
// would pass them as the third parameter here
|
||||
// cli_frontend does the heavy lifting; if we have osd-specific options, we
|
||||
// create a derivative of cli_options and add our own
|
||||
cli_options options;
|
||||
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
|
||||
// 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)
|
||||
fatalerror("Error creating keyboard device");
|
||||
|
||||
|
@ -44,7 +44,7 @@
|
||||
|
||||
|
||||
//============================================================
|
||||
// osd_alloc
|
||||
// osd_malloc
|
||||
//============================================================
|
||||
|
||||
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
|
||||
//============================================================
|
||||
|
@ -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))
|
||||
{
|
||||
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;
|
||||
}
|
||||
/* add us to the texture list */
|
||||
|
@ -67,7 +67,7 @@ struct _osd_directory
|
||||
|
||||
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;
|
||||
|
||||
strcpy(p, path);
|
||||
@ -126,13 +126,13 @@ osd_directory *osd_opendir(const char *dirname)
|
||||
dir->fd = NULL;
|
||||
}
|
||||
|
||||
tmpstr = (char *) osd_malloc(strlen(dirname)+1);
|
||||
tmpstr = (char *) osd_malloc_array(strlen(dirname)+1);
|
||||
strcpy(tmpstr, dirname);
|
||||
|
||||
if (tmpstr[0] == '$')
|
||||
{
|
||||
char *envval;
|
||||
envstr = (char *) osd_malloc(strlen(tmpstr)+1);
|
||||
envstr = (char *) osd_malloc_array(strlen(tmpstr)+1);
|
||||
|
||||
strcpy(envstr, tmpstr);
|
||||
|
||||
@ -149,7 +149,7 @@ osd_directory *osd_opendir(const char *dirname)
|
||||
{
|
||||
j = strlen(envval) + strlen(tmpstr) + 1;
|
||||
osd_free(tmpstr);
|
||||
tmpstr = (char *) osd_malloc(j);
|
||||
tmpstr = (char *) osd_malloc_array(j);
|
||||
|
||||
// start with the value of $HOME
|
||||
strcpy(tmpstr, envval);
|
||||
|
@ -115,7 +115,7 @@ file_error osd_open(const char *path, UINT32 openflags, osd_file **file, UINT64
|
||||
tmpstr = NULL;
|
||||
|
||||
// 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)
|
||||
{
|
||||
filerr = FILERR_OUT_OF_MEMORY;
|
||||
@ -160,14 +160,14 @@ file_error osd_open(const char *path, UINT32 openflags, osd_file **file, UINT64
|
||||
goto error;
|
||||
}
|
||||
|
||||
tmpstr = (char *) osd_malloc(strlen((*file)->filename)+1);
|
||||
tmpstr = (char *) osd_malloc_array(strlen((*file)->filename)+1);
|
||||
strcpy(tmpstr, (*file)->filename);
|
||||
|
||||
// does path start with an environment variable?
|
||||
if (tmpstr[0] == '$')
|
||||
{
|
||||
char *envval;
|
||||
envstr = (char *) osd_malloc(strlen(tmpstr)+1);
|
||||
envstr = (char *) osd_malloc_array(strlen(tmpstr)+1);
|
||||
|
||||
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;
|
||||
osd_free(tmpstr);
|
||||
tmpstr = (char *) osd_malloc(j);
|
||||
tmpstr = (char *) osd_malloc_array(j);
|
||||
|
||||
// start with the value of $HOME
|
||||
strcpy(tmpstr, envval);
|
||||
|
@ -348,7 +348,8 @@ int main(int argc, char *argv[])
|
||||
{
|
||||
sdl_osd_interface osd;
|
||||
sdl_options options;
|
||||
res = cli_execute(options, osd, argc, argv);
|
||||
cli_frontend frontend(options, osd);
|
||||
res = frontend.execute(argc, argv);
|
||||
}
|
||||
|
||||
#ifdef MALLOC_DEBUG
|
||||
|
@ -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
|
||||
//============================================================
|
||||
@ -277,7 +291,7 @@ char *osd_get_clipboard_text(void)
|
||||
length = CFDataGetLength (data_ref);
|
||||
range = CFRangeMake (0,length);
|
||||
|
||||
result = (char *)osd_malloc (length+1);
|
||||
result = (char *)osd_malloc_array (length+1);
|
||||
if (result != NULL)
|
||||
{
|
||||
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
|
||||
// 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);
|
||||
result->name = ((char *) result) + sizeof(*result);
|
||||
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
|
||||
{
|
||||
*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 (path[0] == '/')
|
||||
|
@ -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
|
||||
//============================================================
|
||||
@ -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
|
||||
// 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);
|
||||
strcpy(((char *) result) + sizeof(*result), path);
|
||||
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)
|
||||
{
|
||||
*dst = (char *)osd_malloc(CCHMAXPATH + 1);
|
||||
*dst = (char *)osd_malloc_array(CCHMAXPATH + 1);
|
||||
if (*dst == NULL)
|
||||
return FILERR_OUT_OF_MEMORY;
|
||||
|
||||
|
@ -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
|
||||
//============================================================
|
||||
@ -207,7 +221,7 @@ char *osd_get_clipboard_text(void)
|
||||
/* return a copy & free original */
|
||||
if (prop != NULL)
|
||||
{
|
||||
result = (char *) osd_malloc(strlen((char *)prop)+1);
|
||||
result = (char *) osd_malloc_array(strlen((char *)prop)+1);
|
||||
strcpy(result, (char *)prop);
|
||||
}
|
||||
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
|
||||
// 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);
|
||||
result->name = ((char *) result) + sizeof(*result);
|
||||
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
|
||||
{
|
||||
*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 (path[0] == '/')
|
||||
|
@ -180,41 +180,54 @@ void *osd_malloc(size_t size)
|
||||
#ifndef MALLOC_DEBUG
|
||||
return HeapAlloc(GetProcessHeap(), 0, size);
|
||||
#else
|
||||
// add in space for the base pointer
|
||||
// add in space for the size
|
||||
size += sizeof(size_t);
|
||||
|
||||
// small items just come from the heap
|
||||
void *result;
|
||||
if (size < GUARD_PAGE_THRESH)
|
||||
result = HeapAlloc(GetProcessHeap(), 0, size);
|
||||
// basic objects just come from the heap
|
||||
void *result = HeapAlloc(GetProcessHeap(), 0, size);
|
||||
|
||||
// large items get guard pages
|
||||
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
|
||||
// store the size and return and pointer to the data afterward
|
||||
*reinterpret_cast<size_t *>(result) = size;
|
||||
return reinterpret_cast<UINT8 *>(result) + sizeof(size_t);
|
||||
#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
|
||||
//============================================================
|
||||
@ -226,14 +239,14 @@ void osd_free(void *ptr)
|
||||
#else
|
||||
size_t size = reinterpret_cast<size_t *>(ptr)[-1];
|
||||
|
||||
// small items just get freed
|
||||
if (size < GUARD_PAGE_THRESH)
|
||||
// if no guard page, just free the pointer
|
||||
if ((size & 0x80000000) == 0)
|
||||
HeapFree(GetProcessHeap(), 0, reinterpret_cast<UINT8 *>(ptr) - sizeof(size_t));
|
||||
|
||||
// large items need more care
|
||||
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);
|
||||
}
|
||||
#endif
|
||||
@ -262,7 +275,7 @@ int osd_setenv(const char *name, const char *value, int overwrite)
|
||||
if (osd_getenv(name) != NULL)
|
||||
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);
|
||||
result = putenv(buf);
|
||||
|
||||
@ -371,7 +384,7 @@ CHAR *astring_from_utf8(const char *utf8string)
|
||||
|
||||
// convert UTF-16 to "ANSI code page" string
|
||||
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)
|
||||
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
|
||||
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)
|
||||
MultiByteToWideChar(CP_UTF8, 0, utf8string, -1, result, char_count);
|
||||
|
||||
|
@ -183,7 +183,7 @@ osd_work_queue *osd_work_queue_alloc(int flags)
|
||||
queue->threads = MIN(queue->threads, WORK_MAX_THREADS);
|
||||
|
||||
// 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)
|
||||
goto error;
|
||||
memset(queue->thread, 0, (queue->threads + 1) * sizeof(queue->thread[0]));
|
||||
|
@ -38,7 +38,7 @@ char *utf8_from_astring(const CHAR *astring)
|
||||
|
||||
// convert UTF-16 to MAME string (UTF-8)
|
||||
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)
|
||||
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)
|
||||
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)
|
||||
WideCharToMultiByte(CP_UTF8, 0, wstring, -1, result, char_count, NULL, NULL);
|
||||
|
||||
|
@ -65,7 +65,7 @@ CHAR *astring_from_utf8(const char *utf8string)
|
||||
|
||||
// convert UTF-16 to "ANSI code page" string
|
||||
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)
|
||||
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)
|
||||
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)
|
||||
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
|
||||
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)
|
||||
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)
|
||||
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)
|
||||
WideCharToMultiByte(CP_UTF8, 0, wstring, -1, result, char_count, NULL, NULL);
|
||||
|
||||
|
@ -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
|
||||
}
|
@ -418,7 +418,8 @@ int main(int argc, char *argv[])
|
||||
{
|
||||
windows_options options;
|
||||
windows_osd_interface osd;
|
||||
result = cli_execute(options, osd, argc, argv);
|
||||
cli_frontend frontend(options, osd);
|
||||
frontend.execute(argc, argv);
|
||||
}
|
||||
|
||||
// free symbols
|
||||
|
@ -45,7 +45,7 @@
|
||||
#include <tchar.h>
|
||||
|
||||
// MAME headers
|
||||
#include "emucore.h"
|
||||
#include "osdcore.h"
|
||||
|
||||
// MAMEOS headers
|
||||
#include "winutf8.h"
|
||||
@ -60,9 +60,6 @@
|
||||
// presumed size of a page of memory
|
||||
#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?
|
||||
#define GUARD_ALIGN_START 0
|
||||
|
||||
@ -85,41 +82,54 @@ void *osd_malloc(size_t size)
|
||||
#ifndef MALLOC_DEBUG
|
||||
return HeapAlloc(GetProcessHeap(), 0, size);
|
||||
#else
|
||||
// add in space for the base pointer
|
||||
// add in space for the size
|
||||
size += sizeof(size_t);
|
||||
|
||||
// small items just come from the heap
|
||||
void *result;
|
||||
if (size < GUARD_PAGE_THRESH)
|
||||
result = HeapAlloc(GetProcessHeap(), 0, size);
|
||||
// basic objects just come from the heap
|
||||
void *result = HeapAlloc(GetProcessHeap(), 0, size);
|
||||
|
||||
// large items get guard pages
|
||||
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
|
||||
// store the size and return and pointer to the data afterward
|
||||
*reinterpret_cast<size_t *>(result) = size;
|
||||
return reinterpret_cast<UINT8 *>(result) + sizeof(size_t);
|
||||
#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
|
||||
//============================================================
|
||||
@ -131,14 +141,14 @@ void osd_free(void *ptr)
|
||||
#else
|
||||
size_t size = reinterpret_cast<size_t *>(ptr)[-1];
|
||||
|
||||
// small items just get freed
|
||||
if (size < GUARD_PAGE_THRESH)
|
||||
// if no guard page, just free the pointer
|
||||
if ((size & 0x80000000) == 0)
|
||||
HeapFree(GetProcessHeap(), 0, reinterpret_cast<UINT8 *>(ptr) - sizeof(size_t));
|
||||
|
||||
// large items need more care
|
||||
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);
|
||||
}
|
||||
#endif
|
||||
|
Loading…
Reference in New Issue
Block a user