/*************************************************************************** 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 "emu.h" #include "machine/ram.h" #include "sound/samples.h" #include "info.h" #include "xmlfile.h" #include "hash.h" #include "config.h" #include /* MESS/MAME configuration */ #ifdef MESS #define XML_ROOT "mess" #define XML_TOP "machine" #else #define XML_ROOT "mame" #define XML_TOP "game" #endif /*************************************************************************** TYPE DEFINITIONS ***************************************************************************/ class parent_info { public: const game_driver *drv; machine_config mconfig; parent_info(const game_driver *drv) : mconfig(*drv) { this->drv = drv; } }; /*************************************************************************** CORE IMPLEMENTATION ***************************************************************************/ /*------------------------------------------------- print_game_switches - print the DIP switch settings for a game -------------------------------------------------*/ static void print_game_switches(FILE *out, const game_driver *game, const ioport_list &portlist) { const input_port_config *port; const input_field_config *field; /* iterate looking for DIP switches */ for (port = portlist.first(); 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\tport->tag)); fprintf(out, " mask=\"%u\"", field->mask); fprintf(out, ">\n"); /* loop over settings */ for (setting = field->settinglist; setting != NULL; setting = setting->next) { fprintf(out, "\t\t\tname)); fprintf(out, " value=\"%u\"", setting->value); if (setting->value == field->defvalue) fprintf(out, " default=\"yes\""); fprintf(out, "/>\n"); } /* terminate the switch entry */ fprintf(out, "\t\t\n"); } } /*------------------------------------------------- print_game_configs - print the Configuration settings for a game -------------------------------------------------*/ static void print_game_configs(FILE *out, const game_driver *game, const ioport_list &portlist) { const input_port_config *port; const input_field_config *field; /* iterate looking for configurations */ for (port = portlist.first(); port != NULL; port = port->next()) for (field = port->fieldlist; field != NULL; field = field->next) if (field->type == IPT_CONFIG) { const input_setting_config *setting; /* output the configuration name information */ fprintf(out, "\t\tport->tag)); fprintf(out, " mask=\"%u\"", field->mask); fprintf(out, ">\n"); /* loop over settings */ for (setting = field->settinglist; setting != NULL; setting = setting->next) { fprintf(out, "\t\t\tname)); fprintf(out, " value=\"%u\"", setting->value); if (setting->value == field->defvalue) fprintf(out, " default=\"yes\""); fprintf(out, "/>\n"); } /* terminate the configuration entry */ fprintf(out, "\t\t\n"); } } /*------------------------------------------------- print_game_adjusters - print the Analog Adjusters for a game -------------------------------------------------*/ static void print_game_adjusters(FILE *out, const game_driver *game, const ioport_list &portlist) { const input_port_config *port; const input_field_config *field; /* iterate looking for Adjusters */ for (port = portlist.first(); port != NULL; port = port->next()) for (field = port->fieldlist; field != NULL; field = field->next) if (field->type == IPT_ADJUSTER) { /* output the adjuster information */ fprintf(out, "\t\t\n", xml_normalize_string(input_field_name(field)), field->defvalue); } } /*------------------------------------------------- print_game_input - print a summary of a game's input -------------------------------------------------*/ static void print_game_input(FILE *out, const game_driver *game, const ioport_list &portlist) { /* fix me -- this needs to be cleaned up to match the core style */ enum {cjoy, cdoublejoy, cAD_stick, cdial, ctrackball, cpaddle, clightgun, cpedal, ckeypad, ckeyboard, 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* const control_types[] = {"joy", "doublejoy", "stick", "dial", "trackball", "paddle", "lightgun", "pedal", "keypad", "keyboard"}; static struct _input_info { const char * type; /* general type of input */ const char * Xway; /* 2, 4, or 8 way */ int analog; int keyb; 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].keyb = 0; control[i].min = 0; control[i].max = 0; control[i].sensitivity = 0; control[i].keydelta = 0; control[i].reverse = 0; } for (port = portlist.first(); 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; case IPT_KEYPAD: control[ckeypad].keyb = 1; break; case IPT_KEYBOARD: control[ckeyboard].keyb = 1; 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\n"); for (i = 0; i < ENDCONTROLTYPES; i++) { if (control[i].Xway != NULL) fprintf(out, "\t\t\t\n", xml_normalize_string(control[i].Xway)); if (control[i].analog) { fprintf(out, "\t\t\t\n"); } if (control[i].keyb) { fprintf(out, "\t\t\t\n", xml_normalize_string(control_types[i])); } } fprintf(out, "\t\t\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\n"); } } /*------------------------------------------------- get_merge_name - get the rom name from a parent set -------------------------------------------------*/ static const char *get_merge_name(const rom_entry *rom, int parents, const parent_info **pinfoarray) { int parent; const char *merge_name = NULL; for (parent = 0; parent < parents; ++parent) { const machine_config *pconfig = &pinfoarray[parent]->mconfig; const rom_source *psource; const rom_entry *pregion, *prom; /* scan the clone_of ROM for a matching ROM entry */ for (psource = rom_first_source(*pconfig); psource != NULL; psource = rom_next_source(*psource)) for (pregion = rom_first_region(*psource); 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)) { merge_name = ROM_GETNAME(prom); break; } } return merge_name; } /*------------------------------------------------- print_game_rom - print the roms section of the XML output -------------------------------------------------*/ static void print_game_rom(FILE *out, const game_driver *game, const machine_config &config) { const game_driver *clone_of = driver_get_clone(game); int rom_type; int parents = 0; const parent_info *pinfoarray[4]; for (; clone_of != NULL; clone_of = driver_get_clone(clone_of)) { assert_always(parents < ARRAY_LENGTH(pinfoarray), "too many parents"); pinfoarray[parents++] = global_alloc(parent_info(clone_of)); } /* iterate over 3 different ROM "types": BIOS, ROMs, DISKs */ for (rom_type = 0; rom_type < 3; rom_type++) { const rom_source *source; const rom_entry *region; /* iterate over ROM sources: first the game, then any devices */ 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)) { 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 char *merge_name = NULL; char bios_name[100]; /* BIOS ROMs only apply to bioses */ if ((is_bios && rom_type != 0) || (!is_bios && rom_type == 0)) continue; /* if we have a valid ROM and we are a clone, see if we can find the parent ROM */ if (!ROM_NOGOODDUMP(rom) && parents > 0) { merge_name = get_merge_name(rom, parents, pinfoarray); } /* 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\n"); } } } for (; parents > 0; parents--) global_free(pinfoarray[parents - 1]); } /*------------------------------------------------- print_game_sampleof - print the 'sampleof' attribute, if appropriate -------------------------------------------------*/ static void print_game_sampleof(FILE *out, const game_driver *game, const machine_config &config) { 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 char *const *samplenames = ((const samples_interface *)sound->devconfig().static_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)); /* must stop here, as there can only be one attribute of the same name */ return; } } } } /*------------------------------------------------- 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) { const device_config_sound_interface *sound = NULL; /* iterate over sound chips looking for samples */ for (bool gotone = config.m_devicelist.first(sound); gotone; gotone = sound->next(sound)) if (sound->devconfig().type() == SAMPLES) { const char *const *samplenames = ((const samples_interface *)sound->devconfig().static_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\n", xml_normalize_string(cursampname)); } } } } /*------------------------------------------------- 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) { /* iterate over CPUs */ const device_config_execute_interface *exec = NULL; for (bool gotone = config.m_devicelist.first(exec); gotone; gotone = exec->next(exec)) { fprintf(out, "\t\tdevconfig().tag())); fprintf(out, " name=\"%s\"", xml_normalize_string(exec->devconfig().name())); fprintf(out, " clock=\"%d\"", exec->devconfig().clock()); fprintf(out, "/>\n"); } /* iterate over sound chips */ const device_config_sound_interface *sound = NULL; for (bool gotone = config.m_devicelist.first(sound); gotone; gotone = sound->next(sound)) { fprintf(out, "\t\tdevconfig().tag())); fprintf(out, " name=\"%s\"", xml_normalize_string(sound->devconfig().name())); if (sound->devconfig().clock() != 0) fprintf(out, " clock=\"%d\"", sound->devconfig().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 screen_device_config *devconfig; /* iterate over screens */ for (devconfig = config.first_screen(); devconfig != NULL; devconfig = devconfig->next_screen()) { fprintf(out, "\t\tscreen_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 (devconfig->screen_type() != SCREEN_TYPE_VECTOR) { const rectangle &visarea = devconfig->visible_area(); int dx = visarea.max_x - visarea.min_x + 1; int dy = visarea.max_y - visarea.min_y + 1; fprintf(out, " width=\"%d\"", dx); fprintf(out, " height=\"%d\"", dy); } /* output refresh rate */ fprintf(out, " refresh=\"%f\"", ATTOSECONDS_TO_HZ(devconfig->refresh())); /* output raw video parameters only for games that are not vector */ /* and had raw parameters specified */ if (devconfig->screen_type() != SCREEN_TYPE_VECTOR && !devconfig->oldstyle_vblank_supplied()) { int pixclock = devconfig->width() * devconfig->height() * ATTOSECONDS_TO_HZ(devconfig->refresh()); fprintf(out, " pixclock=\"%d\"", pixclock); fprintf(out, " htotal=\"%d\"", devconfig->width()); fprintf(out, " hbend=\"%d\"", devconfig->visible_area().min_x); fprintf(out, " hbstart=\"%d\"", devconfig->visible_area().max_x+1); fprintf(out, " vtotal=\"%d\"", devconfig->height()); fprintf(out, " vbend=\"%d\"", devconfig->visible_area().min_y); fprintf(out, " vbstart=\"%d\"", devconfig->visible_area().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 = config.m_devicelist.count(SPEAKER); /* if we have no sound, zero out the speaker count */ const device_config_sound_interface *sound = NULL; if (!config.m_devicelist.first(sound)) speakers = 0; fprintf(out, "\t\t\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\tflags & (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.m_total_colors); fprintf(out, "/>\n"); } /*------------------------------------------------- print_game_categories - print the Categories settings for a system -------------------------------------------------*/ static void print_game_categories(FILE *out, const game_driver *game, const ioport_list &portlist) { const input_port_config *port; const input_field_config *field; /* iterate looking for Categories */ for (port = portlist.first(); port != NULL; port = port->next()) for (field = port->fieldlist; field != NULL; field = field->next) if (field->type == IPT_CATEGORY) { const input_setting_config *setting; /* output the category name information */ fprintf(out, "\t\t\n", xml_normalize_string(input_field_name(field))); /* loop over item settings */ for (setting = field->settinglist; setting != NULL; setting = setting->next) { fprintf(out, "\t\t\tname)); if (setting->value == field->defvalue) fprintf(out, " default=\"yes\""); fprintf(out, "/>\n"); } /* terminate the category entry */ fprintf(out, "\t\t\n"); } } /*------------------------------------------------- print_game_images - prints out all info on image devices -------------------------------------------------*/ static void print_game_images(FILE *out, const game_driver *game, const machine_config &config) { const device_config_image_interface *dev = NULL; const char *name; const char *shortname; for (bool gotone = config.m_devicelist.first(dev); gotone; gotone = dev->next(dev)) { /* print out device type */ fprintf(out, "\t\timage_type_name())); /* does this device have a tag? */ if (dev->devconfig().tag()) fprintf(out, " tag=\"%s\"", xml_normalize_string(dev->devconfig().tag())); /* is this device mandatory? */ if (dev->must_be_loaded()) fprintf(out, " mandatory=\"1\""); if (dev->image_interface()[0] ) fprintf(out, " interface=\"%s\"", xml_normalize_string(dev->image_interface())); /* close the XML tag */ fprintf(out, ">\n"); name = dev->instance_name(); shortname = dev->brief_instance_name(); fprintf(out, "\t\t\t\n"); astring extensions(dev->file_extensions()); char *ext = strtok((char*)extensions.cstr(),","); while (ext != NULL) { fprintf(out, "\t\t\t\n"); ext = strtok (NULL, ","); } fprintf(out, "\t\t\n"); } } /*------------------------------------------------- print_game_software_list - print the information for all known software lists for this system -------------------------------------------------*/ static void print_game_software_list(FILE *out, const game_driver *game, const machine_config &config) { for (const device_config *dev = config.m_devicelist.first(SOFTWARE_LIST); dev != NULL; dev = dev->typenext()) { software_list_config *swlist = (software_list_config *)downcast(dev)->inline_config(); for ( int i = 0; i < DEVINFO_STR_SWLIST_MAX - DEVINFO_STR_SWLIST_0; i++ ) { if ( swlist->list_name[i] ) { fprintf(out, "\t\tlist_name[i] ); fprintf(out, "status=\"%s\" />\n", (swlist->list_type == SOFTWARE_LIST_ORIGINAL_SYSTEM) ? "original" : "compatible" ); } } } } /* device iteration helpers */ #define ram_first(config) (config).m_devicelist.first(RAM) #define ram_next(previous) ((previous)->typenext()) /*------------------------------------------------- print_game_ramoptions - prints out all RAM options for this system -------------------------------------------------*/ static void print_game_ramoptions(FILE *out, const game_driver *game, const machine_config &config) { const device_config *device; for (device = ram_first(config); device != NULL; device = ram_next(device)) { ram_config *ram = (ram_config *)downcast(device)->inline_config(); fprintf(out, "\t\t%u\n", ram_parse_string(ram->default_size)); if (ram->extra_options != NULL) { int j; int size = strlen(ram->extra_options); char * const s = mame_strdup(ram->extra_options); char * const e = s + size; char *p = s; for (j=0;j%u\n", ram_parse_string(p)); p += strlen(p); if (p == e) break; p += 1; } osd_free(s); } } } /*------------------------------------------------- print_game_info - print the XML information for one particular game driver -------------------------------------------------*/ static void print_game_info(FILE *out, const game_driver *game) { const game_driver *clone_of; machine_config config(*game); ioport_list portlist; 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 */ input_port_list_init(portlist, game->ipt, NULL, 0, FALSE); /* 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\""); if (game->flags & GAME_MECHANICAL) fprintf(out, " ismechanical=\"yes\""); /* 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%s\n", xml_normalize_string(game->description)); /* print the year only if is a number or another allowed character (? or +) */ if (game->year != NULL && strspn(game->year, "0123456789?+") == strlen(game->year)) fprintf(out, "\t\t%s\n", xml_normalize_string(game->year)); /* print the manufacturer information */ if (game->manufacturer != NULL) fprintf(out, "\t\t%s\n", xml_normalize_string(game->manufacturer)); /* now print various additional information */ print_game_bios(out, game); print_game_rom(out, game, config); 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, portlist); print_game_switches(out, game, portlist); print_game_configs(out, game, portlist); print_game_categories(out, game, portlist); print_game_adjusters(out, game, portlist); print_game_driver(out, game, config); print_game_images( out, game, config ); print_game_software_list( out, game, config ); print_game_ramoptions( out, game, config ); /* close the topmost tag */ fprintf(out, "\t\n"); } /*------------------------------------------------- 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, "\n" "\n" "\t\n" "\t\n" "\t\n" "\t\n" "\t\t\n" "\t\t\n" "\t\t\n" "\t\t\n" "\t\t\n" "\t\t\n" "\t\t\n" "\t\t\n" "\t\t\n" "\t\t\n" "\t\t\n" "\t\t\n" "\t\t\t\n" "\t\t\t\n" "\t\t\t\n" "\t\t\n" "\t\t\t\n" "\t\t\t\n" "\t\t\t\n" "\t\t\t\n" "\t\t\t\n" "\t\t\t\n" "\t\t\t\n" "\t\t\t\n" "\t\t\t\n" "\t\t\t\n" "\t\t\t\n" "\t\t\n" "\t\t\t\n" "\t\t\t\n" "\t\t\t\n" "\t\t\t\n" "\t\t\t\n" "\t\t\t\n" "\t\t\t\n" "\t\t\t\n" "\t\t\n" "\t\t\t\n" "\t\t\n" "\t\t\t\n" "\t\t\t\n" "\t\t\t\n" "\t\t\t\n" "\t\t\n" "\t\t\t\n" "\t\t\t\n" "\t\t\t\n" "\t\t\t\n" "\t\t\t\n" "\t\t\t\n" "\t\t\t\n" "\t\t\t\n" "\t\t\t\n" "\t\t\t\n" "\t\t\t\n" "\t\t\t\n" "\t\t\t\n" "\t\t\n" "\t\t\t\n" "\t\t\n" "\t\t\t\n" "\t\t\t\n" "\t\t\t\n" "\t\t\t\n" "\t\t\t\n" "\t\t\t\n" "\t\t\t\t\n" "\t\t\t\t\n" "\t\t\t\t\n" "\t\t\t\t\n" "\t\t\t\t\n" "\t\t\t\t\n" "\t\t\n" "\t\t\t\n" "\t\t\t\n" "\t\t\t\n" "\t\t\t\n" "\t\t\t\t\n" "\t\t\t\t\n" "\t\t\t\t\n" "\t\t\n" "\t\t\t\n" "\t\t\t\n" "\t\t\t\n" "\t\t\t\n" "\t\t\t\t\n" "\t\t\t\t\n" "\t\t\t\t\n" "\t\t\n" "\t\t\t\n" "\t\t\t\n" "\t\t\t\t\n" "\t\t\t\t\n" "\t\t\n" "\t\t\t\n" "\t\t\t\n" "\t\t\n" "\t\t\t\n" "\t\t\t\n" "\t\t\t\n" "\t\t\t\n" "\t\t\t\n" "\t\t\t\n" "\t\t\t\n" "\t\t\t\n" "\t\t\t\n" "\t\t\n" "\t\t\t\n" "\t\t\t\n" "\t\t\t\n" "\t\t\t\n" "\t\t\t\n" "\t\t\t\t\n" "\t\t\t\t\n" "\t\t\t\n" "\t\t\t\t\n" "\t\t\n" "\t\t\t\n" "\t\t\t\n" "\t\t\n" "\t\t\t\n" "]>\n\n" "<" XML_ROOT " build=\"%s\" debug=\"" #ifdef MAME_DEBUG "yes" #else "no" #endif "\" mameconfig=\"%d\">\n", xml_normalize_string(build_version), CONFIG_VERSION ); for (drvnum = 0; games[drvnum] != NULL; drvnum++) if (mame_strwildcmp(gamename, games[drvnum]->name) == 0) print_game_info(out, games[drvnum]); fprintf(out, "\n"); }