summaryrefslogtreecommitdiffstatshomepage
path: root/src/emu/info.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/emu/info.c')
-rw-r--r--src/emu/info.c1009
1 files changed, 1009 insertions, 0 deletions
diff --git a/src/emu/info.c b/src/emu/info.c
new file mode 100644
index 00000000000..a8ce2549af7
--- /dev/null
+++ b/src/emu/info.c
@@ -0,0 +1,1009 @@
+/***************************************************************************
+
+ info.c
+
+ Dumps the MAME internal data as an XML file.
+
+ Copyright (c) 1996-2007, 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"
+
+/* MESS/MAME configuration */
+#ifdef MESS
+#define XML_ROOT "mess"
+#define XML_TOP "machine"
+#else
+#define XML_ROOT "mame"
+#define XML_TOP "game"
+#endif
+
+#ifdef MESS
+void print_game_device(FILE* out, const game_driver* game);
+void print_game_ramoptions(FILE* out, const game_driver* game);
+#endif /* MESS */
+
+/* Print a free format string */
+
+static void print_game_switch(FILE* out, const game_driver* game)
+{
+ const input_port_entry* input;
+
+ begin_resource_tracking();
+
+ input = input_port_allocate(game->ipt, NULL);
+
+ while (input->type != IPT_END)
+ {
+ if (input->type==IPT_DIPSWITCH_NAME)
+ {
+ int def = input->default_value;
+
+ fprintf(out, "\t\t<dipswitch");
+
+ fprintf(out, " name=\"%s\"", xml_normalize_string(input->name));
+ ++input;
+
+ fprintf(out, ">\n");
+
+ while (input->type==IPT_DIPSWITCH_SETTING)
+ {
+ fprintf(out, "\t\t\t<dipvalue");
+ fprintf(out, " name=\"%s\"", xml_normalize_string(input->name));
+ if (def == input->default_value)
+ fprintf(out, " default=\"yes\"");
+
+ fprintf(out, "/>\n");
+
+ ++input;
+ }
+
+ fprintf(out, "\t\t</dipswitch>\n");
+ }
+ else
+ ++input;
+ }
+
+ end_resource_tracking();
+}
+
+static void print_game_input(FILE* out, const game_driver* game)
+{
+enum {cjoy, cdoublejoy, cAD_stick, cdial, ctrackball, cpaddle, clightgun, cpedal, ENDCONTROLTYPES};
+ const input_port_entry* input;
+ 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];
+
+ for (i=0;i<ENDCONTROLTYPES;i++)
+ {
+ control[i].type = control_types[i];
+ control[i].Xway = 0;
+ control[i].analog = 0;
+ control[i].min = 0;
+ control[i].max = 0;
+ control[i].sensitivity = 0;
+ control[i].keydelta = 0;
+ control[i].reverse = 0;
+ }
+
+ begin_resource_tracking();
+
+ input = input_port_allocate(game->ipt, NULL);
+
+ while (input->type != IPT_END)
+ {
+ if (nplayer < input->player+1)
+ nplayer = input->player+1;
+
+ switch (input->type)
+ {
+ case IPT_JOYSTICK_LEFT:
+ case IPT_JOYSTICK_RIGHT:
+
+ /* if control not defined, start it off as horizontal 2-way */
+ if (!control[cjoy].Xway)
+ 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 (input->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)
+ 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 (input->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)
+ 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 (input->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)
+ 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 (input->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:
+ if (nbutton<1) nbutton = 1;
+ break;
+ case IPT_BUTTON2:
+ if (nbutton<2) nbutton = 2;
+ break;
+ case IPT_BUTTON3:
+ if (nbutton<3) nbutton = 3;
+ break;
+ case IPT_BUTTON4:
+ if (nbutton<4) nbutton = 4;
+ break;
+ case IPT_BUTTON5:
+ if (nbutton<5) nbutton = 5;
+ break;
+ case IPT_BUTTON6:
+ if (nbutton<6) nbutton = 6;
+ break;
+ case IPT_BUTTON7:
+ if (nbutton<7) nbutton = 7;
+ break;
+ case IPT_BUTTON8:
+ if (nbutton<8) nbutton = 8;
+ break;
+ case IPT_BUTTON9:
+ if (nbutton<9) nbutton = 9;
+ break;
+ case IPT_BUTTON10:
+ if (nbutton<10) nbutton = 10;
+ break;
+
+ case IPT_COIN1:
+ if (ncoin < 1) ncoin = 1;
+ break;
+ case IPT_COIN2:
+ if (ncoin < 2) ncoin = 2;
+ break;
+ case IPT_COIN3:
+ if (ncoin < 3) ncoin = 3;
+ break;
+ case IPT_COIN4:
+ if (ncoin < 4) ncoin = 4;
+ break;
+ case IPT_COIN5:
+ if (ncoin < 5) ncoin = 5;
+ break;
+ case IPT_COIN6:
+ if (ncoin < 6) ncoin = 6;
+ break;
+ case IPT_COIN7:
+ if (ncoin < 7) ncoin = 7;
+ break;
+ case IPT_COIN8:
+ if (ncoin < 8) ncoin = 8;
+ break;
+ 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 (input->analog.min)
+ control[analogcontrol].min = input->analog.min;
+ if (input->analog.max)
+ control[analogcontrol].max = input->analog.max;
+ if (input->analog.sensitivity)
+ control[analogcontrol].sensitivity = input->analog.sensitivity;
+ if (input->analog.delta)
+ control[analogcontrol].keydelta = input->analog.delta;
+ if (input->analog.reverse)
+ control[analogcontrol].reverse = 1;
+
+ analogcontrol = 0;
+ }
+
+ ++input;
+ }
+
+ fprintf(out, "\t\t<input");
+ fprintf(out, " players=\"%d\"", nplayer );
+ if (nbutton)
+ fprintf(out, " buttons=\"%d\"", nbutton );
+ if (ncoin)
+ fprintf(out, " coins=\"%d\"", ncoin );
+ if (service)
+ fprintf(out, " service=\"%s\"", xml_normalize_string(service) );
+ if (tilt)
+ fprintf(out, " tilt=\"%s\"", xml_normalize_string(tilt) );
+ fprintf(out, ">\n");
+
+ for (i=0;i<ENDCONTROLTYPES;i++)
+ {
+ if (control[i].Xway)
+ 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");
+
+ end_resource_tracking();
+}
+
+static void print_game_bios(FILE* out, const game_driver* game)
+{
+ const rom_entry *rom;
+
+ if (game->rom != NULL)
+ {
+ for (rom = game->rom; !ROMENTRY_ISEND(rom); rom++)
+ if (ROMENTRY_ISSYSTEM_BIOS(rom))
+ {
+ const char *name = ROM_GETHASHDATA(rom);
+ const char *description = name + strlen(name) + 1;
+
+ 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");
+ }
+ }
+}
+
+static void print_game_rom(FILE* out, const game_driver* game)
+{
+ const rom_entry *region, *rom, *chunk;
+ const rom_entry *pregion, *prom, *fprom=NULL;
+ const game_driver *clone_of;
+ int rom_type;
+
+ if (!game->rom)
+ return;
+
+ clone_of = driver_get_clone(game);
+ for (rom_type = 0; rom_type < 3; rom_type++)
+ {
+ for (region = rom_first_region(game); region; region = rom_next_region(region))
+ for (rom = rom_first_file(region); rom; rom = rom_next_file(rom))
+ {
+ int offset, length, in_parent, is_disk, is_bios, found_bios, i;
+ char name[100], bios_name[100];
+
+ strcpy(name,ROM_GETNAME(rom));
+ offset = ROM_GETOFFSET(rom);
+ is_disk = ROMREGION_ISDISKDATA(region);
+ is_bios = ROM_GETBIOSFLAGS(rom);
+
+ switch (rom_type)
+ {
+ case 0: /* rom_type 0 = BIOS */
+ if (is_disk || !is_bios)
+ continue;
+ break;
+ case 1: /* rom_type 1 = ROM */
+ if (is_disk || is_bios)
+ continue;
+ break;
+ case 2: /* rom_type 1 = DISK */
+ if (!is_disk || is_bios)
+ continue;
+ break;
+ }
+
+ in_parent = 0;
+ length = 0;
+ for (chunk = rom_first_chunk(rom); chunk; chunk = rom_next_chunk(chunk))
+ length += ROM_GETLENGTH(chunk);
+
+ if (!ROM_NOGOODDUMP(rom) && clone_of)
+ {
+ fprom=NULL;
+ for (pregion = rom_first_region(clone_of); pregion; pregion = rom_next_region(pregion))
+ for (prom = rom_first_file(pregion); prom; prom = rom_next_file(prom))
+ if (hash_data_is_equal(ROM_GETHASHDATA(rom), ROM_GETHASHDATA(prom), 0))
+ {
+ if (!fprom || !strcmp(ROM_GETNAME(prom), name))
+ fprom=prom;
+ in_parent = 1;
+ }
+ }
+
+ found_bios = 0;
+ if(!is_disk && is_bios)
+ {
+ /* Scan backwards for name */
+ for (prom = rom-1; prom != game->rom; prom--)
+ if (ROMENTRY_ISSYSTEM_BIOS(prom))
+ {
+ strcpy(bios_name, ROM_GETHASHDATA(prom));
+ found_bios = 1;
+ break;
+ }
+ }
+
+
+ if (!is_disk)
+ fprintf(out, "\t\t<rom");
+ else
+ fprintf(out, "\t\t<disk");
+
+ if (*name)
+ fprintf(out, " name=\"%s\"", xml_normalize_string(name));
+ if (in_parent)
+ fprintf(out, " merge=\"%s\"", xml_normalize_string(ROM_GETNAME(fprom)));
+ if (!is_disk && found_bios)
+ 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))
+ {
+ for (i=0;i<HASH_NUM_FUNCTIONS;i++)
+ {
+ int func = 1<<i;
+ const char* func_name = hash_function_name(func);
+ char checksum[1000];
+
+ if (hash_data_extract_printable_checksum(ROM_GETHASHDATA(rom), func, checksum))
+ {
+ fprintf(out, " %s=\"%s\"", func_name, checksum);
+ }
+ }
+ }
+
+ switch (ROMREGION_GETTYPE(region))
+ {
+ case REGION_CPU1: fprintf(out, " region=\"cpu1\""); break;
+ case REGION_CPU2: fprintf(out, " region=\"cpu2\""); break;
+ case REGION_CPU3: fprintf(out, " region=\"cpu3\""); break;
+ case REGION_CPU4: fprintf(out, " region=\"cpu4\""); break;
+ case REGION_CPU5: fprintf(out, " region=\"cpu5\""); break;
+ case REGION_CPU6: fprintf(out, " region=\"cpu6\""); break;
+ case REGION_CPU7: fprintf(out, " region=\"cpu7\""); break;
+ case REGION_CPU8: fprintf(out, " region=\"cpu8\""); break;
+ case REGION_GFX1: fprintf(out, " region=\"gfx1\""); break;
+ case REGION_GFX2: fprintf(out, " region=\"gfx2\""); break;
+ case REGION_GFX3: fprintf(out, " region=\"gfx3\""); break;
+ case REGION_GFX4: fprintf(out, " region=\"gfx4\""); break;
+ case REGION_GFX5: fprintf(out, " region=\"gfx5\""); break;
+ case REGION_GFX6: fprintf(out, " region=\"gfx6\""); break;
+ case REGION_GFX7: fprintf(out, " region=\"gfx7\""); break;
+ case REGION_GFX8: fprintf(out, " region=\"gfx8\""); break;
+ case REGION_PROMS: fprintf(out, " region=\"proms\""); break;
+ case REGION_PLDS: fprintf(out, " region=\"plds\""); break;
+ case REGION_SOUND1: fprintf(out, " region=\"sound1\""); break;
+ case REGION_SOUND2: fprintf(out, " region=\"sound2\""); break;
+ case REGION_SOUND3: fprintf(out, " region=\"sound3\""); break;
+ case REGION_SOUND4: fprintf(out, " region=\"sound4\""); break;
+ case REGION_SOUND5: fprintf(out, " region=\"sound5\""); break;
+ case REGION_SOUND6: fprintf(out, " region=\"sound6\""); break;
+ case REGION_SOUND7: fprintf(out, " region=\"sound7\""); break;
+ case REGION_SOUND8: fprintf(out, " region=\"sound8\""); break;
+ case REGION_USER1: fprintf(out, " region=\"user1\""); break;
+ case REGION_USER2: fprintf(out, " region=\"user2\""); break;
+ case REGION_USER3: fprintf(out, " region=\"user3\""); break;
+ case REGION_USER4: fprintf(out, " region=\"user4\""); break;
+ case REGION_USER5: fprintf(out, " region=\"user5\""); break;
+ case REGION_USER6: fprintf(out, " region=\"user6\""); break;
+ case REGION_USER7: fprintf(out, " region=\"user7\""); break;
+ case REGION_USER8: fprintf(out, " region=\"user8\""); break;
+ case REGION_USER9: fprintf(out, " region=\"user9\""); break;
+ case REGION_USER10: fprintf(out, " region=\"user10\""); break;
+ case REGION_USER11: fprintf(out, " region=\"user11\""); break;
+ case REGION_USER12: fprintf(out, " region=\"user12\""); break;
+ case REGION_USER13: fprintf(out, " region=\"user13\""); break;
+ case REGION_USER14: fprintf(out, " region=\"user14\""); break;
+ case REGION_USER15: fprintf(out, " region=\"user15\""); break;
+ case REGION_USER16: fprintf(out, " region=\"user16\""); break;
+ case REGION_USER17: fprintf(out, " region=\"user17\""); break;
+ case REGION_USER18: fprintf(out, " region=\"user18\""); break;
+ case REGION_USER19: fprintf(out, " region=\"user19\""); break;
+ case REGION_USER20: fprintf(out, " region=\"user20\""); break;
+ case REGION_DISKS: fprintf(out, " region=\"disks\""); break;
+ default: fprintf(out, " region=\"0x%x\"", (int)ROMREGION_GETTYPE(region)); break;
+ }
+
+ 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\"");
+
+ if (!is_disk)
+ {
+ if (ROMREGION_GETFLAGS(region) & ROMREGION_DISPOSE)
+ fprintf(out, " dispose=\"yes\"");
+
+ fprintf(out, " offset=\"%x\"", offset);
+ }
+ else
+ {
+ fprintf(out, " index=\"%x\"", DISK_GETINDEX(rom));
+ }
+ fprintf(out, "/>\n");
+ }
+ }
+}
+
+static void print_game_sampleof(FILE* out, const game_driver* game)
+{
+#if (HAS_SAMPLES)
+ machine_config drv;
+ int i;
+
+ expand_machine_driver(game->drv, &drv);
+
+ for( i = 0; i < MAX_SOUND && drv.sound[i].type != SOUND_DUMMY; i++ )
+ {
+ const char **samplenames = NULL;
+ if( drv.sound[i].type == SOUND_SAMPLES )
+ samplenames = ((struct Samplesinterface *)drv.sound[i].config)->samplenames;
+ if (samplenames != 0 && samplenames[0] != 0) {
+ int k = 0;
+ if (samplenames[k][0]=='*')
+ {
+ /* output sampleof only if different from game name */
+ if (strcmp(samplenames[k] + 1, game->name)!=0)
+ fprintf(out, " sampleof=\"%s\"", xml_normalize_string(samplenames[k] + 1));
+ ++k;
+ }
+ }
+ }
+#endif
+}
+
+static void print_game_sample(FILE* out, const game_driver* game)
+{
+#if (HAS_SAMPLES)
+ machine_config drv;
+ int i;
+
+ expand_machine_driver(game->drv, &drv);
+
+ for( i = 0; i < MAX_SOUND && drv.sound[i].type != SOUND_DUMMY; i++ )
+ {
+ const char **samplenames = NULL;
+ if( drv.sound[i].type == SOUND_SAMPLES )
+ samplenames = ((struct Samplesinterface *)drv.sound[i].config)->samplenames;
+ if (samplenames != 0 && samplenames[0] != 0) {
+ int k = 0;
+ if (samplenames[k][0]=='*')
+ {
+ ++k;
+ }
+ while (samplenames[k] != 0) {
+ /* check if is not empty */
+ if (*samplenames[k]) {
+ /* check if sample is duplicate */
+ int l = 0;
+ while (l<k && strcmp(samplenames[k],samplenames[l])!=0)
+ ++l;
+ if (l==k)
+ fprintf(out, "\t\t<sample name=\"%s\"/>\n", xml_normalize_string(samplenames[k]));
+ }
+ ++k;
+ }
+ }
+ }
+#endif
+}
+
+static void print_game_micro(FILE* out, const game_driver* game)
+{
+ machine_config driver;
+ const cpu_config* cpu;
+ const sound_config* sound;
+ int j;
+
+ expand_machine_driver(game->drv, &driver);
+ cpu = driver.cpu;
+ sound = driver.sound;
+
+ for(j=0;j<MAX_CPU;++j)
+ {
+ if (cpu[j].type != CPU_DUMMY)
+ {
+ fprintf(out, "\t\t<chip");
+ fprintf(out, " type=\"cpu\"");
+
+ fprintf(out, " name=\"%s\"", xml_normalize_string(cputype_name(cpu[j].type)));
+
+ fprintf(out, " clock=\"%d\"", cpu[j].clock);
+ fprintf(out, "/>\n");
+ }
+ }
+
+ for(j=0;j<MAX_SOUND;++j)
+ {
+ if (sound[j].type != SOUND_DUMMY)
+ {
+ fprintf(out, "\t\t<chip");
+ fprintf(out, " type=\"audio\"");
+ fprintf(out, " name=\"%s\"", xml_normalize_string(sndtype_name(sound[j].type)));
+ if (sound[j].clock)
+ fprintf(out, " clock=\"%d\"", sound[j].clock);
+ fprintf(out, "/>\n");
+ }
+ }
+}
+
+static void print_game_display(FILE* out, const game_driver* game)
+{
+ machine_config driver;
+
+ int dx;
+ int dy;
+ int scrnum;
+
+ expand_machine_driver(game->drv, &driver);
+
+ for (scrnum = 0; scrnum < MAX_SCREENS; scrnum++)
+ if (driver.screen[scrnum].tag != NULL)
+ {
+ fprintf(out, "\t\t<display");
+
+ fprintf(out, " type=\"%s\"", (driver.video_attributes & VIDEO_TYPE_VECTOR) ? "vector" : "raster" );
+
+ 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 (! (driver.video_attributes & VIDEO_TYPE_VECTOR) )
+ {
+ dx = driver.screen[scrnum].defstate.visarea.max_x - driver.screen[scrnum].defstate.visarea.min_x + 1;
+ dy = driver.screen[scrnum].defstate.visarea.max_y - driver.screen[scrnum].defstate.visarea.min_y + 1;
+ fprintf(out, " width=\"%d\"", dx);
+ fprintf(out, " height=\"%d\"", dy);
+ }
+
+ fprintf(out, " refresh=\"%f\"", ATTOSECONDS_TO_HZ(driver.screen[scrnum].defstate.refresh));
+
+ fprintf(out, " />\n");
+ }
+}
+
+static void print_game_sound(FILE* out, const game_driver* game)
+{
+ machine_config driver;
+ const cpu_config* cpu;
+ const sound_config* sound;
+
+ /* check if the game have sound emulation */
+ int has_sound = 0;
+ int i;
+
+ expand_machine_driver(game->drv, &driver);
+ cpu = driver.cpu;
+ sound = driver.sound;
+
+ i = 0;
+ while (i < MAX_SOUND && !has_sound)
+ {
+ if (sound[i].type != SOUND_DUMMY)
+ has_sound = 1;
+ ++i;
+ }
+
+ fprintf(out, "\t\t<sound");
+
+ /* sound channel */
+ if (has_sound)
+ {
+ int speakers;
+ for (speakers = 0; speakers < MAX_SPEAKER; speakers++)
+ if (driver.speaker[speakers].tag == NULL)
+ break;
+ fprintf(out, " channels=\"%d\"", speakers);
+ }
+ else
+ fprintf(out, " channels=\"0\"");
+
+ fprintf(out, "/>\n");
+}
+
+static void print_game_driver(FILE* out, const game_driver* game)
+{
+ machine_config driver;
+
+ expand_machine_driver(game->drv, &driver);
+
+ 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\"", driver.total_colors);
+
+ fprintf(out, "/>\n");
+}
+
+/* Print the MAME info record for a game */
+static void print_game_info(FILE* out, const game_driver* game)
+{
+ const char *start;
+ const game_driver *clone_of;
+
+ /* No action if not a game */
+ if (game->flags & GAME_NO_STANDALONE)
+ return;
+
+ fprintf(out, "\t<" XML_TOP);
+
+ fprintf(out, " name=\"%s\"", xml_normalize_string(game->name) );
+
+ start = strrchr(game->source_file, '/');
+ if (!start)
+ start = strrchr(game->source_file, '\\');
+ if (!start)
+ start = game->source_file - 1;
+ fprintf(out, " sourcefile=\"%s\"", xml_normalize_string(start + 1));
+
+ if (game->flags & GAME_IS_BIOS_ROOT)
+ fprintf(out, " isbios=\"yes\"");
+
+ if (game->flags & GAME_NO_STANDALONE)
+ fprintf(out, " runnable=\"no\"");
+
+ clone_of = driver_get_clone(game);
+ if (clone_of && !(clone_of->flags & GAME_IS_BIOS_ROOT))
+ fprintf(out, " cloneof=\"%s\"", xml_normalize_string(clone_of->name));
+
+ if (clone_of)
+ fprintf(out, " romof=\"%s\"", xml_normalize_string(clone_of->name));
+
+ print_game_sampleof(out, game);
+
+ fprintf(out, ">\n");
+
+ if (game->description)
+ fprintf(out, "\t\t<description>%s</description>\n", xml_normalize_string(game->description));
+
+ /* print the year only if is a number */
+ if (game->year && strspn(game->year,"0123456789")==strlen(game->year))
+ fprintf(out, "\t\t<year>%s</year>\n", xml_normalize_string(game->year) );
+
+ if (game->manufacturer)
+ fprintf(out, "\t\t<manufacturer>%s</manufacturer>\n", xml_normalize_string(game->manufacturer));
+
+ print_game_bios(out, game);
+ print_game_rom(out, game);
+ print_game_sample(out, game);
+ print_game_micro(out, game);
+ print_game_display(out, game);
+ print_game_sound(out, game);
+ print_game_input(out, game);
+ print_game_switch(out, game);
+ print_game_driver(out, game);
+#ifdef MESS
+ print_game_device(out, game);
+ print_game_ramoptions(out, game);
+#endif
+
+ fprintf(out, "\t</" XML_TOP ">\n");
+}
+
+static void print_mame_data(FILE* out, const game_driver* const games[], const char *gamename)
+{
+ int j;
+
+ /* print games */
+ for(j=0;games[j];++j)
+ if (mame_strwildcmp(gamename, games[j]->name) == 0)
+ print_game_info(out, games[j]);
+}
+
+/* Print the MAME database in XML format */
+void print_mame_xml(FILE* out, const game_driver* const games[], const char *gamename)
+{
+ 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 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) #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<!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)
+ );
+
+ print_mame_data(out, games, gamename);
+
+ fprintf(out, "</" XML_ROOT ">\n");
+}