mame/src/emu/info.c
2008-07-28 16:22:20 +00:00

1002 lines
32 KiB
C

/***************************************************************************
info.c
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.
***************************************************************************/
#include <ctype.h>
#include "driver.h"
#include "sound/samples.h"
#include "info.h"
#include "xmlfile.h"
#include "hash.h"
#ifdef MESS
#include "infomess.h"
#endif /* MESS */
/* MESS/MAME configuration */
#ifdef MESS
#define XML_ROOT "mess"
#define XML_TOP "machine"
#else
#define XML_ROOT "mame"
#define XML_TOP "game"
#endif
/*-------------------------------------------------
print_game_switches - print the DIP switch
settings for a game
-------------------------------------------------*/
static void print_game_switches(FILE *out, const game_driver *game, const input_port_config *portlist)
{
const input_port_config *port;
const input_field_config *field;
/* iterate looking for DIP switches */
for (port = portlist; port != NULL; port = port->next)
for (field = port->fieldlist; field != NULL; field = field->next)
if (field->type == IPT_DIPSWITCH)
{
const input_setting_config *setting;
/* output the switch name information */
fprintf(out, "\t\t<dipswitch name=\"%s\">\n", xml_normalize_string(input_field_name(field)));
/* loop over settings */
for (setting = field->settinglist; setting != NULL; setting = setting->next)
{
fprintf(out, "\t\t\t<dipvalue name=\"%s\"", xml_normalize_string(setting->name));
if (setting->value == field->defvalue)
fprintf(out, " default=\"yes\"");
fprintf(out, "/>\n");
}
/* terminate the switch entry */
fprintf(out, "\t\t</dipswitch>\n");
}
}
/*-------------------------------------------------
print_game_input - print a summary of a game's
input
-------------------------------------------------*/
static void print_game_input(FILE *out, const game_driver *game, const input_port_config *portlist)
{
/* fix me -- this needs to be cleaned up to match the core style */
enum {cjoy, cdoublejoy, cAD_stick, cdial, ctrackball, cpaddle, clightgun, cpedal, ENDCONTROLTYPES};
int nplayer = 0;
int nbutton = 0;
int ncoin = 0;
int controlsyes = 0;
int analogcontrol = 0;
int i;
const char* service = 0;
const char* tilt = 0;
const char* control_types[] = {"joy", "doublejoy", "stick", "dial", "trackball", "paddle", "lightgun", "pedal"};
static struct _input_info
{
const char * type; /* general type of input */
const char * Xway; /* 2, 4, or 8 way */
int analog;
int min; /* analog minimum value */
int max; /* analog maximum value */
int sensitivity; /* default analog sensitivity */
int keydelta; /* default analog keydelta */
int reverse; /* default analog reverse setting */
} control[ENDCONTROLTYPES];
const input_port_config *port;
const input_field_config *field;
for (i=0;i<ENDCONTROLTYPES;i++)
{
control[i].type = control_types[i];
control[i].Xway = NULL;
control[i].analog = 0;
control[i].min = 0;
control[i].max = 0;
control[i].sensitivity = 0;
control[i].keydelta = 0;
control[i].reverse = 0;
}
for (port = portlist; port != NULL; port = port->next)
for (field = port->fieldlist; field != NULL; field = field->next)
{
if (nplayer < field->player+1)
nplayer = field->player+1;
switch (field->type)
{
case IPT_JOYSTICK_LEFT:
case IPT_JOYSTICK_RIGHT:
/* if control not defined, start it off as horizontal 2-way */
if (control[cjoy].Xway == NULL)
control[cjoy].Xway = "joy2way";
else if (strcmp(control[cjoy].Xway,"joy2way") == 0)
;
/* if already defined as vertical, make it 4 or 8 way */
else if (strcmp(control[cjoy].Xway,"vjoy2way") == 0)
{
if (field->way == 4)
control[cjoy].Xway = "joy4way";
else
control[cjoy].Xway = "joy8way";
}
controlsyes = 1;
break;
case IPT_JOYSTICK_UP:
case IPT_JOYSTICK_DOWN:
/* if control not defined, start it off as vertical 2-way */
if (control[cjoy].Xway == NULL)
control[cjoy].Xway = "vjoy2way";
else if (strcmp(control[cjoy].Xway,"vjoy2way") == 0)
;
/* if already defined as horiz, make it 4 or 8way */
else if (strcmp(control[cjoy].Xway,"joy2way") == 0)
{
if (field->way == 4)
control[cjoy].Xway = "joy4way";
else
control[cjoy].Xway = "joy8way";
}
controlsyes = 1;
break;
case IPT_JOYSTICKRIGHT_UP:
case IPT_JOYSTICKRIGHT_DOWN:
case IPT_JOYSTICKLEFT_UP:
case IPT_JOYSTICKLEFT_DOWN:
/* if control not defined, start it off as vertical 2way */
if (control[cdoublejoy].Xway == NULL)
control[cdoublejoy].Xway = "vdoublejoy2way";
else if (strcmp(control[cdoublejoy].Xway,"vdoublejoy2way") == 0)
;
/* if already defined as horiz, make it 4 or 8 way */
else if (strcmp(control[cdoublejoy].Xway,"doublejoy2way") == 0)
{
if (field->way == 4)
control[cdoublejoy].Xway = "doublejoy4way";
else
control[cdoublejoy].Xway = "doublejoy8way";
}
controlsyes = 1;
break;
case IPT_JOYSTICKRIGHT_LEFT:
case IPT_JOYSTICKRIGHT_RIGHT:
case IPT_JOYSTICKLEFT_LEFT:
case IPT_JOYSTICKLEFT_RIGHT:
/* if control not defined, start it off as horiz 2-way */
if (control[cdoublejoy].Xway == NULL)
control[cdoublejoy].Xway = "doublejoy2way";
else if (strcmp(control[cdoublejoy].Xway,"doublejoy2way") == 0)
;
/* if already defined as vertical, make it 4 or 8 way */
else if (strcmp(control[cdoublejoy].Xway,"vdoublejoy2way") == 0)
{
if (field->way == 4)
control[cdoublejoy].Xway = "doublejoy4way";
else
control[cdoublejoy].Xway = "doublejoy8way";
}
controlsyes = 1;
break;
/* mark as an analog input, and get analog stats after switch */
case IPT_PADDLE:
analogcontrol = cpaddle;
break;
case IPT_DIAL:
analogcontrol = cdial;
break;
case IPT_TRACKBALL_X:
case IPT_TRACKBALL_Y:
analogcontrol = ctrackball;
break;
case IPT_AD_STICK_X:
case IPT_AD_STICK_Y:
analogcontrol = cAD_stick;
break;
case IPT_LIGHTGUN_X:
case IPT_LIGHTGUN_Y:
analogcontrol = clightgun;
break;
case IPT_PEDAL:
case IPT_PEDAL2:
case IPT_PEDAL3:
analogcontrol = cpedal;
break;
case IPT_BUTTON1:
case IPT_BUTTON2:
case IPT_BUTTON3:
case IPT_BUTTON4:
case IPT_BUTTON5:
case IPT_BUTTON6:
case IPT_BUTTON7:
case IPT_BUTTON8:
case IPT_BUTTON9:
case IPT_BUTTON10:
case IPT_BUTTON11:
case IPT_BUTTON12:
case IPT_BUTTON13:
case IPT_BUTTON14:
case IPT_BUTTON15:
case IPT_BUTTON16:
nbutton = MAX(nbutton, field->type - IPT_BUTTON1 + 1);
break;
case IPT_COIN1:
case IPT_COIN2:
case IPT_COIN3:
case IPT_COIN4:
case IPT_COIN5:
case IPT_COIN6:
case IPT_COIN7:
case IPT_COIN8:
ncoin = MAX(ncoin, field->type - IPT_COIN1 + 1);
case IPT_SERVICE :
service = "yes";
break;
case IPT_TILT :
tilt = "yes";
break;
}
/* get the analog stats */
if (analogcontrol)
{
controlsyes = 1;
control[analogcontrol].analog = 1;
if (field->min)
control[analogcontrol].min = field->min;
if (field->max)
control[analogcontrol].max = field->max;
if (field->sensitivity)
control[analogcontrol].sensitivity = field->sensitivity;
if (field->delta)
control[analogcontrol].keydelta = field->delta;
if (field->flags & ANALOG_FLAG_REVERSE)
control[analogcontrol].reverse = 1;
analogcontrol = 0;
}
}
fprintf(out, "\t\t<input");
fprintf(out, " players=\"%d\"", nplayer);
if (nbutton != 0)
fprintf(out, " buttons=\"%d\"", nbutton);
if (ncoin != 0)
fprintf(out, " coins=\"%d\"", ncoin);
if (service != NULL)
fprintf(out, " service=\"%s\"", xml_normalize_string(service));
if (tilt != NULL)
fprintf(out, " tilt=\"%s\"", xml_normalize_string(tilt));
fprintf(out, ">\n");
for (i = 0; i < ENDCONTROLTYPES; i++)
{
if (control[i].Xway != NULL)
fprintf(out, "\t\t\t<control type=\"%s\"/>\n", xml_normalize_string(control[i].Xway));
if (control[i].analog)
{
fprintf(out, "\t\t\t<control type=\"%s\"", xml_normalize_string(control_types[i]));
if (control[i].min || control[i].max)
{
fprintf(out, " minimum=\"%d\"", control[i].min);
fprintf(out, " maximum=\"%d\"", control[i].max);
}
if (control[i].sensitivity)
fprintf(out, " sensitivity=\"%d\"", control[i].sensitivity);
if (control[i].keydelta)
fprintf(out, " keydelta=\"%d\"", control[i].keydelta);
if (control[i].reverse)
fprintf(out, " reverse=\"yes\"");
fprintf(out, "/>\n");
}
}
fprintf(out, "\t\t</input>\n");
}
/*-------------------------------------------------
print_game_bios - print the BIOS set for a
game
-------------------------------------------------*/
static void print_game_bios(FILE *out, const game_driver *game)
{
const rom_entry *rom;
/* skip if no ROMs */
if (game->rom == NULL)
return;
/* iterate over ROM entries and look for BIOSes */
for (rom = game->rom; !ROMENTRY_ISEND(rom); rom++)
if (ROMENTRY_ISSYSTEM_BIOS(rom))
{
const char *name = ROM_GETNAME(rom);
const char *description = ROM_GETHASHDATA(rom);
/* output extracted name and descriptions */
fprintf(out, "\t\t<biosset");
fprintf(out, " name=\"%s\"", xml_normalize_string(name));
fprintf(out, " description=\"%s\"", xml_normalize_string(description));
if (ROM_GETBIOSFLAGS(rom) == 1)
fprintf(out, " default=\"yes\"");
fprintf(out, "/>\n");
}
}
/*-------------------------------------------------
print_game_rom - print the roms section of
the XML output
-------------------------------------------------*/
static void print_game_rom(FILE *out, const game_driver *game)
{
const game_driver *clone_of = driver_get_clone(game);
int rom_type;
/* if no roms, just exit early */
if (game->rom == NULL)
return;
/* iterate over 3 different ROM "types": BIOS, ROMs, DISKs */
for (rom_type = 0; rom_type < 3; rom_type++)
{
const rom_entry *region;
/* iterate first through regions */
for (region = rom_first_region(game); region != NULL; region = rom_next_region(region))
{
int is_disk = ROMREGION_ISDISKDATA(region);
const rom_entry *rom;
/* disk regions only work for disks */
if ((is_disk && rom_type != 2) || (!is_disk && rom_type == 2))
continue;
/* iterate through ROM entries */
for (rom = rom_first_file(region); rom != NULL; rom = rom_next_file(rom))
{
int is_bios = ROM_GETBIOSFLAGS(rom);
const char *name = ROM_GETNAME(rom);
int offset = ROM_GETOFFSET(rom);
const rom_entry *parent_rom = NULL;
const rom_entry *chunk;
char bios_name[100];
int length;
/* BIOS ROMs only apply to bioses */
if ((is_bios && rom_type != 0) || (!is_bios && rom_type == 0))
continue;
/* compute the total length of all chunks */
length = 0;
for (chunk = rom_first_chunk(rom); chunk; chunk = rom_next_chunk(chunk))
length += ROM_GETLENGTH(chunk);
/* if we have a valid ROM and we are a clone, see if we can find the parent ROM */
if (!ROM_NOGOODDUMP(rom) && clone_of != NULL)
{
const rom_entry *pregion, *prom;
/* scan the clone_of ROM for a matching ROM entry */
for (pregion = rom_first_region(clone_of); pregion != NULL; pregion = rom_next_region(pregion))
for (prom = rom_first_file(pregion); prom != NULL; prom = rom_next_file(prom))
if (hash_data_is_equal(ROM_GETHASHDATA(rom), ROM_GETHASHDATA(prom), 0))
{
parent_rom = prom;
break;
}
}
/* scan for a BIOS name */
bios_name[0] = 0;
if (!is_disk && is_bios)
{
const rom_entry *brom;
/* scan backwards through the ROM entries */
for (brom = rom - 1; brom != game->rom; brom--)
if (ROMENTRY_ISSYSTEM_BIOS(brom))
{
strcpy(bios_name, ROM_GETNAME(brom));
break;
}
}
/* opening tag */
if (!is_disk)
fprintf(out, "\t\t<rom");
else
fprintf(out, "\t\t<disk");
/* add name, merge, bios, and size tags */
if (name != NULL && name[0] != 0)
fprintf(out, " name=\"%s\"", xml_normalize_string(name));
if (parent_rom != NULL)
fprintf(out, " merge=\"%s\"", xml_normalize_string(ROM_GETNAME(parent_rom)));
if (bios_name[0] != 0)
fprintf(out, " bios=\"%s\"", xml_normalize_string(bios_name));
if (!is_disk)
fprintf(out, " size=\"%d\"", length);
/* dump checksum information only if there is a known dump */
if (!hash_data_has_info(ROM_GETHASHDATA(rom), HASH_INFO_NO_DUMP))
{
char checksum[HASH_BUF_SIZE];
int hashtype;
/* iterate over hash function types and print out their values */
for (hashtype = 0; hashtype < HASH_NUM_FUNCTIONS; hashtype++)
if (hash_data_extract_printable_checksum(ROM_GETHASHDATA(rom), 1 << hashtype, checksum))
fprintf(out, " %s=\"%s\"", hash_function_name(1 << hashtype), checksum);
}
/* append a region name */
fprintf(out, " region=\"%s\"", ROMREGION_GETTAG(region));
/* add nodump/baddump flags */
if (hash_data_has_info(ROM_GETHASHDATA(rom), HASH_INFO_NO_DUMP))
fprintf(out, " status=\"nodump\"");
if (hash_data_has_info(ROM_GETHASHDATA(rom), HASH_INFO_BAD_DUMP))
fprintf(out, " status=\"baddump\"");
/* for non-disk entries, print dispose flag and offset */
if (!is_disk)
{
if (ROMREGION_GETFLAGS(region) & ROMREGION_DISPOSE)
fprintf(out, " dispose=\"yes\"");
fprintf(out, " offset=\"%x\"", offset);
}
/* for disk entries, add the disk index */
else
fprintf(out, " index=\"%x\"", DISK_GETINDEX(rom));
fprintf(out, "/>\n");
}
}
}
}
/*-------------------------------------------------
print_game_sampleof - print the 'sampleof'
attribute, if appropriate
-------------------------------------------------*/
static void print_game_sampleof(FILE *out, const game_driver *game, const machine_config *config)
{
#if (HAS_SAMPLES)
int sndnum;
for (sndnum = 0; sndnum < ARRAY_LENGTH(config->sound) && config->sound[sndnum].type != SOUND_DUMMY; sndnum++)
if (config->sound[sndnum].type == SOUND_SAMPLES)
{
const char *const *samplenames = ((const struct Samplesinterface *)config->sound[sndnum].config)->samplenames;
if (samplenames != NULL)
{
int sampnum;
/* iterate over sample names */
for (sampnum = 0; samplenames[sampnum] != NULL; sampnum++)
{
const char *cursampname = samplenames[sampnum];
/* only output sampleof if different from the game name */
if (cursampname[0] == '*' && strcmp(cursampname + 1, game->name) != 0)
fprintf(out, " sampleof=\"%s\"", xml_normalize_string(cursampname + 1));
}
}
}
#endif
}
/*-------------------------------------------------
print_game_sample - print a list of all
samples referenced by a game_driver
-------------------------------------------------*/
static void print_game_sample(FILE *out, const game_driver *game, const machine_config *config)
{
#if (HAS_SAMPLES)
int sndnum;
/* iterate over sound chips looking for samples */
for (sndnum = 0; sndnum < ARRAY_LENGTH(config->sound) && config->sound[sndnum].type != SOUND_DUMMY; sndnum++)
if (config->sound[sndnum].type == SOUND_SAMPLES)
{
const char *const *samplenames = ((const struct Samplesinterface *)config->sound[sndnum].config)->samplenames;
if (samplenames != NULL)
{
int sampnum;
/* iterate over sample names */
for (sampnum = 0; samplenames[sampnum] != NULL; sampnum++)
{
const char *cursampname = samplenames[sampnum];
int dupnum;
/* ignore the special '*' samplename */
if (sampnum == 0 && cursampname[0] == '*')
continue;
/* filter out duplicates */
for (dupnum = 0; dupnum < sampnum; dupnum++)
if (strcmp(samplenames[dupnum], cursampname) == 0)
break;
if (dupnum < sampnum)
continue;
/* output the sample name */
fprintf(out, "\t\t<sample name=\"%s\"/>\n", xml_normalize_string(cursampname));
}
}
}
#endif
}
/*-------------------------------------------------
print_game_chips - print a list of CPU and
sound chips used by a game
-------------------------------------------------*/
static void print_game_chips(FILE *out, const game_driver *game, const machine_config *config)
{
int chipnum;
/* iterate over CPUs */
for (chipnum = 0; chipnum < ARRAY_LENGTH(config->cpu); chipnum++)
if (config->cpu[chipnum].type != CPU_DUMMY)
{
fprintf(out, "\t\t<chip");
fprintf(out, " type=\"cpu\"");
fprintf(out, " tag=\"%s\"", xml_normalize_string(config->cpu[chipnum].tag));
fprintf(out, " name=\"%s\"", xml_normalize_string(cputype_name(config->cpu[chipnum].type)));
fprintf(out, " clock=\"%d\"", config->cpu[chipnum].clock);
fprintf(out, "/>\n");
}
/* iterate over sound chips */
for (chipnum = 0; chipnum < ARRAY_LENGTH(config->sound); chipnum++)
if (config->sound[chipnum].type != SOUND_DUMMY)
{
fprintf(out, "\t\t<chip");
fprintf(out, " type=\"audio\"");
fprintf(out, " tag=\"%s\"", xml_normalize_string(config->sound[chipnum].tag));
fprintf(out, " name=\"%s\"", xml_normalize_string(sndtype_name(config->sound[chipnum].type)));
if (config->sound[chipnum].clock != 0)
fprintf(out, " clock=\"%d\"", config->sound[chipnum].clock);
fprintf(out, "/>\n");
}
}
/*-------------------------------------------------
print_game_display - print a list of all the
displays
-------------------------------------------------*/
static void print_game_display(FILE *out, const game_driver *game, const machine_config *config)
{
const device_config *screen;
/* iterate over screens */
for (screen = video_screen_first(config); screen != NULL; screen = video_screen_next(screen))
{
const screen_config *scrconfig = screen->inline_config;
fprintf(out, "\t\t<display");
switch (scrconfig->type)
{
case SCREEN_TYPE_RASTER: fprintf(out, " type=\"raster\""); break;
case SCREEN_TYPE_VECTOR: fprintf(out, " type=\"vector\""); break;
case SCREEN_TYPE_LCD: fprintf(out, " type=\"lcd\""); break;
default: fprintf(out, " type=\"unknown\""); break;
}
/* output the orientation as a string */
switch (game->flags & ORIENTATION_MASK)
{
case ORIENTATION_FLIP_X:
fprintf(out, " rotate=\"0\" flipx=\"yes\"");
break;
case ORIENTATION_FLIP_Y:
fprintf(out, " rotate=\"180\" flipx=\"yes\"");
break;
case ORIENTATION_FLIP_X|ORIENTATION_FLIP_Y:
fprintf(out, " rotate=\"180\"");
break;
case ORIENTATION_SWAP_XY:
fprintf(out, " rotate=\"90\" flipx=\"yes\"");
break;
case ORIENTATION_SWAP_XY|ORIENTATION_FLIP_X:
fprintf(out, " rotate=\"90\"");
break;
case ORIENTATION_SWAP_XY|ORIENTATION_FLIP_Y:
fprintf(out, " rotate=\"270\"");
break;
case ORIENTATION_SWAP_XY|ORIENTATION_FLIP_X|ORIENTATION_FLIP_Y:
fprintf(out, " rotate=\"270\" flipx=\"yes\"");
break;
default:
fprintf(out, " rotate=\"0\"");
break;
}
/* output width and height only for games that are not vector */
if (scrconfig->type != SCREEN_TYPE_VECTOR)
{
int dx = scrconfig->visarea.max_x - scrconfig->visarea.min_x + 1;
int dy = scrconfig->visarea.max_y - scrconfig->visarea.min_y + 1;
fprintf(out, " width=\"%d\"", dx);
fprintf(out, " height=\"%d\"", dy);
}
/* output refresh rate */
fprintf(out, " refresh=\"%f\"", ATTOSECONDS_TO_HZ(scrconfig->refresh));
/* output raw video parameters only for games that are not vector */
/* and had raw parameters specified */
if ((scrconfig->type != SCREEN_TYPE_VECTOR) && !scrconfig->oldstyle_vblank_supplied)
{
int pixclock = scrconfig->width * scrconfig->height * ATTOSECONDS_TO_HZ(scrconfig->refresh);
fprintf(out, " pixclock=\"%d\"", pixclock);
fprintf(out, " htotal=\"%d\"", scrconfig->width);
fprintf(out, " hbend=\"%d\"", scrconfig->visarea.min_x);
fprintf(out, " hbstart=\"%d\"", scrconfig->visarea.max_x+1);
fprintf(out, " vtotal=\"%d\"", scrconfig->height);
fprintf(out, " vbend=\"%d\"", scrconfig->visarea.min_y);
fprintf(out, " vbstart=\"%d\"", scrconfig->visarea.max_y+1);
}
fprintf(out, " />\n");
}
}
/*-------------------------------------------------
print_game_sound - print a list of all the
displays
-------------------------------------------------*/
static void print_game_sound(FILE *out, const game_driver *game, const machine_config *config)
{
int speakers = speaker_output_count(config);
int has_sound = FALSE;
int sndnum;
/* see if we have any sound chips to report */
for (sndnum = 0; sndnum < ARRAY_LENGTH(config->sound); sndnum++)
if (config->sound[sndnum].type != SOUND_DUMMY)
{
has_sound = TRUE;
break;
}
/* if we have sound, count the number of speakers */
if (!has_sound)
speakers = 0;
fprintf(out, "\t\t<sound channels=\"%d\"/>\n", speakers);
}
/*-------------------------------------------------
print_game_driver - print driver status
-------------------------------------------------*/
static void print_game_driver(FILE *out, const game_driver *game, const machine_config *config)
{
fprintf(out, "\t\t<driver");
/* The status entry is an hint for frontend authors */
/* to select working and not working games without */
/* the need to know all the other status entries. */
/* Games marked as status=good are perfectly emulated, games */
/* marked as status=imperfect are emulated with only */
/* some minor issues, games marked as status=preliminary */
/* don't work or have major emulation problems. */
if (game->flags & (GAME_NOT_WORKING | GAME_UNEMULATED_PROTECTION | GAME_NO_SOUND | GAME_WRONG_COLORS))
fprintf(out, " status=\"preliminary\"");
else if (game->flags & (GAME_IMPERFECT_COLORS | GAME_IMPERFECT_SOUND | GAME_IMPERFECT_GRAPHICS))
fprintf(out, " status=\"imperfect\"");
else
fprintf(out, " status=\"good\"");
if (game->flags & GAME_NOT_WORKING)
fprintf(out, " emulation=\"preliminary\"");
else
fprintf(out, " emulation=\"good\"");
if (game->flags & GAME_WRONG_COLORS)
fprintf(out, " color=\"preliminary\"");
else if (game->flags & GAME_IMPERFECT_COLORS)
fprintf(out, " color=\"imperfect\"");
else
fprintf(out, " color=\"good\"");
if (game->flags & GAME_NO_SOUND)
fprintf(out, " sound=\"preliminary\"");
else if (game->flags & GAME_IMPERFECT_SOUND)
fprintf(out, " sound=\"imperfect\"");
else
fprintf(out, " sound=\"good\"");
if (game->flags & GAME_IMPERFECT_GRAPHICS)
fprintf(out, " graphic=\"imperfect\"");
else
fprintf(out, " graphic=\"good\"");
if (game->flags & GAME_NO_COCKTAIL)
fprintf(out, " cocktail=\"preliminary\"");
if (game->flags & GAME_UNEMULATED_PROTECTION)
fprintf(out, " protection=\"preliminary\"");
if (game->flags & GAME_SUPPORTS_SAVE)
fprintf(out, " savestate=\"supported\"");
else
fprintf(out, " savestate=\"unsupported\"");
fprintf(out, " palettesize=\"%d\"", config->total_colors);
fprintf(out, "/>\n");
}
/*-------------------------------------------------
print_game_info - print the XML information
for one particular game driver
-------------------------------------------------*/
static void print_game_info(FILE *out, const game_driver *game)
{
const input_port_config *portconfig;
const game_driver *clone_of;
machine_config *config;
const char *start;
/* no action if not a game */
if (game->flags & GAME_NO_STANDALONE)
return;
/* start tracking resources and allocate the machine and input configs */
config = machine_config_alloc(game->machine_config);
#ifdef MESS
/* temporary hook until MESS device transition is complete */
mess_devices_setup(config, game);
#endif /* MESS */
portconfig = input_port_config_alloc(game->ipt, NULL, 0);
/* print the header and the game name */
fprintf(out, "\t<" XML_TOP);
fprintf(out, " name=\"%s\"", xml_normalize_string(game->name) );
/* strip away any path information from the source_file and output it */
start = strrchr(game->source_file, '/');
if (start == NULL)
start = strrchr(game->source_file, '\\');
if (start == NULL)
start = game->source_file - 1;
fprintf(out, " sourcefile=\"%s\"", xml_normalize_string(start + 1));
/* append bios and runnable flags */
if (game->flags & GAME_IS_BIOS_ROOT)
fprintf(out, " isbios=\"yes\"");
if (game->flags & GAME_NO_STANDALONE)
fprintf(out, " runnable=\"no\"");
/* display clone information */
clone_of = driver_get_clone(game);
if (clone_of != NULL && !(clone_of->flags & GAME_IS_BIOS_ROOT))
fprintf(out, " cloneof=\"%s\"", xml_normalize_string(clone_of->name));
if (clone_of != NULL)
fprintf(out, " romof=\"%s\"", xml_normalize_string(clone_of->name));
/* display sample information and close the game tag */
print_game_sampleof(out, game, config);
fprintf(out, ">\n");
/* output game description */
if (game->description != NULL)
fprintf(out, "\t\t<description>%s</description>\n", xml_normalize_string(game->description));
/* print the year only if is a number */
if (game->year != NULL && strspn(game->year, "0123456789") == strlen(game->year))
fprintf(out, "\t\t<year>%s</year>\n", xml_normalize_string(game->year));
/* print the manufacturer information */
if (game->manufacturer != NULL)
fprintf(out, "\t\t<manufacturer>%s</manufacturer>\n", xml_normalize_string(game->manufacturer));
/* now print various additional information */
print_game_bios(out, game);
print_game_rom(out, game);
print_game_sample(out, game, config);
print_game_chips(out, game, config);
print_game_display(out, game, config);
print_game_sound(out, game, config);
print_game_input(out, game, portconfig);
print_game_switches(out, game, portconfig);
print_game_driver(out, game, config);
#ifdef MESS
print_game_device(out, game, config);
print_game_ramoptions(out, game, config);
#endif /* MESS */
/* close the topmost tag */
fprintf(out, "\t</" XML_TOP ">\n");
input_port_config_free(portconfig);
machine_config_free(config);
}
/*-------------------------------------------------
print_mame_xml - print the XML information
for all known games
-------------------------------------------------*/
void print_mame_xml(FILE *out, const game_driver *const games[], const char *gamename)
{
int drvnum;
fprintf(out,
"<?xml version=\"1.0\"?>\n"
"<!DOCTYPE " XML_ROOT " [\n"
"<!ELEMENT " XML_ROOT " (" XML_TOP "+)>\n"
"\t<!ATTLIST " XML_ROOT " build CDATA #IMPLIED>\n"
"\t<!ATTLIST " XML_ROOT " debug (yes|no) \"no\">\n"
#ifdef MESS
"\t<!ELEMENT " XML_TOP " (description, year?, manufacturer, biosset*, rom*, disk*, sample*, chip*, display*, sound?, input?, dipswitch*, driver?, device*, ramoption*)>\n"
#else
"\t<!ELEMENT " XML_TOP " (description, year?, manufacturer, biosset*, rom*, disk*, sample*, chip*, display*, sound?, input?, dipswitch*, driver?)>\n"
#endif
"\t\t<!ATTLIST " XML_TOP " name CDATA #REQUIRED>\n"
"\t\t<!ATTLIST " XML_TOP " sourcefile CDATA #IMPLIED>\n"
"\t\t<!ATTLIST " XML_TOP " isbios (yes|no) \"no\">\n"
"\t\t<!ATTLIST " XML_TOP " runnable (yes|no) \"yes\">\n"
"\t\t<!ATTLIST " XML_TOP " cloneof CDATA #IMPLIED>\n"
"\t\t<!ATTLIST " XML_TOP " romof CDATA #IMPLIED>\n"
"\t\t<!ATTLIST " XML_TOP " sampleof CDATA #IMPLIED>\n"
"\t\t<!ELEMENT description (#PCDATA)>\n"
"\t\t<!ELEMENT year (#PCDATA)>\n"
"\t\t<!ELEMENT manufacturer (#PCDATA)>\n"
"\t\t<!ELEMENT biosset EMPTY>\n"
"\t\t\t<!ATTLIST biosset name CDATA #REQUIRED>\n"
"\t\t\t<!ATTLIST biosset description CDATA #REQUIRED>\n"
"\t\t\t<!ATTLIST biosset default (yes|no) \"no\">\n"
"\t\t<!ELEMENT rom EMPTY>\n"
"\t\t\t<!ATTLIST rom name CDATA #REQUIRED>\n"
"\t\t\t<!ATTLIST rom bios CDATA #IMPLIED>\n"
"\t\t\t<!ATTLIST rom size CDATA #REQUIRED>\n"
"\t\t\t<!ATTLIST rom crc CDATA #IMPLIED>\n"
"\t\t\t<!ATTLIST rom md5 CDATA #IMPLIED>\n"
"\t\t\t<!ATTLIST rom sha1 CDATA #IMPLIED>\n"
"\t\t\t<!ATTLIST rom merge CDATA #IMPLIED>\n"
"\t\t\t<!ATTLIST rom region CDATA #IMPLIED>\n"
"\t\t\t<!ATTLIST rom offset CDATA #IMPLIED>\n"
"\t\t\t<!ATTLIST rom status (baddump|nodump|good) \"good\">\n"
"\t\t\t<!ATTLIST rom dispose (yes|no) \"no\">\n"
"\t\t<!ELEMENT disk EMPTY>\n"
"\t\t\t<!ATTLIST disk name CDATA #REQUIRED>\n"
"\t\t\t<!ATTLIST disk md5 CDATA #IMPLIED>\n"
"\t\t\t<!ATTLIST disk sha1 CDATA #IMPLIED>\n"
"\t\t\t<!ATTLIST disk merge CDATA #IMPLIED>\n"
"\t\t\t<!ATTLIST disk region CDATA #IMPLIED>\n"
"\t\t\t<!ATTLIST disk index CDATA #IMPLIED>\n"
"\t\t\t<!ATTLIST disk status (baddump|nodump|good) \"good\">\n"
"\t\t<!ELEMENT sample EMPTY>\n"
"\t\t\t<!ATTLIST sample name CDATA #REQUIRED>\n"
"\t\t<!ELEMENT chip EMPTY>\n"
"\t\t\t<!ATTLIST chip name CDATA #REQUIRED>\n"
"\t\t\t<!ATTLIST chip tag CDATA #IMPLIED>\n"
"\t\t\t<!ATTLIST chip type (cpu|audio) #REQUIRED>\n"
"\t\t\t<!ATTLIST chip clock CDATA #IMPLIED>\n"
"\t\t<!ELEMENT display EMPTY>\n"
"\t\t\t<!ATTLIST display type (raster|vector|lcd|unknown) #REQUIRED>\n"
"\t\t\t<!ATTLIST display rotate (0|90|180|270) #REQUIRED>\n"
"\t\t\t<!ATTLIST display flipx (yes|no) \"no\">\n"
"\t\t\t<!ATTLIST display width CDATA #IMPLIED>\n"
"\t\t\t<!ATTLIST display height CDATA #IMPLIED>\n"
"\t\t\t<!ATTLIST display refresh CDATA #REQUIRED>\n"
"\t\t\t<!ATTLIST display pixclock CDATA #IMPLIED>\n"
"\t\t\t<!ATTLIST display htotal CDATA #IMPLIED>\n"
"\t\t\t<!ATTLIST display hbend CDATA #IMPLIED>\n"
"\t\t\t<!ATTLIST display hbstart CDATA #IMPLIED>\n"
"\t\t\t<!ATTLIST display vtotal CDATA #IMPLIED>\n"
"\t\t\t<!ATTLIST display vbend CDATA #IMPLIED>\n"
"\t\t\t<!ATTLIST display vbstart CDATA #IMPLIED>\n"
"\t\t<!ELEMENT sound EMPTY>\n"
"\t\t\t<!ATTLIST sound channels CDATA #REQUIRED>\n"
"\t\t<!ELEMENT input (control*)>\n"
"\t\t\t<!ATTLIST input service (yes|no) \"no\">\n"
"\t\t\t<!ATTLIST input tilt (yes|no) \"no\">\n"
"\t\t\t<!ATTLIST input players CDATA #REQUIRED>\n"
"\t\t\t<!ATTLIST input buttons CDATA #IMPLIED>\n"
"\t\t\t<!ATTLIST input coins CDATA #IMPLIED>\n"
"\t\t\t<!ELEMENT control EMPTY>\n"
"\t\t\t\t<!ATTLIST control type CDATA #REQUIRED>\n"
"\t\t\t\t<!ATTLIST control minimum CDATA #IMPLIED>\n"
"\t\t\t\t<!ATTLIST control maximum CDATA #IMPLIED>\n"
"\t\t\t\t<!ATTLIST control sensitivity CDATA #IMPLIED>\n"
"\t\t\t\t<!ATTLIST control keydelta CDATA #IMPLIED>\n"
"\t\t\t\t<!ATTLIST control reverse (yes|no) \"no\">\n"
"\t\t<!ELEMENT dipswitch (dipvalue*)>\n"
"\t\t\t<!ATTLIST dipswitch name CDATA #REQUIRED>\n"
"\t\t\t<!ELEMENT dipvalue EMPTY>\n"
"\t\t\t\t<!ATTLIST dipvalue name CDATA #REQUIRED>\n"
"\t\t\t\t<!ATTLIST dipvalue default (yes|no) \"no\">\n"
"\t\t<!ELEMENT driver EMPTY>\n"
"\t\t\t<!ATTLIST driver status (good|imperfect|preliminary) #REQUIRED>\n"
"\t\t\t<!ATTLIST driver emulation (good|imperfect|preliminary) #REQUIRED>\n"
"\t\t\t<!ATTLIST driver color (good|imperfect|preliminary) #REQUIRED>\n"
"\t\t\t<!ATTLIST driver sound (good|imperfect|preliminary) #REQUIRED>\n"
"\t\t\t<!ATTLIST driver graphic (good|imperfect|preliminary) #REQUIRED>\n"
"\t\t\t<!ATTLIST driver cocktail (good|imperfect|preliminary) #IMPLIED>\n"
"\t\t\t<!ATTLIST driver protection (good|imperfect|preliminary) #IMPLIED>\n"
"\t\t\t<!ATTLIST driver savestate (supported|unsupported) #REQUIRED>\n"
"\t\t\t<!ATTLIST driver palettesize CDATA #REQUIRED>\n"
#ifdef MESS
"\t\t<!ELEMENT device (instance*, extension*)>\n"
"\t\t\t<!ATTLIST device type CDATA #REQUIRED>\n"
"\t\t\t<!ATTLIST device tag CDATA #IMPLIED>\n"
"\t\t\t<!ATTLIST device mandatory CDATA #IMPLIED>\n"
"\t\t\t<!ELEMENT instance EMPTY>\n"
"\t\t\t\t<!ATTLIST instance name CDATA #REQUIRED>\n"
"\t\t\t\t<!ATTLIST instance briefname CDATA #REQUIRED>\n"
"\t\t\t<!ELEMENT extension EMPTY>\n"
"\t\t\t\t<!ATTLIST extension name CDATA #REQUIRED>\n"
"\t\t<!ELEMENT ramoption (#PCDATA)>\n"
"\t\t\t<!ATTLIST ramoption default CDATA #IMPLIED>\n"
#endif
"]>\n\n"
"<" XML_ROOT " build=\"%s\" debug=\""
#ifdef MAME_DEBUG
"yes"
#else
"no"
#endif
"\">\n",
xml_normalize_string(build_version)
);
for (drvnum = 0; games[drvnum] != NULL; drvnum++)
if (mame_strwildcmp(gamename, games[drvnum]->name) == 0)
print_game_info(out, games[drvnum]);
fprintf(out, "</" XML_ROOT ">\n");
}