void sdl_osd_interface::init(running_machine &machine) { // call our parent osd_interface::init(machine); sdl_options &options = downcast<sdl_options &>(machine.options()); const char *stemp; // determine if we are benchmarking, and adjust options appropriately int bench = options.bench(); astring error_string; if (bench > 0) { options.set_value(OPTION_THROTTLE, false, OPTION_PRIORITY_MAXIMUM, error_string); options.set_value(OPTION_SOUND, false, OPTION_PRIORITY_MAXIMUM, error_string); options.set_value(SDLOPTION_VIDEO, "none", OPTION_PRIORITY_MAXIMUM, error_string); options.set_value(OPTION_SECONDS_TO_RUN, bench, OPTION_PRIORITY_MAXIMUM, error_string); assert(!error_string); } // Some driver options - must be before audio init! stemp = options.audio_driver(); if (stemp != NULL && strcmp(stemp, SDLOPTVAL_AUTO) != 0) { mame_printf_verbose("Setting SDL audiodriver '%s' ...\n", stemp); osd_setenv(SDLENV_AUDIODRIVER, stemp, 1); } stemp = options.video_driver(); if (stemp != NULL && strcmp(stemp, SDLOPTVAL_AUTO) != 0) { mame_printf_verbose("Setting SDL videodriver '%s' ...\n", stemp); osd_setenv(SDLENV_VIDEODRIVER, stemp, 1); } #if (SDLMAME_SDL2) stemp = options.render_driver(); if (stemp != NULL && strcmp(stemp, SDLOPTVAL_AUTO) != 0) { mame_printf_verbose("Setting SDL renderdriver '%s' ...\n", stemp); //osd_setenv(SDLENV_RENDERDRIVER, stemp, 1); SDL_SetHint(SDL_HINT_RENDER_DRIVER, stemp); } #endif /* Set the SDL environment variable for drivers wanting to load the * lib at startup. */ #if USE_OPENGL /* FIXME: move lib loading code from drawogl.c here */ stemp = options.gl_lib(); if (stemp != NULL && strcmp(stemp, SDLOPTVAL_AUTO) != 0) { osd_setenv("SDL_VIDEO_GL_DRIVER", stemp, 1); mame_printf_verbose("Setting SDL_VIDEO_GL_DRIVER = '%s' ...\n", stemp); } #endif /* get number of processors */ stemp = options.numprocessors(); osd_num_processors = 0; if (strcmp(stemp, "auto") != 0) { osd_num_processors = atoi(stemp); if (osd_num_processors < 1) { mame_printf_warning("numprocessors < 1 doesn't make much sense. Assuming auto ...\n"); osd_num_processors = 0; } } /* Initialize SDL */ if (!SDLMAME_INIT_IN_WORKER_THREAD) { #if (SDLMAME_SDL2) if (SDL_InitSubSystem(SDL_INIT_TIMER|SDL_INIT_AUDIO| SDL_INIT_VIDEO| SDL_INIT_JOYSTICK|SDL_INIT_NOPARACHUTE)) { #else if (SDL_Init(SDL_INIT_TIMER|SDL_INIT_AUDIO| SDL_INIT_VIDEO| SDL_INIT_JOYSTICK|SDL_INIT_NOPARACHUTE)) { #endif mame_printf_error("Could not initialize SDL %s\n", SDL_GetError()); exit(-1); } osd_sdl_info(); } // must be before sdlvideo_init! machine.add_notifier(MACHINE_NOTIFY_EXIT, machine_notify_delegate(FUNC(osd_exit), &machine)); defines_verbose(); if (!SDLMAME_HAS_DEBUGGER) if (machine.debug_flags & DEBUG_FLAG_OSD_ENABLED) { mame_printf_error("sdlmame: -debug not supported on X11-less builds\n\n"); osd_exit(machine); exit(-1); } if (sdlvideo_init(machine)) { osd_exit(machine); mame_printf_error("sdlvideo_init: Initialization failed!\n\n\n"); fflush(stderr); fflush(stdout); exit(-1); } sdlinput_init(machine); sdlaudio_init(machine); sdloutput_init(machine); #ifdef SDLMAME_NETWORK sdlnetdev_init(machine); #endif if (options.oslog()) machine.add_logerror_callback(output_oslog); /* now setup watchdog */ int watchdog_timeout = options.watchdog(); int str = options.seconds_to_run(); /* only enable watchdog if seconds_to_run is enabled *and* relatively short (time taken from ui.c) */ if ((watchdog_timeout != 0) && (str > 0) && (str < 60*5 )) { m_watchdog = auto_alloc(machine, watchdog); m_watchdog->setTimeout(watchdog_timeout); } #if (SDLMAME_SDL2) SDL_EventState(SDL_TEXTINPUT, SDL_TRUE); #else SDL_EnableUNICODE(SDL_TRUE); #endif } #if defined(SDLMAME_UNIX) && (!defined(SDLMAME_EMSCRIPTEN)) #define POINT_SIZE 144.0 #ifdef SDLMAME_MACOSX #define EXTRA_HEIGHT 1.0 #define EXTRA_WIDTH 1.15 //------------------------------------------------- // font_open - attempt to "open" a handle to the // font with the given name //------------------------------------------------- osd_font sdl_osd_interface::font_open(const char *_name, int &height) { CFStringRef font_name = NULL; CTFontRef ct_font = NULL; CTFontDescriptorRef font_descriptor; CGAffineTransform affine_transform = CGAffineTransformIdentity; astring name(_name); if (name == "default") { name = "LucidaGrande"; } /* handle bdf fonts in the core */ if (name.len() > 4) if (name.makeupper().substr(name.len()-4,4) == ".BDF" ) return NULL; font_name = CFStringCreateWithCString( NULL, name.cstr(), kCFStringEncodingUTF8 ); if( font_name != NULL ) { font_descriptor = CTFontDescriptorCreateWithNameAndSize( font_name, POINT_SIZE ); if( font_descriptor != NULL ) { ct_font = CTFontCreateWithFontDescriptor( font_descriptor, POINT_SIZE, &affine_transform ); CFRelease( font_descriptor ); } } CFRelease( font_name ); if (!ct_font) { mame_printf_verbose("Couldn't find/open font %s, using MAME default\n", name.cstr()); return NULL; } CFStringRef real_name = CTFontCopyPostScriptName( ct_font ); char real_name_c_string[255]; CFStringGetCString ( real_name, real_name_c_string, 255, kCFStringEncodingUTF8 ); mame_printf_verbose("Matching font: %s\n", real_name_c_string); CFRelease( real_name ); CGFloat line_height = 0.0; line_height += CTFontGetAscent(ct_font); line_height += CTFontGetDescent(ct_font); line_height += CTFontGetLeading(ct_font); height = ceilf(line_height * EXTRA_HEIGHT); return (osd_font)ct_font; }
void debug_view_state::recompute() { const debug_view_state_source &source = downcast<const debug_view_state_source &>(*m_source); // start with a blank list reset(); // add a cycles entry: cycles:99999999 state_item **tailptr = &m_state_list; *tailptr = auto_alloc(machine(), state_item(REG_CYCLES, "cycles", 8)); tailptr = &(*tailptr)->m_next; // add a beam entry: beamx:1234 *tailptr = auto_alloc(machine(), state_item(REG_BEAMX, "beamx", 4)); tailptr = &(*tailptr)->m_next; // add a beam entry: beamy:5678 *tailptr = auto_alloc(machine(), state_item(REG_BEAMY, "beamy", 4)); tailptr = &(*tailptr)->m_next; // add a beam entry: frame:123456 *tailptr = auto_alloc(machine(), state_item(REG_FRAME, "frame", 6)); tailptr = &(*tailptr)->m_next; // add a flags entry: flags:xxxxxxxx *tailptr = auto_alloc(machine(), state_item(STATE_GENFLAGS, "flags", source.m_stateintf->state_string_max_length(STATE_GENFLAGS))); tailptr = &(*tailptr)->m_next; // add a divider entry *tailptr = auto_alloc(machine(), state_item(REG_DIVIDER, "", 0)); tailptr = &(*tailptr)->m_next; // add all registers into it for (const device_state_entry *entry = source.m_stateintf->state_first(); entry != NULL; entry = entry->next()) if (entry->visible()) { *tailptr = auto_alloc(machine(), state_item(entry->index(), entry->symbol(), source.m_stateintf->state_string_max_length(entry->index()))); tailptr = &(*tailptr)->m_next; } // count the entries and determine the maximum tag and value sizes int count = 0; int maxtaglen = 0; int maxvallen = 0; for (state_item *item = m_state_list; item != NULL; item = item->m_next) { count++; maxtaglen = MAX(maxtaglen, item->m_symbol.len()); maxvallen = MAX(maxvallen, item->m_vallen); } // set the current divider and total cols m_divider = 1 + maxtaglen + 1; m_total.x = 1 + maxtaglen + 2 + maxvallen + 1; m_total.y = count; m_topleft.x = 0; m_topleft.y = 0; // no longer need to recompute m_recompute = false; }
void sdl_osd_interface::init(running_machine &machine) { // call our parent osd_common_t::init(machine); const char *stemp; // determine if we are benchmarking, and adjust options appropriately int bench = options().bench(); std::string error_string; if (bench > 0) { options().set_value(OPTION_THROTTLE, false, OPTION_PRIORITY_MAXIMUM, error_string); options().set_value(OSDOPTION_SOUND, "none", OPTION_PRIORITY_MAXIMUM, error_string); options().set_value(OSDOPTION_VIDEO, "none", OPTION_PRIORITY_MAXIMUM, error_string); options().set_value(OPTION_SECONDS_TO_RUN, bench, OPTION_PRIORITY_MAXIMUM, error_string); assert(error_string.c_str()[0] == 0); } // Some driver options - must be before audio init! stemp = options().audio_driver(); if (stemp != NULL && strcmp(stemp, OSDOPTVAL_AUTO) != 0) { osd_printf_verbose("Setting SDL audiodriver '%s' ...\n", stemp); osd_setenv(SDLENV_AUDIODRIVER, stemp, 1); } stemp = options().video_driver(); if (stemp != NULL && strcmp(stemp, OSDOPTVAL_AUTO) != 0) { osd_printf_verbose("Setting SDL videodriver '%s' ...\n", stemp); osd_setenv(SDLENV_VIDEODRIVER, stemp, 1); } stemp = options().render_driver(); if (stemp != NULL) { if (strcmp(stemp, OSDOPTVAL_AUTO) != 0) { osd_printf_verbose("Setting SDL renderdriver '%s' ...\n", stemp); //osd_setenv(SDLENV_RENDERDRIVER, stemp, 1); SDL_SetHint(SDL_HINT_RENDER_DRIVER, stemp); } else { #if defined(SDLMAME_WIN32) // OpenGL renderer has less issues with mode switching on windows osd_printf_verbose("Setting SDL renderdriver '%s' ...\n", "opengl"); //osd_setenv(SDLENV_RENDERDRIVER, stemp, 1); SDL_SetHint(SDL_HINT_RENDER_DRIVER, "opengl"); #endif } } /* Set the SDL environment variable for drivers wanting to load the * lib at startup. */ #if USE_OPENGL /* FIXME: move lib loading code from drawogl.c here */ stemp = options().gl_lib(); if (stemp != NULL && strcmp(stemp, OSDOPTVAL_AUTO) != 0) { osd_setenv("SDL_VIDEO_GL_DRIVER", stemp, 1); osd_printf_verbose("Setting SDL_VIDEO_GL_DRIVER = '%s' ...\n", stemp); } #endif /* get number of processors */ stemp = options().numprocessors(); osd_num_processors = 0; if (strcmp(stemp, "auto") != 0) { osd_num_processors = atoi(stemp); if (osd_num_processors < 1) { osd_printf_warning("numprocessors < 1 doesn't make much sense. Assuming auto ...\n"); osd_num_processors = 0; } } /* Initialize SDL */ if (!SDLMAME_INIT_IN_WORKER_THREAD) { #ifdef SDLMAME_EMSCRIPTEN // timer brings in threads which are not supported in Emscripten if (SDL_InitSubSystem(SDL_INIT_VIDEO| SDL_INIT_GAMECONTROLLER|SDL_INIT_NOPARACHUTE)) { #else if (SDL_InitSubSystem(SDL_INIT_TIMER| SDL_INIT_VIDEO| SDL_INIT_GAMECONTROLLER|SDL_INIT_NOPARACHUTE)) { #endif osd_printf_error("Could not initialize SDL %s\n", SDL_GetError()); exit(-1); } osd_sdl_info(); } defines_verbose(); osd_common_t::init_subsystems(); if (options().oslog()) machine.add_logerror_callback(output_oslog); /* now setup watchdog */ int watchdog_timeout = options().watchdog(); if (watchdog_timeout != 0) { m_watchdog = auto_alloc(machine, watchdog); m_watchdog->setTimeout(watchdog_timeout); } #ifdef SDLMAME_EMSCRIPTEN SDL_EventState(SDL_TEXTINPUT, SDL_FALSE); #else SDL_EventState(SDL_TEXTINPUT, SDL_TRUE); #endif }
device_t *at28c16_device_config::alloc_device( running_machine &machine ) const { return auto_alloc( &machine, at28c16_device( machine, *this ) ); }
bitmap_t *sdl_osd_interface::font_get_bitmap(osd_font font, unicode_char chnum, INT32 &width, INT32 &xoffs, INT32 &yoffs) { UniChar uni_char; CGGlyph glyph; bitmap_t *bitmap = (bitmap_t *)NULL; CTFontRef ct_font = (CTFontRef)font; const CFIndex count = 1; CGRect bounding_rect, success_rect; CGContextRef context_ref; if( chnum == ' ' ) { uni_char = 'n'; CTFontGetGlyphsForCharacters( ct_font, &uni_char, &glyph, count ); success_rect = CTFontGetBoundingRectsForGlyphs( ct_font, kCTFontDefaultOrientation, &glyph, &bounding_rect, count ); uni_char = chnum; CTFontGetGlyphsForCharacters( ct_font, &uni_char, &glyph, count ); } else { uni_char = chnum; CTFontGetGlyphsForCharacters( ct_font, &uni_char, &glyph, count ); success_rect = CTFontGetBoundingRectsForGlyphs( ct_font, kCTFontDefaultOrientation, &glyph, &bounding_rect, count ); } if( CGRectEqualToRect( success_rect, CGRectNull ) == false ) { size_t bitmap_width; size_t bitmap_height; bitmap_width = ceilf(bounding_rect.size.width * EXTRA_WIDTH); bitmap_width = bitmap_width == 0 ? 1 : bitmap_width; bitmap_height = ceilf( (CTFontGetAscent(ct_font) + CTFontGetDescent(ct_font) + CTFontGetLeading(ct_font)) * EXTRA_HEIGHT); xoffs = yoffs = 0; width = bitmap_width; size_t bits_per_component; CGColorSpaceRef color_space; CGBitmapInfo bitmap_info = kCGBitmapByteOrder32Host | kCGImageAlphaPremultipliedFirst; color_space = CGColorSpaceCreateDeviceRGB(); bits_per_component = 8; bitmap = auto_alloc(machine(), bitmap_t(bitmap_width, bitmap_height, BITMAP_FORMAT_ARGB32)); context_ref = CGBitmapContextCreate( bitmap->base, bitmap_width, bitmap_height, bits_per_component, bitmap->rowpixels*4, color_space, bitmap_info ); if( context_ref != NULL ) { CGFontRef font_ref; font_ref = CTFontCopyGraphicsFont( ct_font, NULL ); CGContextSetTextPosition(context_ref, -bounding_rect.origin.x*EXTRA_WIDTH, CTFontGetDescent(ct_font)+CTFontGetLeading(ct_font) ); CGContextSetRGBFillColor(context_ref, 1.0, 1.0, 1.0, 1.0); CGContextSetFont( context_ref, font_ref ); CGContextSetFontSize( context_ref, POINT_SIZE ); CGContextShowGlyphs( context_ref, &glyph, count ); CGFontRelease( font_ref ); CGContextRelease( context_ref ); } CGColorSpaceRelease( color_space ); } return bitmap; }
device_t *riot6532_device_config::alloc_device(running_machine &machine) const { return auto_alloc(&machine, riot6532_device(machine, *this)); }
device_t *speaker_device_config::alloc_device(running_machine &machine) const { return auto_alloc(&machine, speaker_device(machine, *this)); }
void video_manager::begin_recording(const char *name, movie_format format) { // stop any existign recording end_recording(); // create a snapshot bitmap so we know what the target size is create_snapshot_bitmap(NULL); // reset the state m_movie_frame = 0; m_movie_next_frame_time = machine().time(); // start up an AVI recording if (format == MF_AVI) { // build up information about this new movie avi_movie_info info; info.video_format = 0; info.video_timescale = 1000 * ((machine().primary_screen != NULL) ? ATTOSECONDS_TO_HZ(machine().primary_screen->frame_period().attoseconds) : screen_device::DEFAULT_FRAME_RATE); info.video_sampletime = 1000; info.video_numsamples = 0; info.video_width = m_snap_bitmap->width; info.video_height = m_snap_bitmap->height; info.video_depth = 24; info.audio_format = 0; info.audio_timescale = machine().sample_rate(); info.audio_sampletime = 1; info.audio_numsamples = 0; info.audio_channels = 2; info.audio_samplebits = 16; info.audio_samplerate = machine().sample_rate(); // create a new temporary movie file file_error filerr; astring fullpath; { emu_file tempfile(machine().options().snapshot_directory(), OPEN_FLAG_WRITE | OPEN_FLAG_CREATE | OPEN_FLAG_CREATE_PATHS); if (name != NULL) filerr = tempfile.open(name); else filerr = open_next(tempfile, "avi"); // compute the frame time m_movie_frame_period = attotime::from_seconds(1000) / info.video_timescale; // if we succeeded, make a copy of the name and create the real file over top if (filerr == FILERR_NONE) fullpath = tempfile.fullpath(); } if (filerr == FILERR_NONE) { // create the file and free the string avi_error avierr = avi_create(fullpath, &info, &m_avifile); if (avierr != AVIERR_NONE) mame_printf_error("Error creating AVI: %s\n", avi_error_string(avierr)); } } // start up a MNG recording else if (format == MF_MNG) { // create a new movie file and start recording m_mngfile = auto_alloc(machine(), emu_file(machine().options().snapshot_directory(), OPEN_FLAG_WRITE | OPEN_FLAG_CREATE | OPEN_FLAG_CREATE_PATHS)); file_error filerr; if (name != NULL) filerr = m_mngfile->open(name); else filerr = open_next(*m_mngfile, "mng"); if (filerr == FILERR_NONE) { // start the capture int rate = (machine().primary_screen != NULL) ? ATTOSECONDS_TO_HZ(machine().primary_screen->frame_period().attoseconds) : screen_device::DEFAULT_FRAME_RATE; png_error pngerr = mng_capture_start(*m_mngfile, m_snap_bitmap, rate); if (pngerr != PNGERR_NONE) return end_recording(); // compute the frame time m_movie_frame_period = attotime::from_hz(rate); } else { mame_printf_error("Error creating MNG\n"); global_free(m_mngfile); m_mngfile = NULL; } } }
cheat_entry::cheat_entry(cheat_manager &manager, symbol_table &globaltable, const char *filename, xml_data_node &cheatnode) : m_manager(manager), m_next(NULL), m_parameter(NULL), m_on_script(NULL), m_off_script(NULL), m_change_script(NULL), m_run_script(NULL), m_symbols(&manager.machine(), &globaltable), m_state(SCRIPT_STATE_OFF), m_numtemp(DEFAULT_TEMP_VARIABLES), m_argindex(0) { // reset scripts try { // pull the variable count out ahead of things int tempcount = xml_get_attribute_int(&cheatnode, "tempvariables", DEFAULT_TEMP_VARIABLES); if (tempcount < 1) throw emu_fatalerror("%s.xml(%d): invalid tempvariables attribute (%d)\n", filename, cheatnode.line, tempcount); // allocate memory for the cheat m_numtemp = tempcount; // get the description const char *description = xml_get_attribute_string(&cheatnode, "desc", NULL); if (description == NULL || description[0] == 0) throw emu_fatalerror("%s.xml(%d): empty or missing desc attribute on cheat\n", filename, cheatnode.line); m_description = description; // create the symbol table m_symbols.add("argindex", symbol_table::READ_ONLY, &m_argindex); astring tempname; for (int curtemp = 0; curtemp < tempcount; curtemp++) m_symbols.add(tempname.format("temp%d", curtemp), symbol_table::READ_WRITE); // read the first comment node xml_data_node *commentnode = xml_get_sibling(cheatnode.child, "comment"); if (commentnode != NULL) { // set the value if not NULL if (commentnode->value != NULL && commentnode->value[0] != 0) m_comment.cpy(commentnode->value); // only one comment is kept commentnode = xml_get_sibling(commentnode->next, "comment"); if (commentnode != NULL) mame_printf_warning("%s.xml(%d): only one comment node is retained; ignoring additional nodes\n", filename, commentnode->line); } // read the first parameter node xml_data_node *paramnode = xml_get_sibling(cheatnode.child, "parameter"); if (paramnode != NULL) { // load this parameter m_parameter = auto_alloc(manager.machine(), cheat_parameter(manager, m_symbols, filename, *paramnode)); // only one parameter allowed paramnode = xml_get_sibling(paramnode->next, "parameter"); if (paramnode != NULL) mame_printf_warning("%s.xml(%d): only one parameter node allowed; ignoring additional nodes\n", filename, paramnode->line); } // read the script nodes for (xml_data_node *scriptnode = xml_get_sibling(cheatnode.child, "script"); scriptnode != NULL; scriptnode = xml_get_sibling(scriptnode->next, "script")) { // load this entry cheat_script *curscript = auto_alloc(manager.machine(), cheat_script(manager, m_symbols, filename, *scriptnode)); // if we have a script already for this slot, it is an error cheat_script *&slot = script_for_state(curscript->state()); if (slot != NULL) mame_printf_warning("%s.xml(%d): only one on script allowed; ignoring additional scripts\n", filename, scriptnode->line); else slot = curscript; } } catch (emu_fatalerror &) { // call our destructor to clean up and re-throw this->~cheat_entry(); throw; } }
cheat_script::script_entry::script_entry(cheat_manager &manager, symbol_table &symbols, const char *filename, xml_data_node &entrynode, bool isaction) : m_next(NULL), m_condition(&symbols), m_expression(&symbols), m_arglist(manager.machine().respool()) { const char *expression = NULL; try { // read the condition if present expression = xml_get_attribute_string(&entrynode, "condition", NULL); if (expression != NULL) m_condition.parse(expression); // if this is an action, parse the expression if (isaction) { expression = entrynode.value; if (expression == NULL || expression[0] == 0) throw emu_fatalerror("%s.xml(%d): missing expression in action tag\n", filename, entrynode.line); m_expression.parse(expression); } // otherwise, parse the attributes and arguments else { // extract format const char *format = xml_get_attribute_string(&entrynode, "format", NULL); if (format == NULL || format[0] == 0) throw emu_fatalerror("%s.xml(%d): missing format in output tag\n", filename, entrynode.line); m_format.cpy(format); // extract other attributes m_line = xml_get_attribute_int(&entrynode, "line", 0); m_justify = JUSTIFY_LEFT; const char *align = xml_get_attribute_string(&entrynode, "align", "left"); if (strcmp(align, "center") == 0) m_justify = JUSTIFY_CENTER; else if (strcmp(align, "right") == 0) m_justify = JUSTIFY_RIGHT; else if (strcmp(align, "left") != 0) throw emu_fatalerror("%s.xml(%d): invalid alignment '%s' specified\n", filename, entrynode.line, align); // then parse arguments int totalargs = 0; for (xml_data_node *argnode = xml_get_sibling(entrynode.child, "argument"); argnode != NULL; argnode = xml_get_sibling(argnode->next, "argument")) { output_argument &curarg = m_arglist.append(*auto_alloc(manager.machine(), output_argument(manager, symbols, filename, *argnode))); // verify we didn't overrun the argument count totalargs += curarg.count(); if (totalargs > MAX_ARGUMENTS) throw emu_fatalerror("%s.xml(%d): too many arguments (found %d, max is %d)\n", filename, argnode->line, totalargs, MAX_ARGUMENTS); } // validate the format against the arguments validate_format(filename, entrynode.line); } } catch (expression_error &err) { throw emu_fatalerror("%s.xml(%d): error parsing cheat expression \"%s\" (%s)\n", filename, entrynode.line, expression, err.code_string()); } }
void cheat_manager::load_cheats(const char *filename) { xml_data_node *rootnode = NULL; emu_file cheatfile(machine().options().cheat_path(), OPEN_FLAG_READ); try { // open the file with the proper name file_error filerr = cheatfile.open(filename, ".xml"); // loop over all instrances of the files found in our search paths while (filerr == FILERR_NONE) { mame_printf_verbose(_("Loading cheats file from %s\n"), cheatfile.fullpath()); // read the XML file into internal data structures xml_parse_options options = { 0 }; xml_parse_error error; options.error = &error; rootnode = xml_file_read(cheatfile, &options); // if unable to parse the file, just bail if (rootnode == NULL) throw emu_fatalerror("%s.xml(%d): error parsing XML (%s)\n", filename, error.error_line, error.error_message); // find the layout node xml_data_node *mamecheatnode = xml_get_sibling(rootnode->child, "mamecheat"); if (mamecheatnode == NULL) throw emu_fatalerror("%s.xml: missing mamecheatnode node", filename); // validate the config data version int version = xml_get_attribute_int(mamecheatnode, "version", 0); if (version != CHEAT_VERSION) throw emu_fatalerror("%s.xml(%d): Invalid cheat XML file: unsupported version", filename, mamecheatnode->line); // parse all the elements for (xml_data_node *cheatnode = xml_get_sibling(mamecheatnode->child, "cheat"); cheatnode != NULL; cheatnode = xml_get_sibling(cheatnode->next, "cheat")) { // load this entry cheat_entry *curcheat = auto_alloc(machine(), cheat_entry(*this, m_symtable, filename, *cheatnode)); // make sure we're not a duplicate cheat_entry *scannode = NULL; if (REMOVE_DUPLICATE_CHEATS) for (scannode = m_cheatlist.first(); scannode != NULL; scannode = scannode->next()) if (strcmp(scannode->description(), curcheat->description()) == 0) { mame_printf_verbose(_("Ignoring duplicate cheat '%s' from file %s\n"), curcheat->description(), cheatfile.fullpath()); break; } // add to the end of the list if (scannode == NULL) m_cheatlist.append(*curcheat); else auto_free(machine(), curcheat); } // free the file and loop for the next one xml_file_free(rootnode); // open the next file in sequence filerr = cheatfile.open_next(); } } // handle errors cleanly catch (emu_fatalerror &err) { mame_printf_error("%s\n", err.string()); m_cheatlist.reset(); if (rootnode != NULL) xml_file_free(rootnode); } }