diff options
-rw-r--r-- | .gitattributes | 4 | ||||
-rw-r--r-- | src/emu/devimage.c | 119 | ||||
-rw-r--r-- | src/emu/devlegcy.h | 10 | ||||
-rw-r--r-- | src/emu/diimage.c | 185 | ||||
-rw-r--r-- | src/emu/diimage.h | 58 | ||||
-rw-r--r-- | src/emu/emu.h | 1 | ||||
-rw-r--r-- | src/emu/emu.mak | 2 | ||||
-rw-r--r-- | src/emu/romload.c | 2 | ||||
-rw-r--r-- | src/emu/romload.h | 3 | ||||
-rw-r--r-- | src/emu/softlist.c | 1445 | ||||
-rw-r--r-- | src/emu/softlist.h | 113 | ||||
-rw-r--r-- | src/emu/ui.c | 29 | ||||
-rw-r--r-- | src/emu/uiimage.c | 1130 | ||||
-rw-r--r-- | src/emu/uiimage.h | 27 | ||||
-rw-r--r-- | src/emu/uimenu.c | 21 |
15 files changed, 2981 insertions, 168 deletions
diff --git a/.gitattributes b/.gitattributes index ef6db93cf97..afc501b3726 100644 --- a/.gitattributes +++ b/.gitattributes @@ -814,6 +814,8 @@ src/emu/romload.c svneol=native#text/plain src/emu/romload.h svneol=native#text/plain src/emu/schedule.c svneol=native#text/plain src/emu/schedule.h svneol=native#text/plain +src/emu/softlist.c svneol=native#text/plain +src/emu/softlist.h svneol=native#text/plain src/emu/sound.c svneol=native#text/plain src/emu/sound.h svneol=native#text/plain src/emu/sound/2151intf.c svneol=native#text/plain @@ -1050,6 +1052,8 @@ src/emu/ui.c svneol=native#text/plain src/emu/ui.h svneol=native#text/plain src/emu/uigfx.c svneol=native#text/plain src/emu/uigfx.h svneol=native#text/plain +src/emu/uiimage.c svneol=native#text/plain +src/emu/uiimage.h svneol=native#text/plain src/emu/uiinput.c svneol=native#text/plain src/emu/uiinput.h svneol=native#text/plain src/emu/uimenu.c svneol=native#text/plain diff --git a/src/emu/devimage.c b/src/emu/devimage.c index fb52fc4cd88..8c0f36b1774 100644 --- a/src/emu/devimage.c +++ b/src/emu/devimage.c @@ -209,25 +209,13 @@ legacy_image_device_base::legacy_image_device_base(running_machine &machine, con ****************************************************************************/ /*------------------------------------------------- - set_image_filename - specifies the filename of - an image --------------------------------------------------*/ - -image_error_t legacy_image_device_base::set_image_filename(const char *filename) -{ - m_name = filename; - zippath_parent(&m_working_directory, filename); - return IMAGE_ERROR_SUCCESS; -} - -/*------------------------------------------------- is_loaded - quick check to determine whether an image is loaded -------------------------------------------------*/ bool legacy_image_device_base::is_loaded() { - return (m_file != NULL); // (image->software_info_ptr != NULL); + return (m_file != NULL) || (m_software_info_ptr != NULL); } /*------------------------------------------------- @@ -332,6 +320,8 @@ bool legacy_image_device_base::load_internal(const char *path, bool is_create, i goto done; /* Check if there's a software list defined for this device and use that if we're not creating an image */ + if (is_create || !load_software_part( this, path, &m_software_info_ptr, &m_software_part_ptr, &m_full_software_name ) ) + { /* determine open plan */ determine_open_plan(is_create, open_plan); @@ -343,7 +333,17 @@ bool legacy_image_device_base::load_internal(const char *path, bool is_create, i if (err && (err != IMAGE_ERROR_FILENOTFOUND)) goto done; } - + } + + /* Copy some image information when we have been loaded through a software list */ + if ( m_software_info_ptr ) + { + m_longname = m_software_info_ptr->longname; + m_manufacturer = m_software_info_ptr->publisher; + m_year = m_software_info_ptr->year; + //m_playable = m_software_info_ptr->supported; + } + /* did we fail to find the file? */ if (!is_loaded()) { @@ -469,6 +469,18 @@ void legacy_image_device_base::clear() m_name.reset(); m_writeable = FALSE; m_created = FALSE; + + m_longname.reset(); + m_manufacturer.reset(); + m_year.reset(); + m_playable.reset(); + m_extrainfo.reset(); + m_basename_noext.reset(); + m_filetype.reset(); + + m_full_software_name = NULL; + m_software_info_ptr = NULL; + m_software_part_ptr = NULL; } /*------------------------------------------------- @@ -480,82 +492,3 @@ void legacy_image_device_base::unload() clear(); } - -/*************************************************************************** - WORKING DIRECTORIES -***************************************************************************/ - -/*------------------------------------------------- - try_change_working_directory - tries to change - the working directory, but only if the directory - actually exists --------------------------------------------------*/ -bool legacy_image_device_base::try_change_working_directory(const char *subdir) -{ - osd_directory *directory; - const osd_directory_entry *entry; - bool success = FALSE; - bool done = FALSE; - - directory = osd_opendir(m_working_directory.cstr()); - if (directory != NULL) - { - while(!done && (entry = osd_readdir(directory)) != NULL) - { - if (!mame_stricmp(subdir, entry->name)) - { - done = TRUE; - success = entry->type == ENTTYPE_DIR; - } - } - - osd_closedir(directory); - } - - /* did we successfully identify the directory? */ - if (success) - zippath_combine(&m_working_directory, m_working_directory, subdir); - - return success; -} -/*------------------------------------------------- - setup_working_directory - sets up the working - directory according to a few defaults --------------------------------------------------*/ - -void legacy_image_device_base::setup_working_directory() -{ - const game_driver *gamedrv; - char *dst = NULL; - - osd_get_full_path(&dst,"."); - /* first set up the working directory to be the starting directory */ - m_working_directory = dst; - - /* now try browsing down to "software" */ - if (try_change_working_directory("software")) - { - /* now down to a directory for this computer */ - gamedrv = device().machine->gamedrv; - while(gamedrv && !try_change_working_directory(gamedrv->name)) - { - gamedrv = driver_get_compatible(gamedrv); - } - } - osd_free(dst); -} - -//------------------------------------------------- -// working_directory - returns the working -// directory to use for this image; this is -// valid even if not mounted -//------------------------------------------------- - -const char * legacy_image_device_base::working_directory() -{ - /* check to see if we've never initialized the working directory */ - if (m_working_directory.len() == 0) - setup_working_directory(); - - return m_working_directory; -} diff --git a/src/emu/devlegcy.h b/src/emu/devlegcy.h index c806796d4a1..3a53e7c2e86 100644 --- a/src/emu/devlegcy.h +++ b/src/emu/devlegcy.h @@ -638,8 +638,6 @@ class legacy_image_device_base : public legacy_device_base, { friend class legacy_image_device_config_base; public: - virtual void set_working_directory(const char *working_directory) { m_working_directory = working_directory; } - virtual const char * working_directory(); virtual bool load(const char *path); virtual bool finish_load(); virtual void unload(); @@ -648,16 +646,8 @@ protected: // construction/destruction legacy_image_device_base(running_machine &machine, const device_config &config); // device_image_interface overrides - - /* working directory; persists across mounts */ - astring m_working_directory; - - void setup_working_directory(); - bool try_change_working_directory(const char *subdir); - bool load_internal(const char *path, bool is_create, int create_format, option_resolution *create_args); void determine_open_plan(int is_create, UINT32 *open_plan); - image_error_t set_image_filename(const char *filename); image_error_t load_image_by_path(UINT32 open_flags, const char *path); void clear(); bool is_loaded(); diff --git a/src/emu/diimage.c b/src/emu/diimage.c index 48f510ce7b2..f3ed1c757eb 100644 --- a/src/emu/diimage.c +++ b/src/emu/diimage.c @@ -39,6 +39,7 @@ #include "emu.h" #include "ui.h" +#include "zippath.h" //************************************************************************** @@ -130,7 +131,10 @@ const char *device_config_image_interface::device_brieftypename(iodevice_t type) device_image_interface::device_image_interface(running_machine &machine, const device_config &config, device_t &device) : device_interface(machine, config, device), m_image_config(dynamic_cast<const device_config_image_interface &>(config)), - m_file(NULL) + m_file(NULL), + m_full_software_name(NULL), + m_software_info_ptr(NULL), + m_software_part_ptr(NULL) { } @@ -143,6 +147,45 @@ device_image_interface::~device_image_interface() { } +/*------------------------------------------------- + display - call image display callback function +-------------------------------------------------*/ + +void device_image_interface::display() +{ +} + + +/*------------------------------------------------- + set_image_filename - specifies the filename of + an image +-------------------------------------------------*/ + +image_error_t device_image_interface::set_image_filename(const char *filename) +{ + m_name = filename; + zippath_parent(&m_working_directory, filename); + m_basename = m_name.cpy(m_name); + + int loc1 = m_name.rchr(0,'\\'); + int loc2 = m_name.rchr(0,'/'); + int loc3 = m_name.rchr(0,':'); + int loc = MAX(loc1,MAX(loc2,loc3)); + if (loc!=-1) { + m_basename = m_basename.substr(loc + 1,m_basename.len()-loc); + } + m_basename_noext = m_basename.cpy(m_basename); + m_filetype = ""; + loc = m_basename_noext.rchr(0,'.'); + if (loc!=-1) { + m_basename_noext = m_basename_noext.substr(0,loc); + m_filetype = m_basename.cpy(m_basename); + m_filetype = m_filetype.substr(loc + 1,m_filetype.len()-loc); + } + + return IMAGE_ERROR_SUCCESS; +} + /**************************************************************************** CREATION FORMATS ****************************************************************************/ @@ -260,74 +303,132 @@ void device_image_interface::message(const char *format, ...) } -/**************************************************************************** - Accessor functions +/*************************************************************************** + WORKING DIRECTORIES +***************************************************************************/ - These provide information about the device; and about the mounted image -****************************************************************************/ +/*------------------------------------------------- + try_change_working_directory - tries to change + the working directory, but only if the directory + actually exists +-------------------------------------------------*/ +bool device_image_interface::try_change_working_directory(const char *subdir) +{ + osd_directory *directory; + const osd_directory_entry *entry; + bool success = FALSE; + bool done = FALSE; + + directory = osd_opendir(m_working_directory.cstr()); + if (directory != NULL) + { + while(!done && (entry = osd_readdir(directory)) != NULL) + { + if (!mame_stricmp(subdir, entry->name)) + { + done = TRUE; + success = entry->type == ENTTYPE_DIR; + } + } + + osd_closedir(directory); + } + + /* did we successfully identify the directory? */ + if (success) + zippath_combine(&m_working_directory, m_working_directory, subdir); + return success; +} /*------------------------------------------------- - filename + setup_working_directory - sets up the working + directory according to a few defaults -------------------------------------------------*/ -const char *device_image_interface::filename() +void device_image_interface::setup_working_directory() { - const char *name = m_name; - return (name[0] != '\0') ? name : NULL; + const game_driver *gamedrv; + char *dst = NULL; + + osd_get_full_path(&dst,"."); + /* first set up the working directory to be the starting directory */ + m_working_directory = dst; + + /* now try browsing down to "software" */ + if (try_change_working_directory("software")) + { + /* now down to a directory for this computer */ + gamedrv = device().machine->gamedrv; + while(gamedrv && !try_change_working_directory(gamedrv->name)) + { + gamedrv = driver_get_compatible(gamedrv); + } + } + osd_free(dst); } +//------------------------------------------------- +// working_directory - returns the working +// directory to use for this image; this is +// valid even if not mounted +//------------------------------------------------- + +const char * device_image_interface::working_directory() +{ + /* check to see if we've never initialized the working directory */ + if (m_working_directory.len() == 0) + setup_working_directory(); + + return m_working_directory; +} + + /*------------------------------------------------- - basename + get_software_region -------------------------------------------------*/ -const char *device_image_interface::basename() +UINT8 *device_image_interface::get_software_region(const char *tag) { - char *fname = (char*)astring(filename()).cstr(); - const char *c; + char full_tag[256]; - // NULL begets NULL - if (!fname) + if ( m_software_info_ptr == NULL || m_software_part_ptr == NULL ) return NULL; - // start at the end and return when we hit a slash or colon - for (c = fname + strlen(fname) - 1; c >= fname; c--) - if (*c == '\\' || *c == '/' || *c == ':') - return c + 1; - - // otherwise, return the whole thing - return fname; + sprintf( full_tag, "%s:%s", device().tag(), tag ); + return memory_region( device().machine, full_tag ); } /*------------------------------------------------- - basename_noext + image_get_software_region_length -------------------------------------------------*/ -const char *device_image_interface::basename_noext() +UINT32 device_image_interface::get_software_region_length(const char *tag) { - const char *s; - char *ext; + char full_tag[256]; - s = astring(basename()); - if (s) - { - ext = (char *)strrchr(s, '.'); - if (ext) - *ext = '\0'; - } - return s; + sprintf( full_tag, "%s:%s", device().tag(), tag ); + return memory_region_length( device().machine, full_tag ); } - /*------------------------------------------------- - filetype --------------------------------------------------*/ + image_get_feature + -------------------------------------------------*/ -const char *device_image_interface::filetype() +const char *device_image_interface::get_feature(const char *feature_name) { - const char *s = filename(); - if (s != NULL) - s = strrchr(s, '.'); - return s ? s+1 : NULL; + feature_list *feature; + + if ( ! m_software_part_ptr->featurelist ) + return NULL; + + for ( feature = m_software_part_ptr->featurelist; feature; feature = feature->next ) + { + if ( ! strcmp( feature->name, feature_name ) ) + return feature->value; + } + + return NULL; } + diff --git a/src/emu/diimage.h b/src/emu/diimage.h index 6a8815d06f9..70bb5556c6d 100644 --- a/src/emu/diimage.h +++ b/src/emu/diimage.h @@ -103,6 +103,9 @@ struct image_device_format }; class device_image_interface; +struct feature_list; +struct software_part; +struct software_info; // device image interface function types typedef int (*device_image_load_func)(device_image_interface &image); @@ -188,12 +191,12 @@ public: device_image_interface(running_machine &machine, const device_config &config, device_t &device); virtual ~device_image_interface(); - virtual void set_working_directory(const char *working_directory) = 0; - virtual const char * working_directory() = 0; virtual bool load(const char *path) = 0; virtual bool finish_load() = 0; virtual void unload() = 0; + virtual void display(); + virtual const image_device_format *device_get_indexed_creatable_format(int index); virtual const image_device_format *device_get_named_creatable_format(const char *format_name); const option_guide *image_device_get_creation_option_guide() { return m_image_config.create_option_guide(); } @@ -206,10 +209,10 @@ public: void message(const char *format, ...); bool exists() { return m_name.len() != 0; } - const char *filename(); - const char *basename(); - const char *basename_noext(); - const char *filetype(); + const char *filename() { if (m_name.len()==0) return NULL; else return m_name; } + const char *basename() { if (m_basename.len()==0) return NULL; else return m_basename; } + const char *basename_noext() { if (m_basename_noext.len()==0) return NULL; else return m_basename_noext; } + const char *filetype() { if (m_filetype.len()==0) return NULL; else return m_filetype; } core_file *image_core_file() { return m_file; } UINT64 length() { check_for_file(); return core_fsize(m_file); } bool is_writable() { return m_writeable; } @@ -227,10 +230,33 @@ public: const device_config_image_interface &image_config() const { return m_image_config; } void set_init_phase() { m_init_phase = TRUE; } + + const char* longname() { return m_longname; } + const char* manufacturer() { return m_manufacturer; } + const char* year() { return m_year; } + const char* playable() { return m_playable; } + const char* pcb() { return m_pcb; } + const char* extrainfo() { return m_extrainfo; } + + const software_info *software_entry() { return m_software_info_ptr; } + + virtual void set_working_directory(const char *working_directory) { m_working_directory = working_directory; } + virtual const char * working_directory(); + + UINT8 *get_software_region(const char *tag); + UINT32 get_software_region_length(const char *tag); + const char *get_feature(const char *feature_name); + protected: + image_error_t set_image_filename(const char *filename); + void clear_error(); void check_for_file() { assert_always(m_file != NULL, "Illegal operation on unmounted image"); } + + void setup_working_directory(); + bool try_change_working_directory(const char *subdir); + // derived class overrides // configuration @@ -243,6 +269,26 @@ protected: /* variables that are only non-zero when an image is mounted */ core_file *m_file; astring m_name; + astring m_basename; + astring m_basename_noext; + astring m_filetype; + + /* working directory; persists across mounts */ + astring m_working_directory; + + /* Software information */ + char *m_full_software_name; + software_info *m_software_info_ptr; + software_part *m_software_part_ptr; + + /* info read from the hash file/software list */ + astring m_longname; + astring m_manufacturer; + astring m_year; + astring m_playable; + astring m_pcb; + astring m_extrainfo; + /* flags */ bool m_writeable; bool m_created; diff --git a/src/emu/emu.h b/src/emu/emu.h index c5625d6d60c..50ab4d3853a 100644 --- a/src/emu/emu.h +++ b/src/emu/emu.h @@ -99,6 +99,7 @@ #include "state.h" // image-related +#include "softlist.h" #include "image.h" // the running machine diff --git a/src/emu/emu.mak b/src/emu/emu.mak index e96bf33ea71..a6c40b9ccd2 100644 --- a/src/emu/emu.mak +++ b/src/emu/emu.mak @@ -80,6 +80,7 @@ EMUOBJS = \ $(EMUOBJ)/rendutil.o \ $(EMUOBJ)/romload.o \ $(EMUOBJ)/schedule.o \ + $(EMUOBJ)/softlist.o \ $(EMUOBJ)/sound.o \ $(EMUOBJ)/state.o \ $(EMUOBJ)/streams.o \ @@ -87,6 +88,7 @@ EMUOBJS = \ $(EMUOBJ)/timer.o \ $(EMUOBJ)/ui.o \ $(EMUOBJ)/uigfx.o \ + $(EMUOBJ)/uiimage.o \ $(EMUOBJ)/uiinput.o \ $(EMUOBJ)/uimenu.o \ $(EMUOBJ)/validity.o \ diff --git a/src/emu/romload.c b/src/emu/romload.c index 4cbcd2bfbf7..ebf18687066 100644 --- a/src/emu/romload.c +++ b/src/emu/romload.c @@ -1264,7 +1264,6 @@ static UINT32 normalize_flags_for_device(running_machine *machine, UINT32 startf } -#ifdef MESS /*------------------------------------------------- load_software_part_region - load a software part @@ -1343,7 +1342,6 @@ void load_software_part_region(running_device *device, char *swlist, char *swnam /* display the results and exit */ display_rom_load_results(romdata); } -#endif /*------------------------------------------------- diff --git a/src/emu/romload.h b/src/emu/romload.h index 298d0df63f9..e66a0d04c7d 100644 --- a/src/emu/romload.h +++ b/src/emu/romload.h @@ -324,9 +324,6 @@ chd_file *get_disk_handle(running_machine *machine, const char *region); /* set a pointer to the CHD file associated with the given region */ void set_disk_handle(running_machine *machine, const char *region, mame_file *file, chd_file *chd); - -#ifdef MESS void load_software_part_region(running_device *device, char *swlist, char *swname, rom_entry *start_region); -#endif #endif /* __ROMLOAD_H__ */ diff --git a/src/emu/softlist.c b/src/emu/softlist.c new file mode 100644 index 00000000000..9e08e745cff --- /dev/null +++ b/src/emu/softlist.c @@ -0,0 +1,1445 @@ +/*************************************************************************** + + softlist.c + + Software list construction helpers. + + +***************************************************************************/ + +#include "emu.h" +#include "pool.h" +#include "expat.h" +#include "emuopts.h" +#include "softlist.h" + +#include <ctype.h> + +enum softlist_parse_position +{ + POS_ROOT, + POS_MAIN, + POS_SOFT, + POS_PART, + POS_DATA +}; + + +typedef struct _parse_state +{ + XML_Parser parser; + int done; + + void (*error_proc)(const char *message); + void *param; + + enum softlist_parse_position pos; + char **text_dest; +} parse_state; + + +struct software_info_list +{ + software_info info; + struct software_info_list *next; +}; + + +struct _software_list +{ + mame_file *file; + object_pool *pool; + parse_state state; + const char *description; + struct software_info_list *software_info_list; + struct software_info_list *current_software_info; + software_info *softinfo; + const char *look_for; + int part_entries; + int current_part_entry; + int rom_entries; + int current_rom_entry; + void (*error_proc)(const char *message); +}; + + +typedef tagmap_t<software_info *> softlist_map; + +/*************************************************************************** + EXPAT INTERFACES +***************************************************************************/ + +/*------------------------------------------------- + expat_malloc/expat_realloc/expat_free - + wrappers for memory allocation functions so + that they pass through out memory tracking + systems +-------------------------------------------------*/ + +static void *expat_malloc(size_t size) +{ + return global_alloc_array_clear(UINT8,size); +} + +static void *expat_realloc(void *ptr, size_t size) +{ + if (ptr) global_free(ptr); + return global_alloc_array_clear(UINT8,size); +} + +static void expat_free(void *ptr) +{ + global_free(ptr); +} + + +/*------------------------------------------------- + parse_error +-------------------------------------------------*/ + +INLINE void ATTR_PRINTF(2,3) parse_error(parse_state *state, const char *fmt, ...) +{ + char buf[256]; + va_list va; + + if (state->error_proc) + { + va_start(va, fmt); + vsnprintf(buf, ARRAY_LENGTH(buf), fmt, va); + va_end(va); + (*state->error_proc)(buf); + } +} + + +/*------------------------------------------------- + unknown_tag +-------------------------------------------------*/ + +INLINE void unknown_tag(parse_state *state, const char *tagname) +{ + parse_error(state, "[%lu:%lu]: Unknown tag: %s\n", + XML_GetCurrentLineNumber(state->parser), + XML_GetCurrentColumnNumber(state->parser), + tagname); +} + + + +/*------------------------------------------------- + unknown_attribute +-------------------------------------------------*/ + +INLINE void unknown_attribute(parse_state *state, const char *attrname) +{ + parse_error(state, "[%lu:%lu]: Unknown attribute: %s\n", + XML_GetCurrentLineNumber(state->parser), + XML_GetCurrentColumnNumber(state->parser), + attrname); +} + + + +/*------------------------------------------------- + unknown_attribute_value +-------------------------------------------------*/ + +INLINE void unknown_attribute_value(parse_state *state, + const char *attrname, const char *attrvalue) +{ + parse_error(state, "[%lu:%lu]: Unknown attribute value: %s\n", + XML_GetCurrentLineNumber(state->parser), + XML_GetCurrentColumnNumber(state->parser), + attrvalue); +} + + +/*------------------------------------------------- + software_name_split + helper; splits a software_list:software:part + string into seperate software_list, software, + and part strings. + + str1:str2:str3 => swlist_name - str1, swname - str2, swpart - str3 + str1:str2 => swlist_name - NULL, swname - str1, swpart - str2 + str1 => swlist_name - NULL, swname - str1, swpart - NULL + + swlist_namem, swnane and swpart will be global_alloc'ed + from the global pool. So they should be global_free'ed + when they are not used anymore. +-------------------------------------------------*/ +static void software_name_split(running_machine* machine, const char *swlist_swname, char **swlist_name, char **swname, char **swpart ) +{ + const char *split_1st_loc = strchr( swlist_swname, ':' ); + const char *split_2nd_loc = ( split_1st_loc ) ? strchr( split_1st_loc + 1, ':' ) : NULL; + + *swlist_name = NULL; + *swname = NULL; + *swpart = NULL; + + if ( split_1st_loc ) + { + if ( split_2nd_loc ) + { + int size = split_1st_loc - swlist_swname; + *swlist_name = auto_alloc_array_clear(machine,char,size+1); + memcpy( *swlist_name, swlist_swname, size ); + + size = split_2nd_loc - ( split_1st_loc + 1 ); + *swname = auto_alloc_array_clear(machine,char,size+1); + memcpy( *swname, split_1st_loc + 1, size ); + + size = strlen( swlist_swname ) - ( split_2nd_loc + 1 - swlist_swname ); + *swpart = auto_alloc_array_clear(machine,char,size+1); + memcpy( *swpart, split_2nd_loc + 1, size ); + } + else + { + int size = split_1st_loc - swlist_swname; + *swname = auto_alloc_array_clear(machine,char,size+1); + memcpy( *swname, swlist_swname, size ); + + size = strlen( swlist_swname ) - ( split_1st_loc + 1 - swlist_swname ); + *swpart = auto_alloc_array_clear(machine,char,size+1); + memcpy( *swpart, split_1st_loc + 1, size ); + } + } + else + { + *swname = auto_strdup(machine,swlist_swname); + } +} + + +/*------------------------------------------------- + add_rom_entry +-------------------------------------------------*/ + +static void add_rom_entry(software_list *swlist, const char *name, const char *hashdata, UINT32 offset, UINT32 length, UINT32 flags) +{ + software_part *part = &swlist->softinfo->partdata[swlist->current_part_entry-1]; + struct rom_entry *entry = &part->romdata[swlist->current_rom_entry]; + + entry->_name = name; + entry->_hashdata = hashdata; + entry->_offset = offset; + entry->_length = length; + entry->_flags = flags; + + swlist->current_rom_entry += 1; + + if ( swlist->current_rom_entry >= swlist->rom_entries ) + { + struct rom_entry *new_entries; + + swlist->rom_entries += 10; + new_entries = (struct rom_entry *)pool_realloc_lib(swlist->pool, part->romdata, swlist->rom_entries * sizeof(struct rom_entry) ); + + if ( new_entries ) + { + part->romdata = new_entries; + } + else + { + /* Allocation error */ + swlist->current_rom_entry -= 1; + } + } +} + +/*------------------------------------------------- + add_feature +-------------------------------------------------*/ + +static void add_feature(software_list *swlist, char *feature_name, char *feature_value) +{ + software_part *part = &swlist->softinfo->partdata[swlist->current_part_entry-1]; + feature_list *new_entry; + + /* First allocate the new entry */ + new_entry = (feature_list *)pool_malloc_lib(swlist->pool, sizeof(feature_list) ); + + if ( new_entry ) + { + new_entry->next = NULL; + new_entry->name = feature_name; + new_entry->value = feature_value ? feature_value : feature_name; + + /* Add new feature to end of feature list */ + if ( part->featurelist ) + { + feature_list *list = part->featurelist; + while ( list->next != NULL ) + { + list = list->next; + } + list->next = new_entry; + } + else + { + part->featurelist = new_entry; + } + } + else + { + /* Unable to allocate memory */ + } +} + +/*------------------------------------------------- + add_software_part +-------------------------------------------------*/ + +static void add_software_part(software_list *swlist, const char *name, const char *interface) +{ + software_part *part = &swlist->softinfo->partdata[swlist->current_part_entry]; + + part->name = name; + part->interface_ = interface; + part->featurelist = NULL; + part->romdata = NULL; + + swlist->current_part_entry += 1; + + if ( swlist->current_part_entry >= swlist->part_entries ) + { + software_part *new_parts; + + swlist->part_entries += 2; + new_parts = (software_part *)pool_realloc_lib(swlist->pool, swlist->softinfo->partdata, swlist->part_entries * sizeof(software_part) ); + + if ( new_parts ) + { + swlist->softinfo->partdata = new_parts; + } + else + { + /* Allocation error */ + swlist->current_part_entry -= 1; + } + } +} + + +/*------------------------------------------------- + start_handler +-------------------------------------------------*/ + +static void start_handler(void *data, const char *tagname, const char **attributes) +{ + software_list *swlist = (software_list *) data; + char **text_dest; + + switch(swlist->state.pos) + { + case POS_ROOT: + if (!strcmp(tagname, "softwarelist")) + { + for( ; attributes[0]; attributes += 2 ) + { + if ( ! strcmp(attributes[0], "name" ) ) + { + } + if ( ! strcmp(attributes[0], "description" ) ) + { + swlist->description = (const char *)pool_malloc_lib(swlist->pool, (strlen(attributes[1]) + 1) * sizeof(char)); + if (!swlist->description) + return; + + strcpy((char *)swlist->description, attributes[1]); + } + } + } + else + { + unknown_tag(&swlist->state, tagname); + } + break; + + case POS_MAIN: + if ( !strcmp( tagname, "software" ) ) + { + const char *name = NULL; + const char *parent = NULL; + const char *supported = NULL; + + for ( ; attributes[0]; attributes += 2 ) + { + if ( !strcmp( attributes[0], "name" ) ) + { + name = attributes[1]; + } + if ( !strcmp( attributes[0], "cloneof" ) ) + { + parent = attributes[1]; + } + if ( !strcmp( attributes[0], "supported" ) ) + { + supported = attributes[1]; + } + } + + if ( name && !mame_strwildcmp( swlist->look_for, name ) ) + { + struct software_info_list *elem = (struct software_info_list *)pool_malloc_lib(swlist->pool,sizeof(struct software_info_list)); + + if ( !elem ) + return; + + /* Clear element and add element to list */ + memset(elem,0,sizeof(struct software_info_list)); + + /* Allocate space to hold the shortname and copy the short name */ + elem->info.shortname = (const char*)pool_malloc_lib(swlist->pool, ( strlen( name ) + 1 ) * sizeof(char) ); + + if ( ! elem->info.shortname ) + return; + + strcpy( (char *)elem->info.shortname, name ); + + /* Allocate space to hold the parentname and copy the parent name */ + if (parent) + { + elem->info.parentname = (const char*)pool_malloc_lib(swlist->pool, ( strlen(parent) + 1 ) * sizeof(char) ); + strcpy((char *)elem->info.parentname, parent); + } + + /* Allocate initial space to hold part information */ + swlist->part_entries = 2; + swlist->current_part_entry = 0; + elem->info.partdata = (software_part *)pool_malloc_lib(swlist->pool, swlist->part_entries * sizeof(software_part) ); + if ( !elem->info.partdata ) + return; + + /* Handle the supported flag */ + elem->info.supported = SOFTWARE_SUPPORTED_YES; + if ( supported && ! strcmp( supported, "partial" ) ) + elem->info.supported = SOFTWARE_SUPPORTED_PARTIAL; + if ( supported && ! strcmp( supported, "no" ) ) + elem->info.supported = SOFTWARE_SUPPORTED_NO; + + /* Add the entry to the end of the list */ + if ( swlist->software_info_list == NULL ) + { + swlist->software_info_list = elem; + swlist->current_software_info = elem; + } + else + { + swlist->current_software_info->next = elem; + swlist->current_software_info = elem; + } + + /* Quick lookup for setting software information */ + swlist->softinfo = &swlist->current_software_info->info; + } + else + { + swlist->softinfo = NULL; + } + } + else + { + unknown_tag(&swlist->state, tagname); + } + break; + + case POS_SOFT: + text_dest = NULL; + + if (!strcmp(tagname, "description")) + text_dest = (char **) &swlist->softinfo->longname; + else if (!strcmp(tagname, "year")) + text_dest = (char **) &swlist->softinfo->year; + else if (!strcmp(tagname, "publisher")) + text_dest = (char **) &swlist->softinfo->publisher; + else if ( !strcmp(tagname, "part" ) ) + { + const char *str_name = NULL; + const char *str_interface = NULL; + + for ( ; attributes[0]; attributes += 2 ) + { + if ( !strcmp( attributes[0], "name" ) ) + str_name = attributes[1]; + + if ( !strcmp( attributes[0], "interface" ) ) + str_interface = attributes[1]; + } + + if ( str_name && str_interface ) + { + if ( swlist->softinfo ) + { + char *name = (char *)pool_malloc_lib(swlist->pool, ( strlen( str_name ) + 1 ) * sizeof(char) ); + char *interface = (char *)pool_malloc_lib(swlist->pool, ( strlen( str_interface ) + 1 ) * sizeof(char) ); + + if ( !name || !interface ) + return; + + strcpy( name, str_name ); + strcpy( interface, str_interface ); + + add_software_part( swlist, name, interface ); + + /* Allocate initial space to hold the rom information */ + swlist->rom_entries = 3; + swlist->current_rom_entry = 0; + swlist->softinfo->partdata[swlist->current_part_entry-1].romdata = (struct rom_entry *)pool_malloc_lib(swlist->pool, swlist->rom_entries * sizeof(struct rom_entry)); + if ( ! swlist->softinfo->partdata[swlist->current_part_entry-1].romdata ) + return; + } + } + else + { + /* Incomplete/incorrect part definition */ + } + } + else + unknown_tag(&swlist->state, tagname); + + if (text_dest && swlist->softinfo) + swlist->state.text_dest = text_dest; + break; + + case POS_PART: + if (!strcmp(tagname, "dataarea")) + { + const char *str_name = NULL; + const char *str_size = NULL; + + for ( ; attributes[0]; attributes += 2 ) + { + if ( !strcmp( attributes[0], "name" ) ) + str_name = attributes[1]; + + if ( !strcmp( attributes[0], "size") ) + str_size = attributes[1]; + } + if ( str_name && str_size ) + { + if ( swlist->softinfo ) + { + UINT32 length = strtol( str_size, NULL, 10 ); + char *s = (char *)pool_malloc_lib(swlist->pool, ( strlen( str_name ) + 1 ) * sizeof(char) ); + + if ( !s ) + return; + + strcpy( s, str_name ); + + /* ROM_REGION( length, "name", flags ) */ + add_rom_entry( swlist, s, NULL, 0, length, ROMENTRYTYPE_REGION ); + } + } + else + { + /* Missing dataarea name or size */ + } + } + else if ( !strcmp(tagname, "feature") ) + { + const char *str_feature_name = NULL; + const char *str_feature_value = NULL; + + for ( ; attributes[0]; attributes += 2 ) + { + if ( !strcmp( attributes[0], "name" ) ) + str_feature_name = attributes[1]; + + if ( !strcmp( attributes[0], "value" ) ) + str_feature_value = attributes[1]; + } + + /* Prepare for adding feature to feature list */ + if ( str_feature_name && swlist->softinfo ) + { + char *name = (char *)pool_malloc_lib(swlist->pool, ( strlen( str_feature_name ) + 1 ) * sizeof(char) ); + char *value = NULL; + + if ( !name ) + return; + + strcpy( name, str_feature_name ); + + if ( str_feature_value ) + { + value = (char *)pool_malloc_lib(swlist->pool, ( strlen( str_feature_value ) + 1 ) * sizeof(char) ); + + if ( !value ) + return; + + strcpy( value, str_feature_value ); + } + + add_feature( swlist, name, value ); + } + } + else + unknown_tag( &swlist->state, tagname ); + break; + + case POS_DATA: + if (!strcmp(tagname, "rom")) + { + const char *str_name = NULL; + const char *str_size = NULL; + const char *str_crc = NULL; + const char *str_sha1 = NULL; + const char *str_offset = NULL; + const char *str_value = NULL; + const char *str_status = NULL; + const char *str_loadflag = NULL; + + for ( ; attributes[0]; attributes += 2 ) + { + if ( !strcmp( attributes[0], "name" ) ) + str_name = attributes[1]; + if ( !strcmp( attributes[0], "size" ) ) + str_size = attributes[1]; + if ( !strcmp( attributes[0], "crc" ) ) + str_crc = attributes[1]; + if ( !strcmp( attributes[0], "sha1" ) ) + str_sha1 = attributes[1]; + if ( !strcmp( attributes[0], "offset" ) ) + str_offset = attributes[1]; + if ( !strcmp( attributes[0], "value" ) ) + str_value = attributes[1]; + if ( !strcmp( attributes[0], "status" ) ) + str_status = attributes[1]; + if ( !strcmp( attributes[0], "loadflag" ) ) + str_loadflag = attributes[1]; + } + if ( swlist->softinfo ) + { + if ( str_size && str_offset ) + { + UINT32 length = strtol( str_size, NULL, 10 ); + UINT32 offset = strtol( str_offset, NULL, 16 ); + + if ( str_loadflag && !strcmp(str_loadflag, "reload") ) + { + /* Handle 'reload' loadflag */ + add_rom_entry( swlist, NULL, NULL, offset, length, ROMENTRYTYPE_RELOAD | ROM_INHERITFLAGS ); + } + else if ( str_loadflag && !strcmp(str_loadflag, "continue") ) + { + /* Handle 'continue' loadflag */ + add_rom_entry( swlist, NULL, NULL, offset, length, ROMENTRYTYPE_CONTINUE | ROM_INHERITFLAGS ); + } + else if ( str_loadflag && !strcmp(str_loadflag, "fill") ) + { + /* Handle 'fill' loadflag */ + add_rom_entry( swlist, NULL, (const char*)atoi(str_value), offset, length, ROMENTRYTYPE_FILL ); + } + else + { + if ( str_name && str_crc && str_sha1 ) + { + char *s_name = (char *)pool_malloc_lib(swlist->pool, ( strlen( str_name ) + 1 ) * sizeof(char) ); + char *hashdata = (char *)pool_malloc_lib( swlist->pool, sizeof(char) * ( strlen(str_crc) + strlen(str_sha1) + 7 + 4 ) ); + int baddump = ( str_status && !strcmp(str_status, "baddump") ) ? 1 : 0; + int nodump = ( str_status && !strcmp(str_status, "nodump" ) ) ? 1 : 0; + int romflags = 0; + + if ( !s_name || !hashdata ) + return; + + strcpy( s_name, str_name ); + sprintf( hashdata, "c:%s#s:%s#%s", str_crc, str_sha1, ( nodump ? NO_DUMP : ( baddump ? BAD_DUMP : "" ) ) ); + + /* Handle loadflag attribute */ + if ( str_loadflag && !strcmp(str_loadflag, "load16_word_swap") ) + romflags = ROM_GROUPWORD | ROM_REVERSE; + else if ( str_loadflag && !strcmp(str_loadflag, "load16_byte") ) + romflags = ROM_SKIP(1); + else if ( str_loadflag && !strcmp(str_loadflag, "load32_word_swap") ) + romflags = ROM_GROUPWORD | ROM_REVERSE | ROM_SKIP(2); + else if ( str_loadflag && !strcmp(str_loadflag, "load32_word") ) + romflags = ROM_GROUPWORD | ROM_SKIP(2); + + /* ROM_LOAD( name, offset, length, hash ) */ + add_rom_entry( swlist, s_name, hashdata, offset, length, ROMENTRYTYPE_ROM | romflags ); + } + } + } + } + else + { + /* Missing name, size, crc, sha1, or offset */ + } + } + else + unknown_tag(&swlist->state, tagname); + break; + } + swlist->state.pos = (softlist_parse_position) (swlist->state.pos + 1); +} + +/*------------------------------------------------- + end_handler +-------------------------------------------------*/ + +static void end_handler(void *data, const char *name) +{ + software_list *swlist = (software_list *) data; + swlist->state.text_dest = NULL; + + swlist->state.pos = (softlist_parse_position) (swlist->state.pos - 1); + switch(swlist->state.pos) + { + case POS_ROOT: + break; + + case POS_SOFT: + if ( ! strcmp( name, "part" ) && swlist->softinfo ) + { + /* ROM_END */ + add_rom_entry( swlist, NULL, NULL, 0, 0, ROMENTRYTYPE_END ); + } + break; + + case POS_MAIN: + if ( swlist->softinfo ) + { + add_software_part( swlist, NULL, NULL ); + } + break; + + case POS_PART: + break; + + case POS_DATA: + break; + } +} + + +/*------------------------------------------------- + data_handler +-------------------------------------------------*/ + +static void data_handler(void *data, const XML_Char *s, int len) +{ + software_list *swlist = (software_list *) data; + int text_len; + char *text; + + if (swlist->state.text_dest) + { + text = *swlist->state.text_dest; + + text_len = text ? strlen(text) : 0; + text = (char*)pool_realloc_lib(swlist->pool, text, text_len + len + 1); + if (!text) + return; + + memcpy(&text[text_len], s, len); + text[text_len + len] = '\0'; + *swlist->state.text_dest = text; + } +} + + +/*------------------------------------------------- + software_list_parse +-------------------------------------------------*/ + +static void software_list_parse(software_list *swlist, + void (*error_proc)(const char *message), + void *param) +{ + char buf[1024]; + UINT32 len; + XML_Memory_Handling_Suite memcallbacks; + + mame_fseek(swlist->file, 0, SEEK_SET); + + memset(&swlist->state, 0, sizeof(swlist->state)); + swlist->state.error_proc = error_proc; + swlist->state.param = param; + + /* create the XML parser */ + memcallbacks.malloc_fcn = expat_malloc; + memcallbacks.realloc_fcn = expat_realloc; + memcallbacks.free_fcn = expat_free; + swlist->state.parser = XML_ParserCreate_MM(NULL, &memcallbacks, NULL); + if (!swlist->state.parser) + goto done; + + XML_SetUserData(swlist->state.parser, swlist); + XML_SetElementHandler(swlist->state.parser, start_handler, end_handler); + XML_SetCharacterDataHandler(swlist->state.parser, data_handler); + + while(!swlist->state.done) + { + len = mame_fread(swlist->file, buf, sizeof(buf)); + swlist->state.done = mame_feof(swlist->file); + if (XML_Parse(swlist->state.parser, buf, len, swlist->state.done) == XML_STATUS_ERROR) + { + parse_error(&swlist->state, "[%lu:%lu]: %s\n", + XML_GetCurrentLineNumber(swlist->state.parser), + XML_GetCurrentColumnNumber(swlist->state.parser), + XML_ErrorString(XML_GetErrorCode(swlist->state.parser))); + goto done; + } + } + +done: + if (swlist->state.parser) + XML_ParserFree(swlist->state.parser); + swlist->state.parser = NULL; + swlist->current_software_info = swlist->software_info_list; +} + + +/*------------------------------------------------- + software_list_open +-------------------------------------------------*/ + +software_list *software_list_open(core_options *options, const char *listname, int is_preload, + void (*error_proc)(const char *message)) +{ + file_error filerr; + astring *fname; + software_list *swlist = NULL; + object_pool *pool = NULL; + + /* create a pool for this software list file */ + pool = pool_alloc_lib(error_proc); + if (!pool) + goto error; + + /* allocate space for this software list file */ + swlist = (software_list *) pool_malloc_lib(pool, sizeof(*swlist)); + if (!swlist) + goto error; + + /* set up the software_list structure */ + memset(swlist, 0, sizeof(*swlist)); + swlist->pool = pool; + swlist->error_proc = error_proc; + + /* open a file */ + fname = astring_assemble_2(astring_alloc(), listname, ".xml"); + filerr = mame_fopen_options(options, SEARCHPATH_HASH, astring_c(fname), OPEN_FLAG_READ, &swlist->file); + astring_free(fname); + + if (filerr != FILERR_NONE) + goto error; + +// if (is_preload) +// software_list_parse(swlist, swlist->error_proc, NULL); + + return swlist; + +error: + if (swlist != NULL) + software_list_close(swlist); + return NULL; +} + + +/*------------------------------------------------- + software_list_close +-------------------------------------------------*/ + +void software_list_close(software_list *swlist) +{ + if (swlist == NULL) + return; + + if (swlist->file) + mame_fclose(swlist->file); + pool_free_lib(swlist->pool); +} + + +/*------------------------------------------------- + software_list_find +-------------------------------------------------*/ + +software_info *software_list_find(software_list *swlist, const char *software) +{ + if (swlist == NULL) + return NULL; + + swlist->look_for = software; + software_list_parse( swlist, swlist->error_proc, NULL ); + + return swlist->current_software_info ? &swlist->current_software_info->info : NULL; +} + + +/*------------------------------------------------- + software_list_first +-------------------------------------------------*/ + +software_info *software_list_first(software_list *swlist) +{ + return software_list_find(swlist, "*"); +} + + +/*------------------------------------------------- + software_list_next +-------------------------------------------------*/ + +software_info *software_list_next(software_list *swlist) +{ + if ( swlist->current_software_info ) + { + swlist->current_software_info = swlist->current_software_info->next; + } + return swlist->current_software_info ? &swlist->current_software_info->info : NULL; +} + + +/*------------------------------------------------- + software_find_part +-------------------------------------------------*/ + +software_part *software_find_part(software_info *sw, const char *partname, const char *interface) +{ + software_part *part = sw ? sw->partdata : NULL; + + /* If neither partname nor interface supplied, then we just return the first entry */ + if ( partname || interface ) + { + while( part && part->name ) + { + if ( partname ) + { + if ( !strcmp(partname, part->name ) ) + { + if ( interface ) + { + if ( !strcmp(interface, part->interface_) ) + { + break; + } + } + else + { + break; + } + } + } + else + { + /* No specific partname supplied, find the first match based on interface */ + if ( interface ) + { + if ( !strcmp(interface, part->interface_) ) + { + break; + } + } + } + part++; + } + } + + if ( ! part->name ) + part = NULL; + + return part; +} + + +/*------------------------------------------------- + software_part_next +-------------------------------------------------*/ + +software_part *software_part_next(software_part *part) +{ + if ( part && part->name ) + { + part++; + } + + if ( ! part->name ) + part = NULL; + + return part; +} + + +/*------------------------------------------------- + load_software_part + + Load a software part for a device. The part to + load is determined by the "path", software lists + configured for a driver, and the interface + supported by the device. + + returns true if the software could be loaded, + false otherwise. If the software could be loaded + sw_info and sw_part are also set. +-------------------------------------------------*/ + +bool load_software_part(device_image_interface *image, const char *path, software_info **sw_info, software_part **sw_part, char **full_sw_name) +{ + char *swlist_name, *swname, *swpart; + bool result = false; + software_list *software_list_ptr = NULL; + software_info *software_info_ptr = NULL; + software_part *software_part_ptr = NULL; + + *sw_info = NULL; + *sw_part = NULL; + + /* Split full software name into software list name and short software name */ + software_name_split( image->device().machine, path, &swlist_name, &swname, &swpart ); + + const char *interface = image->image_config().image_interface(); + + if ( swlist_name ) + { + /* Try to open the software list xml file explicitly named by the user */ + software_list_ptr = software_list_open( mame_options(), swlist_name, FALSE, NULL ); + + if ( software_list_ptr ) + { + software_info_ptr = software_list_find( software_list_ptr, swname ); + + if ( software_info_ptr ) + { + software_part_ptr = software_find_part( software_info_ptr, swpart, interface ); + } + } + } + else + { + /* Loop through all the software lists named in the driver */ + running_device *swlists = devtag_get_device( image->device().machine, __SOFTWARE_LIST_TAG ); + + if ( swlists ) + { + software_list_config *swlist = (software_list_config *)downcast<const legacy_device_config_base *>(&image->device().baseconfig())->inline_config(); + + for ( int i = 0; i < DEVINFO_STR_SWLIST_MAX - DEVINFO_STR_SWLIST_0; i++ ) + { + swlist_name = swlist->list_name[i]; + + if ( swlist_name && *swlist_name ) + { + if ( software_list_ptr ) + { + software_list_close( software_list_ptr ); + } + + software_list_ptr = software_list_open( mame_options(), swlist_name, FALSE, NULL ); + + if ( software_list_ptr ) + { + software_info_ptr = software_list_find( software_list_ptr, swname ); + + if ( software_info_ptr ) + { + software_part_ptr = software_find_part( software_info_ptr, swpart, interface ); + } + } + } + } + } + + /* If not found try to load the software list using the driver name */ + if ( ! software_part_ptr ) + { + swlist_name = (char *)image->device().machine->gamedrv->name; + + if ( software_list_ptr ) + { + software_list_close( software_list_ptr ); + } + + software_list_ptr = software_list_open( mame_options(), swlist_name, FALSE, NULL ); + + if ( software_list_ptr ) + { + software_info_ptr = software_list_find( software_list_ptr, swname ); + + if ( software_info_ptr ) + { + software_part_ptr = software_find_part( software_info_ptr, swpart, interface ); + } + } + } + + /* If not found try to load the software list using the software name as software */ + /* list name and software part name as software name. */ + if ( ! software_part_ptr ) + { + swlist_name = swname; + swname = swpart; + swpart = NULL; + + if ( software_list_ptr ) + { + software_list_close( software_list_ptr ); + } + + software_list_ptr = software_list_open( mame_options(), swlist_name, FALSE, NULL ); + + if ( software_list_ptr ) + { + software_info_ptr = software_list_find( software_list_ptr, swname ); + + if ( software_info_ptr ) + { + software_part_ptr = software_find_part( software_info_ptr, swpart, interface ); + } + + if ( ! software_part_ptr ) + { + software_list_close( software_list_ptr ); + software_list_ptr = NULL; + } + } + } + } + + if ( software_part_ptr ) + { + /* Load the software part */ + try { + load_software_part_region( &image->device(), (char *)swlist_name, (char *)software_info_ptr->shortname, software_part_ptr->romdata ); + } + catch (emu_fatalerror &fatal) + { + software_list_close( software_list_ptr ); + throw fatal; + } + + /* Create a copy of the software and part information */ + *sw_info = auto_alloc_clear( image->device().machine, software_info ); + (*sw_info)->shortname = auto_strdup( image->device().machine, software_info_ptr->shortname ); + (*sw_info)->longname = auto_strdup( image->device().machine, software_info_ptr->longname ); + if ( software_info_ptr->year ) + (*sw_info)->year = auto_strdup( image->device().machine, software_info_ptr->year ); + if ( software_info_ptr->publisher ) + (*sw_info)->publisher = auto_strdup( image->device().machine, software_info_ptr->publisher ); + + *sw_part = auto_alloc_clear( image->device().machine, software_part ); + (*sw_part)->name = auto_strdup( image->device().machine, software_part_ptr->name ); + if ( software_part_ptr->interface_ ) + (*sw_part)->interface_ = auto_strdup( image->device().machine, software_part_ptr->interface_ ); + + if ( software_part_ptr->featurelist ) + { + feature_list *list = software_part_ptr->featurelist; + feature_list *new_list = auto_alloc_clear( image->device().machine, feature_list ); + + (*sw_part)->featurelist = new_list; + + new_list->name = auto_strdup( image->device().machine, list->name ); + new_list->value = auto_strdup( image->device().machine, list->value ); + + list = list->next; + + while( list ) + { + new_list->next = auto_alloc_clear( image->device().machine, feature_list ); + new_list = new_list->next; + new_list->name = auto_strdup( image->device().machine, list->name ); + new_list->value = auto_strdup( image->device().machine, list->value ); + + list = list->next; + } + + new_list->next = NULL; + } + + /* Tell the world which part we actually loaded */ + *full_sw_name = auto_alloc_array( image->device().machine, char, strlen(swlist_name) + strlen(software_info_ptr->shortname) + strlen(software_part_ptr->name) + 3 ); + sprintf( *full_sw_name, "%s:%s:%s", swlist_name, software_info_ptr->shortname, software_part_ptr->name ); + + result = true; + } + + /* Close the software list if it's still open */ + if ( software_list_ptr ) + { + software_list_close( software_list_ptr ); + software_info_ptr = NULL; + software_list_ptr = NULL; + } + auto_free( image->device().machine, swlist_name ); + auto_free( image->device().machine, swname ); + auto_free( image->device().machine, swpart ); + + return result; +} + + +/*************************************************************************** + DEVICE INTERFACE +***************************************************************************/ + + +static DEVICE_START( software_list ) +{ +} + +static DEVICE_VALIDITY_CHECK( software_list ) +{ + software_list_config *swlist = (software_list_config *)downcast<const legacy_device_config_base *>(device)->inline_config(); + int error = FALSE; + softlist_map names; + softlist_map descriptions; + + enum { NAME_LEN_PARENT = 8, NAME_LEN_CLONE = 16 }; + + for (int i = 0; i < DEVINFO_STR_SWLIST_MAX - DEVINFO_STR_SWLIST_0; i++) + { + if (swlist->list_name[i]) + { + if (mame_options() == NULL) + return FALSE; + + software_list *list = software_list_open(mame_options(), swlist->list_name[i], FALSE, NULL); + + /* if no .xml list is found, then return (this happens e.g. if you moved/renamed the xml list) */ + if (list == NULL) + return FALSE; + + for (software_info *swinfo = software_list_first(list); swinfo != NULL; swinfo = software_list_next(list)) + { + const char *s; + int is_clone = 0; + + /* First, check if the xml got corrupted: */ + + /* Did we lost any description? */ + if (swinfo->longname == NULL) + { + mame_printf_error("%s: %s has no description\n", swlist->list_name[i], swinfo->shortname); + return TRUE; + } + + /* Did we lost any year? */ + if (swinfo->year == NULL) + { + mame_printf_error("%s: %s has no year\n", swlist->list_name[i], swinfo->shortname); + return TRUE; + } + + /* Did we lost any publisher? */ + if (swinfo->publisher == NULL) + { + mame_printf_error("%s: %s has no publisher\n", swlist->list_name[i], swinfo->shortname); + return TRUE; + } + + /* Second, since the xml is fine, run additional checks: */ + + /* check for duplicate names */ + if (names.add(swinfo->shortname, swinfo, FALSE) == TMERR_DUPLICATE) + { + software_info *match = names.find(swinfo->shortname); + mame_printf_error("%s: %s is a duplicate name (%s)\n", swlist->list_name[i], swinfo->shortname, match->shortname); + error = TRUE; + } + + /* check for duplicate descriptions */ + if (descriptions.add(swinfo->longname, swinfo, FALSE) == TMERR_DUPLICATE) + { + software_info *match = names.find(swinfo->shortname); + mame_printf_error("%s: %s is a duplicate description (%s)\n", swlist->list_name[i], swinfo->longname, match->longname); + error = TRUE; + } + + if (swinfo->parentname != NULL) + is_clone = 1; + + /* make sure the driver name is 8 chars or less */ + if ((is_clone && strlen(swinfo->shortname) > NAME_LEN_CLONE) || ((!is_clone) && strlen(swinfo->shortname) > NAME_LEN_PARENT)) + { + mame_printf_error("%s: %s %s driver name must be %d characters or less\n", swlist->list_name[i], swinfo->shortname, + is_clone ? "clone" : "parent", is_clone ? NAME_LEN_CLONE : NAME_LEN_PARENT); + error = TRUE; + } + + /* make sure the year is only digits, '?' or '+' */ + for (s = swinfo->year; *s; s++) + if (!isdigit((UINT8)*s) && *s != '?' && *s != '+') + { + mame_printf_error("%s: %s has an invalid year '%s'\n", swlist->list_name[i], swinfo->shortname, swinfo->year); + error = TRUE; + break; + } + + // TODO: shall we verify that all parts have some dataarea? and what about checking that a shortname is really present? + } + + software_list_close(list); + } + } + return error; +} + +DEVICE_GET_INFO( software_list ) +{ + switch (state) + { + /* --- the following bits of info are returned as 64-bit signed integers --- */ + case DEVINFO_INT_TOKEN_BYTES: info->i = 1; break; + case DEVINFO_INT_INLINE_CONFIG_BYTES: info->i = sizeof(software_list_config); break; + + /* --- the following bits of info are returned as pointers to data or functions --- */ + case DEVINFO_FCT_START: info->start = DEVICE_START_NAME( software_list ); break; + case DEVINFO_FCT_STOP: /* Nothing */ break; + case DEVINFO_FCT_VALIDITY_CHECK: info->p = (void*)DEVICE_VALIDITY_CHECK_NAME( software_list ); break; + + /* --- the following bits of info are returned as NULL-terminated strings --- */ + case DEVINFO_STR_NAME: strcpy(info->s, "Software lists"); break; + case DEVINFO_STR_FAMILY: strcpy(info->s, "Software lists"); break; + case DEVINFO_STR_VERSION: strcpy(info->s, "1.0"); break; + case DEVINFO_STR_SOURCE_FILE: strcpy(info->s, __FILE__); break; + case DEVINFO_STR_CREDITS: strcpy(info->s, "Copyright MESS Team"); break; + } + + if ( state >= DEVINFO_STR_SWLIST_0 && state <= DEVINFO_STR_SWLIST_MAX ) + { + software_list_config *config = (software_list_config *)downcast<const legacy_device_config_base *>(device)->inline_config(); + + if ( config->list_name[ state - DEVINFO_STR_SWLIST_0 ] ) + strcpy(info->s, config->list_name[ state - DEVINFO_STR_SWLIST_0 ]); + } +} + + +/*************************************************************************** + MENU SUPPORT +***************************************************************************/ + +/* state of the software menu */ +typedef struct _software_menu_state software_menu_state; +struct _software_menu_state +{ + char *list_name; /* currently selected list */ +}; + +/* state of a software entry */ +typedef struct _software_entry_state software_entry_state; +struct _software_entry_state +{ + const char *short_name; + const char *interface; +}; + + +/* populate a specific list */ +static void ui_mess_menu_populate_software_entries(running_machine *machine, ui_menu *menu, char *list_name) +{ + software_list *list = software_list_open(mame_options(), list_name, FALSE, NULL); + + if (list) + { + for (software_info *swinfo = software_list_first(list); swinfo != NULL; swinfo = software_list_next(list)) + { + software_entry_state *entry = (software_entry_state *) ui_menu_pool_alloc(menu, sizeof(*entry)); + entry->short_name = ui_menu_pool_strdup(menu, swinfo->shortname); + + software_part *part = software_find_part(swinfo, NULL, NULL); + entry->interface = ui_menu_pool_strdup(menu, part->interface_); + + ui_menu_item_append(menu, swinfo->shortname, swinfo->longname, 0, entry); + } + + software_list_close(list); + } +} + +void ui_mess_menu_software_list(running_machine *machine, ui_menu *menu, void *parameter, void *state) +{ + const ui_menu_event *event; + software_menu_state *sw_state = (software_menu_state *)state; + + if (!ui_menu_populated(menu)) + ui_mess_menu_populate_software_entries(machine, menu, sw_state->list_name); + + /* process the menu */ + event = ui_menu_process(machine, menu, 0); + + if (event != NULL && event->iptkey == IPT_UI_SELECT && event->itemref != NULL) + { + device_image_interface *image = NULL; + device_image_interface *sel_image = NULL; + software_entry_state *entry = (software_entry_state *) event->itemref; + + /* search for a device with the right interface */ + for (bool gotone = machine->devicelist.first(image); gotone; gotone = image->next(image)) + { + const char *interface = image->image_config().image_interface(); + + if (interface != NULL) + { + if (!strcmp(interface, entry->interface)) + { + sel_image = image; + break; + } + } + } + + if (sel_image != NULL) + sel_image->load(entry->short_name); + else + popmessage("No matching device found for interface '%s'!", entry->interface); + } +} + +/* list of available software lists - i.e. cartridges, floppies */ +static void ui_mess_menu_populate_software_list(running_machine *machine, ui_menu *menu) +{ + for (const device_config *dev = machine->config->devicelist.first(); dev != NULL; dev = dev->next()) + { + if (!strcmp(dev->tag(), __SOFTWARE_LIST_TAG)) + { + software_list_config *swlist = (software_list_config *)downcast<const legacy_device_config_base *>(dev)->inline_config(); + + for (int i = 0; i < DEVINFO_STR_SWLIST_MAX - DEVINFO_STR_SWLIST_0; i++) + { + if (swlist->list_name[i]) + { + software_list *list = software_list_open(mame_options(), swlist->list_name[i], FALSE, NULL); + + if (list) + { + /* todo: fix this */ + for (software_info *swinfo = software_list_first(list); swinfo != NULL; swinfo = software_list_next(list)) + { + } + + ui_menu_item_append(menu, list->description, NULL, 0, swlist->list_name[i]); + + software_list_close(list); + } + } + } + } + } +} + +void ui_image_menu_software(running_machine *machine, ui_menu *menu, void *parameter, void *state) +{ + const ui_menu_event *event; + + if (!ui_menu_populated(menu)) + ui_mess_menu_populate_software_list(machine, menu); + + /* process the menu */ + event = ui_menu_process(machine, menu, 0); + + if (event != NULL && event->iptkey == IPT_UI_SELECT) + { + ui_menu *child_menu = ui_menu_alloc(machine, render_container_get_ui(), ui_mess_menu_software_list, NULL); + software_menu_state *child_menustate = (software_menu_state *)ui_menu_alloc_state(child_menu, sizeof(*child_menustate), NULL); + child_menustate->list_name = (char *)event->itemref; + ui_menu_stack_push(child_menu); + } +} + +DEFINE_LEGACY_DEVICE(SOFTWARE_LIST, software_list);
\ No newline at end of file diff --git a/src/emu/softlist.h b/src/emu/softlist.h new file mode 100644 index 00000000000..2fa52347c9e --- /dev/null +++ b/src/emu/softlist.h @@ -0,0 +1,113 @@ +/********************************************************************* + + softlist.h + + Software and software list information. + +*********************************************************************/ + +#ifndef __SOFTLIST_H_ +#define __SOFTLIST_H_ + +#include "uimenu.h" + + +/********************************************************************* + + Internal structures and XML file handling + +*********************************************************************/ + +/* Replace this with list<string>? */ +struct feature_list +{ + feature_list *next; + char *name; + char *value; +}; + +struct software_part +{ + const char *name; + const char *interface_; + feature_list *featurelist; + struct rom_entry *romdata; +}; + + +/* The software info struct holds basic software information. Additional, + optional information like local software names, release dates, serial + numbers, etc can be maintained and stored in external recources. +*/ +struct software_info +{ + const char *shortname; + const char *longname; + const char *parentname; + const char *year; /* Copyright year on title screen, actual release dates can be tracked in external resources */ + const char *publisher; + UINT32 supported; + software_part *partdata; +}; + + +typedef struct _software_list software_list; + +/* Handling a software list */ +software_list *software_list_open(core_options *options, const char *listname, int is_preload, void (*error_proc)(const char *message)); +void software_list_close(software_list *swlist); +software_info *software_list_first(software_list *swlist); +software_info *software_list_find(software_list *swlist, const char *software); +software_info *software_list_next(software_list *swlist); + +software_part *software_find_part(software_info *sw, const char *partname, const char *interface_); +software_part *software_part_next(software_part *part); + + +bool load_software_part(device_image_interface *image, const char *path, software_info **sw_info, software_part **sw_part, char **full_sw_name); + +void ui_image_menu_software(running_machine *machine, ui_menu *menu, void *parameter, void *state); + + +/********************************************************************* + + Driver software list configuration + +*********************************************************************/ +DECLARE_LEGACY_DEVICE(SOFTWARE_LIST, software_list); +#define __SOFTWARE_LIST_TAG "software_list" + + +#define SOFTWARE_SUPPORTED_YES 0 +#define SOFTWARE_SUPPORTED_PARTIAL 1 +#define SOFTWARE_SUPPORTED_NO 2 + + +#define SOFTWARE_LIST_CONFIG_SIZE 10 + + +typedef struct _software_list_config software_list_config; +struct _software_list_config +{ + char *list_name[SOFTWARE_LIST_CONFIG_SIZE]; +}; + + +#define DEVINFO_STR_SWLIST_0 (DEVINFO_STR_DEVICE_SPECIFIC+0) +#define DEVINFO_STR_SWLIST_MAX (DEVINFO_STR_SWLIST_0 + SOFTWARE_LIST_CONFIG_SIZE - 1) + + +#define MDRV_SOFTWARE_LIST_CONFIG(_idx,_list) \ + MDRV_DEVICE_CONFIG_DATAPTR_ARRAY(software_list_config, list_name, _idx, _list) + +#define MDRV_SOFTWARE_LIST_ADD( _list ) \ + MDRV_DEVICE_ADD( __SOFTWARE_LIST_TAG, SOFTWARE_LIST, 0 ) \ + MDRV_SOFTWARE_LIST_CONFIG(0,_list) + + +#define MDRV_SOFTWARE_LIST_MODIFY( _list ) \ + MDRV_DEVICE_MODIFY( __SOFTWARE_LIST_TAG ) \ + MDRV_SOFTWARE_LIST_CONFIG(0,_list) + + +#endif diff --git a/src/emu/ui.c b/src/emu/ui.c index 4a4361d791c..043b75f1083 100644 --- a/src/emu/ui.c +++ b/src/emu/ui.c @@ -21,11 +21,6 @@ #include "uiinput.h" #include "uimenu.h" #include "uigfx.h" - -#ifdef MESS -#include "uimess.h" -#endif /* MESS */ - #include <ctype.h> @@ -1266,6 +1261,26 @@ void ui_paste(running_machine *machine) } /*------------------------------------------------- + ui_image_handler_ingame - execute display + callback function for each image device +-------------------------------------------------*/ + +void ui_image_handler_ingame(running_machine *machine) +{ + device_image_interface *image = NULL; + + /* run display routine for devices */ + if (mame_get_phase(machine) == MAME_PHASE_RUNNING) + { + for (bool gotone = machine->devicelist.first(image); gotone; gotone = image->next(image)) + { + image->display(); + } + } + +} + +/*------------------------------------------------- handler_ingame - in-game handler takes care of the standard keypresses -------------------------------------------------*/ @@ -1345,9 +1360,7 @@ static UINT32 handler_ingame(running_machine *machine, render_container *contain ui_paste(machine); } -#ifdef MESS - ui_mess_handler_ingame(machine); -#endif /* MESS */ + ui_image_handler_ingame(machine); if (ui_disabled) return ui_disabled; diff --git a/src/emu/uiimage.c b/src/emu/uiimage.c new file mode 100644 index 00000000000..76d2e7884e3 --- /dev/null +++ b/src/emu/uiimage.c @@ -0,0 +1,1130 @@ +/********************************************************************* + + filemngr.c + + MESS's clunky built-in file manager + + TODO + - Support image creation arguments + - Restrict directory listing by file extension + - Support file manager invocation from the main menu for + required images + - Restrict empty slot if image required + +*********************************************************************/ + +#include <stdio.h> +#include <ctype.h> +#include <stdlib.h> + +#include "emu.h" +#include "image.h" +#include "ui.h" +#include "uimenu.h" +#include "zippath.h" +#include "unicode.h" + + + +/*************************************************************************** + CONSTANTS +***************************************************************************/ + +/* conditional compilation to enable chosing of image formats - this is not + * yet fully implemented */ +#define ENABLE_FORMATS 0 + +/* time (in seconds) to display errors */ +#define ERROR_MESSAGE_TIME 5 + +/* itemrefs for key menu items */ +#define ITEMREF_NEW_IMAGE_NAME ((void *) 0x0001) +#define ITEMREF_CREATE ((void *) 0x0002) +#define ITEMREF_FORMAT ((void *) 0x0003) +#define ITEMREF_NO ((void *) 0x0004) +#define ITEMREF_YES ((void *) 0x0005) + + + +/*************************************************************************** + TYPE DEFINITIONS +***************************************************************************/ + +/* menu item type in the file selector */ +enum _file_selector_entry_type +{ + SELECTOR_ENTRY_TYPE_EMPTY, + SELECTOR_ENTRY_TYPE_CREATE, + SELECTOR_ENTRY_TYPE_DRIVE, + SELECTOR_ENTRY_TYPE_DIRECTORY, + SELECTOR_ENTRY_TYPE_FILE +}; +typedef enum _file_selector_entry_type file_selector_entry_type; + + + +/* an entry within the file manager */ +typedef struct _file_selector_entry file_selector_entry; +struct _file_selector_entry +{ + file_selector_entry *next; + + file_selector_entry_type type; + const char *basename; + const char *fullpath; +}; + + + +/* state of the file manager */ +typedef struct _file_manager_menu_state file_manager_menu_state; +struct _file_manager_menu_state +{ + device_image_interface *selected_device; + astring *current_directory; + astring *current_file; +}; + + + +/* state of the file selector menu */ +typedef struct _file_selector_menu_state file_selector_menu_state; +struct _file_selector_menu_state +{ + file_manager_menu_state *manager_menustate; + file_selector_entry *entrylist; +}; + + + +/* state of the file creator menu */ +typedef struct _file_create_menu_state file_create_menu_state; +struct _file_create_menu_state +{ + file_manager_menu_state *manager_menustate; + const image_device_format *current_format; + int confirm_save_as_yes; + char filename_buffer[1024]; +}; + + +/* state of the confirm save as menu */ +typedef struct _confirm_save_as_menu_state confirm_save_as_menu_state; +struct _confirm_save_as_menu_state +{ + int *yes; +}; + +char *stripspace(const char *src) +{ + static char buff[512]; + if( src ) + { + char *dst; + while( *src && isspace(*src) ) + src++; + strcpy(buff, src); + dst = buff + strlen(buff); + while( dst >= buff && isspace(*--dst) ) + *dst = '\0'; + return buff; + } + return NULL; +} + +//============================================================ +// strip_extension +//============================================================ + +char *strip_extension(const char *filename) +{ + char *newname; + char *c; + + // NULL begets NULL + if (!filename) + return NULL; + + // allocate space for it + newname = (char *) malloc(strlen(filename) + 1); + if (!newname) + return NULL; + + // copy in the name + strcpy(newname, filename); + + // search backward for a period, failing if we hit a slash or a colon + for (c = newname + strlen(newname) - 1; c >= newname; c--) + { + // if we hit a period, NULL terminate and break + if (*c == '.') + { + *c = 0; + break; + } + + // if we hit a slash or colon just stop + if (*c == '\\' || *c == '/' || *c == ':') + break; + } + + return newname; +} + + +/*************************************************************************** + MENU HELPERS +***************************************************************************/ + +/*------------------------------------------------- + input_character - inputs a typed character + into a buffer +-------------------------------------------------*/ + +static void input_character(char *buffer, size_t buffer_length, unicode_char unichar, int (*filter)(unicode_char)) +{ + size_t buflen = strlen(buffer); + + if ((unichar == 8) && (buflen > 0)) + { + *(char *)utf8_previous_char(&buffer[buflen]) = 0; + } + else if ((unichar > ' ') && ((filter == NULL) || (*filter)(unichar))) + { + buflen += utf8_from_uchar(&buffer[buflen], buffer_length - buflen, unichar); + buffer[buflen] = 0; + } +} + + + +/*------------------------------------------------- + extra_text_draw_box - generically adds header + or footer text +-------------------------------------------------*/ + +static void extra_text_draw_box(float origx1, float origx2, float origy, float yspan, const char *text, int direction) +{ + float text_width, text_height; + float width, maxwidth; + float x1, y1, x2, y2, temp; + + /* get the size of the text */ + ui_draw_text_full( render_container_get_ui(),text, 0.0f, 0.0f, 1.0f, JUSTIFY_LEFT, WRAP_WORD, + DRAW_NONE, ARGB_WHITE, ARGB_BLACK, &text_width, &text_height); + width = text_width + (2 * UI_BOX_LR_BORDER); + maxwidth = MAX(width, origx2 - origx1); + + /* compute our bounds */ + x1 = 0.5f - 0.5f * maxwidth; + x2 = x1 + maxwidth; + y1 = origy + (yspan * direction); + y2 = origy + (UI_BOX_TB_BORDER * direction); + + if (y1 > y2) + { + temp = y1; + y1 = y2; + y2 = temp; + } + + /* draw a box */ + ui_draw_outlined_box(render_container_get_ui(),x1, y1, x2, y2, UI_BACKGROUND_COLOR); + + /* take off the borders */ + x1 += UI_BOX_LR_BORDER; + x2 -= UI_BOX_LR_BORDER; + y1 += UI_BOX_TB_BORDER; + y2 -= UI_BOX_TB_BORDER; + + /* draw the text within it */ + ui_draw_text_full(render_container_get_ui(),text, x1, y1, text_width, JUSTIFY_LEFT, WRAP_WORD, + DRAW_NORMAL, ARGB_WHITE, ARGB_BLACK, NULL, NULL); +} + + + +/*------------------------------------------------- + extra_text_render - generically adds header + and footer text +-------------------------------------------------*/ + +static void extra_text_render(running_machine *machine, ui_menu *menu, void *state, void *selectedref, float top, float bottom, + float origx1, float origy1, float origx2, float origy2, + const char *header, const char *footer) +{ + header = ((header != NULL) && (header[0] != '\0')) ? header : NULL; + footer = ((footer != NULL) && (footer[0] != '\0')) ? footer : NULL; + + if (header != NULL) + extra_text_draw_box(origx1, origx2, origy1, top, header, -1); + if (footer != NULL) + extra_text_draw_box(origx1, origx2, origy2, bottom, footer, +1); +} + + + +/*************************************************************************** + CONFIRM SAVE AS MENU +***************************************************************************/ + +/*------------------------------------------------- + menu_confirm_save_as_populate - populates the + confirm save as menu +-------------------------------------------------*/ + +static void menu_confirm_save_as_populate(running_machine *machine, ui_menu *menu, void *state) +{ + ui_menu_item_append(menu, "File Already Exists - Overide?", NULL, MENU_FLAG_DISABLE, NULL); + ui_menu_item_append(menu, MENU_SEPARATOR_ITEM, NULL, MENU_FLAG_DISABLE, NULL); + ui_menu_item_append(menu, "No", NULL, 0, ITEMREF_NO); + ui_menu_item_append(menu, "Yes", NULL, 0, ITEMREF_YES); +} + + + +/*------------------------------------------------- + menu_confirm_save_as - confirm save as menu +-------------------------------------------------*/ + +static void menu_confirm_save_as(running_machine *machine, ui_menu *menu, void *parameter, void *state) +{ + const ui_menu_event *event; + confirm_save_as_menu_state *menustate = (confirm_save_as_menu_state *) state; + + /* if the menu isn't built, populate now */ + if (!ui_menu_populated(menu)) + menu_confirm_save_as_populate(machine, menu, state); + + /* process the menu */ + event = ui_menu_process(machine, menu, 0); + + /* process the event */ + if ((event != NULL) && (event->iptkey == IPT_UI_SELECT)) + { + if (event->itemref == ITEMREF_YES) + *menustate->yes = TRUE; + + /* no matter what, pop out */ + ui_menu_stack_pop(machine); + } +} + + + +/*************************************************************************** + FILE CREATE MENU +***************************************************************************/ + +/*------------------------------------------------- + is_valid_filename_char - tests to see if a + character is valid in a filename +-------------------------------------------------*/ + +static int is_valid_filename_char(unicode_char unichar) +{ + /* this should really be in the OSD layer */ + static const char valid_filename_char[] = + { + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 00-0f */ + 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 10-1f */ + 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 0, 0, 1, 1, 1, 0, /* !"#$%&'()*+,-./ */ + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, /* 0123456789:;<=>? */ + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* @ABCDEFGHIJKLMNO */ + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, /* PQRSTUVWXYZ[\]^_ */ + 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* `abcdefghijklmno */ + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 0, /* pqrstuvwxyz{|}~ */ + }; + return (unichar < ARRAY_LENGTH(valid_filename_char)) && valid_filename_char[unichar]; +} + + + +/*------------------------------------------------- + file_create_render_extra - perform our + special rendering +-------------------------------------------------*/ + +static void file_create_render_extra(running_machine *machine, ui_menu *menu, void *state, void *selectedref, float top, float bottom, float origx1, float origy1, float origx2, float origy2) +{ + file_create_menu_state *menustate = (file_create_menu_state *) state; + + extra_text_render(machine, menu, state, selectedref, top, bottom, origx1, origy1, origx2, origy2, + astring_c(menustate->manager_menustate->current_directory), + NULL); +} + + + +/*------------------------------------------------- + menu_file_create_populate - populates the file + creator menu +-------------------------------------------------*/ + +static void menu_file_create_populate(running_machine *machine, ui_menu *menu, void *state, void *selection) +{ + astring buffer; + file_create_menu_state *menustate = (file_create_menu_state *) state; + device_image_interface *device = menustate->manager_menustate->selected_device; + const image_device_format *format; + const char *new_image_name; + + /* append the "New Image Name" item */ + if (selection == ITEMREF_NEW_IMAGE_NAME) + { + astring_assemble_2(&buffer, menustate->filename_buffer, "_"); + new_image_name = astring_c(&buffer); + } + else + { + new_image_name = menustate->filename_buffer; + } + ui_menu_item_append(menu, "New Image Name:", new_image_name, 0, ITEMREF_NEW_IMAGE_NAME); + + /* do we support multiple formats? */ + format = device->device_get_creatable_formats(); + if (ENABLE_FORMATS && (format != NULL)) + { + ui_menu_item_append(menu, "Image Format:", menustate->current_format->m_description, 0, ITEMREF_FORMAT); + menustate->current_format = format; + } + + /* finish up the menu */ + ui_menu_item_append(menu, MENU_SEPARATOR_ITEM, NULL, 0, NULL); + ui_menu_item_append(menu, "Create", NULL, 0, ITEMREF_CREATE); + + /* set up custom render proc */ + ui_menu_set_custom_render(menu, file_create_render_extra, ui_get_line_height() + 3.0f * UI_BOX_TB_BORDER, 0); +} + + + +/*------------------------------------------------- + create_new_image - creates a new disk image +-------------------------------------------------*/ + +static int create_new_image(device_image_interface *image, const char *directory, const char *filename, int *yes) +{ + astring *path; + osd_directory_entry *entry; + osd_dir_entry_type file_type; + int do_create, err; + int result = FALSE; + ui_menu *child_menu; + confirm_save_as_menu_state *child_menustate; + + /* assemble the full path */ + path = zippath_combine(astring_alloc(), directory, filename); + + /* does a file or a directory exist at the path */ + entry = osd_stat(astring_c(path)); + file_type = (entry != NULL) ? entry->type : ENTTYPE_NONE; + if (entry != NULL) + free(entry); + + /* special case */ + if ((file_type == ENTTYPE_FILE) && *yes) + file_type = ENTTYPE_NONE; + + switch(file_type) + { + case ENTTYPE_NONE: + /* no file/dir here - always create */ + do_create = TRUE; + break; + + case ENTTYPE_FILE: + /* a file exists here - ask for permission from the user */ + child_menu = ui_menu_alloc(image->device().machine, render_container_get_ui(), menu_confirm_save_as, NULL); + child_menustate = (confirm_save_as_menu_state*)ui_menu_alloc_state(child_menu, sizeof(*child_menustate), NULL); + child_menustate->yes = yes; + ui_menu_stack_push(child_menu); + do_create = FALSE; + break; + + case ENTTYPE_DIR: + /* a directory exists here - we can't save over it */ + ui_popup_time(ERROR_MESSAGE_TIME, "Cannot save over directory"); + do_create = FALSE; + break; + + default: + fatalerror("Unexpected"); + do_create = FALSE; + break; + } + + /* create the image, if appropriate */ + if (do_create) + { + err = image->create(astring_c(path), 0, NULL); + if (err != 0) + popmessage("Error: %s", image->error()); + else + result = TRUE; + } + + /* free the path */ + astring_free(path); + + return result; +} + + + +/*------------------------------------------------- + menu_file_create - file creator menu +-------------------------------------------------*/ + +static void menu_file_create(running_machine *machine, ui_menu *menu, void *parameter, void *state) +{ + void *selection; + const ui_menu_event *event; + ui_menu_event fake_event; + file_create_menu_state *menustate = (file_create_menu_state *) state; + + /* identify the selection */ + selection = ui_menu_get_selection(menu); + + /* rebuild the menu */ + ui_menu_reset(menu, UI_MENU_RESET_REMEMBER_POSITION); + menu_file_create_populate(machine, menu, state, selection); + + if (menustate->confirm_save_as_yes) + { + /* we just returned from a "confirm save as" dialog and the user said "yes" - fake an event */ + memset(&fake_event, 0, sizeof(fake_event)); + fake_event.iptkey = IPT_UI_SELECT; + fake_event.itemref = ITEMREF_CREATE; + event = &fake_event; + } + else + { + /* process the menu */ + event = ui_menu_process(machine, menu, 0); + } + + /* process the event */ + if (event != NULL) + { + /* handle selections */ + switch(event->iptkey) + { + case IPT_UI_SELECT: + if ((event->itemref == ITEMREF_CREATE) || (event->itemref == ITEMREF_NEW_IMAGE_NAME)) + { + if (create_new_image( + menustate->manager_menustate->selected_device, + astring_c(menustate->manager_menustate->current_directory), + menustate->filename_buffer, + &menustate->confirm_save_as_yes)) + { + /* success - pop out twice to device view */ + ui_menu_stack_pop(machine); + ui_menu_stack_pop(machine); + } + } + break; + + case IPT_SPECIAL: + if (ui_menu_get_selection(menu) == ITEMREF_NEW_IMAGE_NAME) + { + input_character( + menustate->filename_buffer, + ARRAY_LENGTH(menustate->filename_buffer), + event->unichar, + is_valid_filename_char); + } + break; + } + } +} + + + +/*************************************************************************** + FILE SELECTOR MENU +***************************************************************************/ + +/*------------------------------------------------- + file_selector_render_extra - perform our + special rendering +-------------------------------------------------*/ + +static void file_selector_render_extra(running_machine *machine, ui_menu *menu, void *state, void *selectedref, float top, float bottom, float origx1, float origy1, float origx2, float origy2) +{ + file_selector_menu_state *menustate = (file_selector_menu_state *) state; + + extra_text_render(machine, menu, state, selectedref, top, bottom, + origx1, origy1, origx2, origy2, + astring_c(menustate->manager_menustate->current_directory), + NULL); +} + + + +/*------------------------------------------------- + compare_file_selector_entries - sorting proc + for file selector entries +-------------------------------------------------*/ + +static int compare_file_selector_entries(const file_selector_entry *e1, const file_selector_entry *e2) +{ + int result; + const char *e1_basename = (e1->basename != NULL) ? e1->basename : ""; + const char *e2_basename = (e2->basename != NULL) ? e2->basename : ""; + + if (e1->type < e2->type) + { + result = -1; + } + else if (e1->type > e2->type) + { + result = 1; + } + else + { + result = mame_stricmp(e1_basename, e2_basename); + if (result == 0) + { + result = strcmp(e1_basename, e2_basename); + if (result == 0) + { + if (e1 < e2) + result = -1; + else if (e1 > e2) + result = 1; + } + } + } + + return result; +} + + + +/*------------------------------------------------- + append_file_selector_entry - appends a new + file selector entry to an entry list +-------------------------------------------------*/ + +static file_selector_entry *append_file_selector_entry(ui_menu *menu, file_selector_menu_state *menustate, + file_selector_entry_type entry_type, const char *entry_basename, const char *entry_fullpath) +{ + file_selector_entry *entry; + file_selector_entry **entryptr; + + /* allocate a new entry */ + entry = (file_selector_entry *) ui_menu_pool_alloc(menu, sizeof(*entry)); + memset(entry, 0, sizeof(*entry)); + entry->type = entry_type; + entry->basename = (entry_basename != NULL) ? ui_menu_pool_strdup(menu, entry_basename) : entry_basename; + entry->fullpath = (entry_fullpath != NULL) ? ui_menu_pool_strdup(menu, entry_fullpath) : entry_fullpath; + + /* find the end of the list */ + entryptr = &menustate->entrylist; + while ((*entryptr != NULL) && (compare_file_selector_entries(entry, *entryptr) >= 0)) + entryptr = &(*entryptr)->next; + + /* insert the entry */ + entry->next = *entryptr; + *entryptr = entry; + return entry; +} + + + +/*------------------------------------------------- + append_file_selector_entry_menu_item - appends + a menu item for a file selector entry +-------------------------------------------------*/ + +static file_selector_entry *append_dirent_file_selector_entry(ui_menu *menu, file_selector_menu_state *menustate, + const osd_directory_entry *dirent) +{ + astring *buffer; + file_selector_entry_type entry_type; + file_selector_entry *entry; + + switch(dirent->type) + { + case ENTTYPE_FILE: + entry_type = SELECTOR_ENTRY_TYPE_FILE; + break; + + case ENTTYPE_DIR: + entry_type = SELECTOR_ENTRY_TYPE_DIRECTORY; + break; + + default: + /* exceptional case; do not add a menu item */ + return NULL; + } + + /* determine the full path */ + buffer = zippath_combine( + astring_alloc(), + astring_c(menustate->manager_menustate->current_directory), + dirent->name); + + /* create the file selector entry */ + entry = append_file_selector_entry( + menu, + menustate, + entry_type, + dirent->name, + astring_c(buffer)); + + astring_free(buffer); + return entry; +} + + + +/*------------------------------------------------- + append_file_selector_entry_menu_item - appends + a menu item for a file selector entry +-------------------------------------------------*/ + +static void append_file_selector_entry_menu_item(ui_menu *menu, const file_selector_entry *entry) +{ + const char *text = NULL; + const char *subtext = NULL; + + switch(entry->type) + { + case SELECTOR_ENTRY_TYPE_EMPTY: + text = "[empty slot]"; + break; + + case SELECTOR_ENTRY_TYPE_CREATE: + text = "[create]"; + break; + + case SELECTOR_ENTRY_TYPE_DRIVE: + text = entry->basename; + subtext = "[DRIVE]"; + break; + + case SELECTOR_ENTRY_TYPE_DIRECTORY: + text = entry->basename; + subtext = "[DIR]"; + break; + + case SELECTOR_ENTRY_TYPE_FILE: + text = entry->basename; + subtext = "[FILE]"; + break; + } + ui_menu_item_append(menu, text, subtext, 0, (void *) entry); +} + + + +/*------------------------------------------------- + menu_file_selector_populate - creates and + allocates all menu items for a directory +-------------------------------------------------*/ + +static file_error menu_file_selector_populate(running_machine *machine, ui_menu *menu, file_selector_menu_state *menustate) +{ + zippath_directory *directory = NULL; + file_error err = FILERR_NONE; + const osd_directory_entry *dirent; + const file_selector_entry *entry; + const file_selector_entry *selected_entry = NULL; + int i; + const char *volume_name; + device_image_interface *device = menustate->manager_menustate->selected_device; + const char *path = astring_c(menustate->manager_menustate->current_directory); + + /* open the directory */ + err = zippath_opendir(path, &directory); + if (err != FILERR_NONE) + goto done; + + /* clear out the menu entries */ + menustate->entrylist = NULL; + + /* add the "[empty slot]" entry */ + append_file_selector_entry(menu, menustate, SELECTOR_ENTRY_TYPE_EMPTY, NULL, NULL); + + if (device->image_config().is_creatable() && !zippath_is_zip(directory)) + { + /* add the "[create]" entry */ + append_file_selector_entry(menu, menustate, SELECTOR_ENTRY_TYPE_CREATE, NULL, NULL); + } + + /* add the drives */ + i = 0; + while((volume_name = osd_get_volume_name(i))!=NULL) + { + append_file_selector_entry(menu, menustate, SELECTOR_ENTRY_TYPE_DRIVE, + volume_name, volume_name); + i++; + } + + /* build the menu for each item */ + while((dirent = zippath_readdir(directory)) != NULL) + { + /* append a dirent entry */ + entry = append_dirent_file_selector_entry(menu, menustate, dirent); + + if (entry != NULL) + { + /* set the selected item to be the first non-parent directory or file */ + if ((selected_entry == NULL) && strcmp(dirent->name, "..")) + selected_entry = entry; + + /* do we have to select this file? */ + if (!mame_stricmp(astring_c(menustate->manager_menustate->current_file), dirent->name)) + selected_entry = entry; + } + } + + /* append all of the menu entries */ + for (entry = menustate->entrylist; entry != NULL; entry = entry->next) + append_file_selector_entry_menu_item(menu, entry); + + /* set the selection (if we have one) */ + if (selected_entry != NULL) + ui_menu_set_selection(menu, (void *) selected_entry); + + /* set up custom render proc */ + ui_menu_set_custom_render(menu, file_selector_render_extra, ui_get_line_height() + 3.0f * UI_BOX_TB_BORDER, 0); + +done: + if (directory != NULL) + zippath_closedir(directory); + return err; +} + + + +/*------------------------------------------------- + check_path - performs a quick check to see if + a path exists +-------------------------------------------------*/ + +static file_error check_path(const char *path) +{ + return zippath_opendir(path, NULL); +} + + + +/*------------------------------------------------- + menu_file_selector - file selector menu +-------------------------------------------------*/ + +static void menu_file_selector(running_machine *machine, ui_menu *menu, void *parameter, void *state) +{ + file_error err; + const ui_menu_event *event; + ui_menu *child_menu; + file_selector_menu_state *menustate; + file_create_menu_state *child_menustate; + const file_selector_entry *entry; + + /* get menu state */ + menustate = (file_selector_menu_state *) state; + + /* if the menu isn't built, populate now */ + if (!ui_menu_populated(menu)) + { + err = menu_file_selector_populate(machine, menu, menustate); + + /* pop out if there was an error */ + if (err != FILERR_NONE) + { + ui_menu_stack_pop(machine); + return; + } + } + + /* process the menu */ + event = ui_menu_process(machine, menu, 0); + if (event != NULL && event->itemref != NULL) + { + /* handle selections */ + if (event->iptkey == IPT_UI_SELECT) + { + entry = (const file_selector_entry *) event->itemref; + switch(entry->type) + { + case SELECTOR_ENTRY_TYPE_EMPTY: + /* empty slot - unload */ + menustate->manager_menustate->selected_device->unload(); + ui_menu_stack_pop(machine); + break; + + case SELECTOR_ENTRY_TYPE_CREATE: + /* create */ + child_menu = ui_menu_alloc(machine, render_container_get_ui(), menu_file_create, NULL); + child_menustate = (file_create_menu_state*)ui_menu_alloc_state(child_menu, sizeof(*child_menustate), NULL); + child_menustate->manager_menustate = menustate->manager_menustate; + ui_menu_stack_push(child_menu); + break; + + case SELECTOR_ENTRY_TYPE_DRIVE: + case SELECTOR_ENTRY_TYPE_DIRECTORY: + /* drive/directory - first check the path */ + err = check_path(entry->fullpath); + if (err != FILERR_NONE) + { + /* this path is problematic; present the user with an error and bail */ + ui_popup_time(1, "Error accessing %s", entry->fullpath); + break; + } + astring_cpyc(menustate->manager_menustate->current_directory, entry->fullpath); + ui_menu_reset(menu, (ui_menu_reset_options)0); + break; + + case SELECTOR_ENTRY_TYPE_FILE: + /* file */ + menustate->manager_menustate->selected_device->load(entry->fullpath); + ui_menu_stack_pop(machine); + break; + } + } + } +} + + + +/*************************************************************************** + FILE MANAGER +***************************************************************************/ + +/*------------------------------------------------- + fix_working_directory - checks the working + directory for this device to ensure that it + "makes sense" +-------------------------------------------------*/ + +static void fix_working_directory(device_image_interface *image) +{ + /* if the image exists, set the working directory to the parent directory */ + if (image->exists()) + { + astring *astr = astring_alloc(); + zippath_parent(astr, image->filename()); + image->set_working_directory(astring_c(astr)); + astring_free(astr); + } + + /* check to see if the path exists; if not clear it */ + if (check_path(image->working_directory()) != FILERR_NONE) + image->set_working_directory(NULL); +} + + + +/*------------------------------------------------- + file_manager_render_extra - perform our + special rendering +-------------------------------------------------*/ + +static void file_manager_render_extra(running_machine *machine, ui_menu *menu, void *state, void *selectedref, float top, float bottom, float origx1, float origy1, float origx2, float origy2) +{ + file_manager_menu_state *menustate = (file_manager_menu_state *) state; + const char *path; + + /* access the path */ + path = (menustate->selected_device != NULL) ? menustate->selected_device->filename() : NULL; + extra_text_render(machine, menu, state, selectedref, top, bottom, + origx1, origy1, origx2, origy2, NULL, path); +} + + + +/*------------------------------------------------- + menu_file_manager_populate - populates the main + file manager menu +-------------------------------------------------*/ + +static void menu_file_manager_populate(running_machine *machine, ui_menu *menu, void *state) +{ + char buffer[2048]; + device_image_interface *image = NULL; + const char *entry_basename; + + /* cycle through all devices for this system */ + for (bool gotone = machine->devicelist.first(image); gotone; gotone = image->next(image)) + { + /* get the image type/id */ + snprintf(buffer, ARRAY_LENGTH(buffer), + "%s", + image->image_config().name()); + + /* get the base name */ + entry_basename = image->basename(); + + /* record the menu item */ + ui_menu_item_append(menu, buffer, (entry_basename != NULL) ? entry_basename : "---", 0, (void *) image); + } + + /* set up custom render proc */ + ui_menu_set_custom_render(menu, file_manager_render_extra, 0, ui_get_line_height() + 3.0f * UI_BOX_TB_BORDER); +} + + + +/*------------------------------------------------- + file_manager_destroy_state - state destructor +-------------------------------------------------*/ + +static void file_manager_destroy_state(ui_menu *menu, void *state) +{ + file_manager_menu_state *menustate = (file_manager_menu_state *) state; + + if (menustate->current_directory != NULL) + astring_free(menustate->current_directory); + + if (menustate->current_file != NULL) + astring_free(menustate->current_file); +} + + + +/*------------------------------------------------- + menu_file_manager - main file manager menu +-------------------------------------------------*/ + +void ui_image_menu_file_manager(running_machine *machine, ui_menu *menu, void *parameter, void *state) +{ + const ui_menu_event *event; + file_manager_menu_state *menustate; + ui_menu *child_menu; + file_selector_menu_state *child_menustate; + + /* if no state, allocate now */ + if (state == NULL) + { + state = ui_menu_alloc_state(menu, sizeof(*menustate), file_manager_destroy_state); + menustate = (file_manager_menu_state *) state; + + menustate->current_directory = astring_alloc(); + menustate->current_file = astring_alloc(); + } + menustate = (file_manager_menu_state *) state; + + /* if the menu isn't built, populate now */ + if (!ui_menu_populated(menu)) + menu_file_manager_populate(machine, menu, state); + + /* update the selected device */ + menustate->selected_device = (device_image_interface *) ui_menu_get_selection(menu); + + /* process the menu */ + event = ui_menu_process(machine, menu, 0); + if (event != NULL && event->iptkey == IPT_UI_SELECT) + { + menustate->selected_device = (device_image_interface *) event->itemref; + if (menustate->selected_device != NULL) + { + /* ensure that the working directory for this device exists */ + fix_working_directory(menustate->selected_device); + + /* set up current_directory and current_file - depends on whether we have an image */ + astring_cpyc(menustate->current_directory, menustate->selected_device->working_directory()); + astring_cpyc(menustate->current_file, menustate->selected_device->exists() ? menustate->selected_device->basename() : ""); + + /* reset the existing menu */ + ui_menu_reset(menu, UI_MENU_RESET_REMEMBER_POSITION); + + /* push the menu */ + child_menu = ui_menu_alloc(machine, render_container_get_ui(), menu_file_selector, NULL); + child_menustate = (file_selector_menu_state *)ui_menu_alloc_state(child_menu, sizeof(*child_menustate), NULL); + child_menustate->manager_menustate = menustate; + ui_menu_stack_push(child_menu); + } + } +} + +/*------------------------------------------------- + image_info_astring - populate an allocated + string with the image info text +-------------------------------------------------*/ + +static astring *image_info_astring(running_machine *machine, astring *string) +{ + device_image_interface *image = NULL; + + astring_printf(string, "%s\n\n", machine->gamedrv->description); + +#if 0 + if (mess_ram_size > 0) + { + char buf2[RAM_STRING_BUFLEN]; + astring_catprintf(string, "RAM: %s\n\n", ram_string(buf2, mess_ram_size)); + } +#endif + + for (bool gotone = machine->devicelist.first(image); gotone; gotone = image->next(image)) + { + const char *name = image->filename(); + if (name != NULL) + { + const char *base_filename; + const char *info; + char *base_filename_noextension; + + base_filename = image->basename(); + base_filename_noextension = strip_extension(base_filename); + + /* display device type and filename */ + astring_catprintf(string, "%s: %s\n", image->image_config().name(), base_filename); + + /* display long filename, if present and doesn't correspond to name */ + info = image->longname(); + if (info && (!base_filename_noextension || mame_stricmp(info, base_filename_noextension))) + astring_catprintf(string, "%s\n", info); + + /* display manufacturer, if available */ + info = image->manufacturer(); + if (info != NULL) + { + astring_catprintf(string, "%s", info); + info = stripspace(image->year()); + if (info && *info) + astring_catprintf(string, ", %s", info); + astring_catprintf(string,"\n"); + } + + /* display playable information, if available */ + info = image->playable(); + if (info != NULL) + astring_catprintf(string, "%s\n", info); + + if (base_filename_noextension != NULL) + free(base_filename_noextension); + } + else + { + astring_catprintf(string, "%s: ---\n", image->image_config().name()); + } + } + return string; +} + + + +/*------------------------------------------------- + ui_image_menu_image_info - menu that shows info + on all loaded images +-------------------------------------------------*/ + +void ui_image_menu_image_info(running_machine *machine, ui_menu *menu, void *parameter, void *state) +{ + /* if the menu isn't built, populate now */ + if (!ui_menu_populated(menu)) + { + astring *tempstring = image_info_astring(machine, astring_alloc()); + ui_menu_item_append(menu, astring_c(tempstring), NULL, MENU_FLAG_MULTILINE, NULL); + astring_free(tempstring); + } + + /* process the menu */ + ui_menu_process(machine, menu, 0); +} diff --git a/src/emu/uiimage.h b/src/emu/uiimage.h new file mode 100644 index 00000000000..25c08636058 --- /dev/null +++ b/src/emu/uiimage.h @@ -0,0 +1,27 @@ +/*************************************************************************** + + uiimage.h + + Internal MAME user interface image. + + Copyright Nicola Salmoria and the MAME Team. + Visit http://mamedev.org for licensing and usage restrictions. + +***************************************************************************/ + +#pragma once + +#ifndef __UIIMAGE_H__ +#define __UIIMAGE_H__ + + + +/*************************************************************************** + FUNCTION PROTOTYPES +***************************************************************************/ + +void ui_image_menu_file_manager(running_machine *machine, ui_menu *menu, void *parameter, void *state); + +void ui_image_menu_image_info(running_machine *machine, ui_menu *menu, void *parameter, void *state); + +#endif /* __UIIMAGE_H__ */ diff --git a/src/emu/uimenu.c b/src/emu/uimenu.c index c100f89b367..57d31a0dec8 100644 --- a/src/emu/uimenu.c +++ b/src/emu/uimenu.c @@ -14,6 +14,7 @@ #include "ui.h" #include "rendutil.h" #include "cheat.h" +#include "uiimage.h" #include "uiinput.h" #include "uimenu.h" #include "audit.h" @@ -1530,11 +1531,23 @@ static void menu_main_populate(running_machine *machine, ui_menu *menu, void *st /* add game info menu */ ui_menu_item_append(menu, CAPSTARTGAMENOUN " Information", NULL, 0, (void *)menu_game_info); -#ifdef MESS - /* add MESS-specific menus */ - ui_mess_main_menu_populate(machine, menu); -#endif /* MESS */ + device_image_interface *image = NULL; + if (machine->devicelist.first(image)) + { + /* add image info menu */ + ui_menu_item_append(menu, "Image Information", NULL, 0, (void*)ui_image_menu_image_info); + /* add file manager menu */ + ui_menu_item_append(menu, "File Manager", NULL, 0, (void*)ui_image_menu_file_manager); + + /* add software menu */ + ui_menu_item_append(menu, "Software", NULL, 0, (void*)ui_image_menu_software); + + #ifdef MESS + /* add MESS-specific menus */ + ui_mess_main_menu_populate(machine, menu); + #endif /* MESS */ + } /* add keyboard mode menu */ if (input_machine_has_keyboard(machine) && inputx_can_post(machine)) ui_menu_item_append(menu, "Keyboard Mode", NULL, 0, (void *)ui_menu_keyboard_mode); |