diff options
author | Miodrag Milanovic <mmicko@gmail.com> | 2010-06-15 09:16:05 +0000 |
---|---|---|
committer | Miodrag Milanovic <mmicko@gmail.com> | 2010-06-15 09:16:05 +0000 |
commit | 791a3515b9b1e2b9761d695357e5ff1e621d0224 (patch) | |
tree | 5c356f6ef1cd67248f5093c4079745b4bad14635 /src/emu | |
parent | 2a5ee186143b35358af24085537426616c4508c6 (diff) |
devlegacy.c,clifront.c,info.c [Miodrag Milanovic]
- Created legacy image device
- Moved opresolv implementation from MESS
- listmedia is option is available in MAME too
- listxml output now contains image devices
Diffstat (limited to 'src/emu')
-rw-r--r-- | src/emu/clifront.c | 70 | ||||
-rw-r--r-- | src/emu/devlegcy.c | 197 | ||||
-rw-r--r-- | src/emu/devlegcy.h | 156 | ||||
-rw-r--r-- | src/emu/diimage.c | 89 | ||||
-rw-r--r-- | src/emu/diimage.h | 91 | ||||
-rw-r--r-- | src/emu/emu.h | 2 | ||||
-rw-r--r-- | src/emu/emu.mak | 2 | ||||
-rw-r--r-- | src/emu/info.c | 59 | ||||
-rw-r--r-- | src/emu/opresolv.c | 585 | ||||
-rw-r--r-- | src/emu/opresolv.h | 160 |
10 files changed, 1406 insertions, 5 deletions
diff --git a/src/emu/clifront.c b/src/emu/clifront.c index f05616006bf..380211d7eb8 100644 --- a/src/emu/clifront.c +++ b/src/emu/clifront.c @@ -55,6 +55,7 @@ static void display_help(void); static int info_verifyroms(core_options *options, const char *gamename); static int info_verifysamples(core_options *options, const char *gamename); static int info_romident(core_options *options, const char *gamename); +static int info_listmedia(core_options *opts, const char *gamename); /* utilities */ static void romident(core_options *options, const char *filename, romident_status *status); @@ -95,8 +96,8 @@ static const options_entry cli_options[] = { "verifysamples", "0", OPTION_COMMAND, "report samplesets that have problems" }, { "romident", "0", OPTION_COMMAND, "compare files with known MAME roms" }, { "listdevices;ld", "0", OPTION_COMMAND, "list available devices" }, -#ifdef MESS { "listmedia;lm", "0", OPTION_COMMAND, "list available media for the system" }, +#ifdef MESS { "listsoftware", "0", OPTION_COMMAND, "list known software for the system" }, #endif @@ -273,8 +274,8 @@ static int execute_commands(core_options *options, const char *exename, const ga { CLIOPTION_LISTSAMPLES, cli_info_listsamples }, { CLIOPTION_VERIFYROMS, info_verifyroms }, { CLIOPTION_VERIFYSAMPLES, info_verifysamples }, -#ifdef MESS { CLIOPTION_LISTMEDIA, info_listmedia }, +#ifdef MESS { CLIOPTION_LISTSOFTWARE, info_listsoftware }, #endif { CLIOPTION_ROMIDENT, info_romident } @@ -777,6 +778,71 @@ static int info_verifyroms(core_options *options, const char *gamename) /*------------------------------------------------- + info_listmedia - output the list of image + devices referenced by a given game or set of + games +-------------------------------------------------*/ + +static int info_listmedia(core_options *options, const char *gamename) +{ + int count = 0, devcount; + int drvindex; + machine_config *config; + const device_config_image_interface *dev; + const char *src; + const char *driver_name; + const char *name; + const char *shortname; + char paren_shortname[16]; + + printf(" SYSTEM DEVICE NAME (brief) IMAGE FILE EXTENSIONS SUPPORTED \n"); + printf("---------- -------------------- ------------------------------------\n"); + + /* iterate over drivers */ + for (drvindex = 0; drivers[drvindex] != NULL; drvindex++) + if (mame_strwildcmp(gamename, drivers[drvindex]->name) == 0) + { + /* allocate the machine config */ + config = machine_config_alloc(drivers[drvindex]->machine_config); + + driver_name = drivers[drvindex]->name; + + devcount = 0; + + for (bool gotone = config->devicelist.first(dev); gotone; gotone = dev->next(dev)) + { + src = downcast<const legacy_image_device_config_base *>(dev)->file_extensions(); + name = downcast<const legacy_image_device_config_base *>(dev)->instance_name(); + shortname = downcast<const legacy_image_device_config_base *>(dev)->brief_instance_name(); + + sprintf(paren_shortname, "(%s)", shortname); + + printf("%-13s%-12s%-8s ", driver_name, name, paren_shortname); + driver_name = " "; + + while (src && *src) + { + printf(".%-5s", src); + src += strlen(src) + 1; + devcount++; + } + printf("\n"); + } + if (!devcount) + printf("%-13s(none)\n",driver_name); + + count++; + machine_config_free(config); + } + + if (!count) + printf("There are no Computers or Consoles named %s\n", gamename); + + return (count > 0) ? MAMERR_NONE : MAMERR_NO_SUCH_GAME; +} + + +/*------------------------------------------------- info_verifysamples - verify the sample sets of one or more games -------------------------------------------------*/ diff --git a/src/emu/devlegcy.c b/src/emu/devlegcy.c index 7bb660e5af9..19a8579cc25 100644 --- a/src/emu/devlegcy.c +++ b/src/emu/devlegcy.c @@ -344,3 +344,200 @@ void legacy_nvram_device_base::nvram_write(mame_file &file) device_nvram_func nvram_func = reinterpret_cast<device_nvram_func>(m_config.get_legacy_config_fct(DEVINFO_FCT_NVRAM)); (*nvram_func)(this, &file, TRUE); } + +//************************************************************************** +// LEGACY IMAGE DEVICE CONFIGURATION +//************************************************************************** + +typedef struct _image_device_type_info image_device_type_info; +struct _image_device_type_info +{ + iodevice_t type; + const char *name; + const char *shortname; +}; + +static const image_device_type_info device_info_array[] = +{ + { IO_CARTSLOT, "cartridge", "cart" }, /* 0 */ + { IO_FLOPPY, "floppydisk", "flop" }, /* 1 */ + { IO_HARDDISK, "harddisk", "hard" }, /* 2 */ + { IO_CYLINDER, "cylinder", "cyln" }, /* 3 */ + { IO_CASSETTE, "cassette", "cass" }, /* 4 */ + { IO_PUNCHCARD, "punchcard", "pcrd" }, /* 5 */ + { IO_PUNCHTAPE, "punchtape", "ptap" }, /* 6 */ + { IO_PRINTER, "printer", "prin" }, /* 7 */ + { IO_SERIAL, "serial", "serl" }, /* 8 */ + { IO_PARALLEL, "parallel", "parl" }, /* 9 */ + { IO_SNAPSHOT, "snapshot", "dump" }, /* 10 */ + { IO_QUICKLOAD, "quickload", "quik" }, /* 11 */ + { IO_MEMCARD, "memcard", "memc" }, /* 12 */ + { IO_CDROM, "cdrom", "cdrm" }, /* 13 */ + { IO_MAGTAPE, "magtape", "magt" }, /* 14 */ +}; + +static const image_device_type_info *find_device_type(iodevice_t type) +{ + int i; + for (i = 0; i < ARRAY_LENGTH(device_info_array); i++) + { + if (device_info_array[i].type == type) + return &device_info_array[i]; + } + return NULL; +} + +static const char *device_typename(iodevice_t type) +{ + const image_device_type_info *info = find_device_type(type); + return (info != NULL) ? info->name : NULL; +} + + + +static const char *device_brieftypename(iodevice_t type) +{ + const image_device_type_info *info = find_device_type(type); + return (info != NULL) ? info->shortname : NULL; +} + +//------------------------------------------------- +// legacy_image_device_config_base - constructor +//------------------------------------------------- + +legacy_image_device_config_base::legacy_image_device_config_base(const machine_config &mconfig, device_type type, const char *tag, const device_config *owner, UINT32 clock, device_get_config_func get_config) + : legacy_device_config_base(mconfig, type, tag, owner, clock, get_config), + device_config_image_interface(mconfig, *this) +{ + memset(&m_config, 0, sizeof(m_config)); + m_mconfig = &mconfig; +} + +//------------------------------------------------- +// device_config_complete - update configuration +// based on completed device setup +//------------------------------------------------- + +void legacy_image_device_config_base::device_config_complete() +{ + char buffer[64]; + const device_config_image_interface *that_device; + int count = 0; + int index = -1; + image_device_format **formatptr; + image_device_format *format; + formatptr = &m_config.m_formatlist; + int cnt = 0; + + m_config.m_type = static_cast<iodevice_t>(get_legacy_config_int(DEVINFO_INT_IMAGE_TYPE)); + m_config.m_readable = get_legacy_config_int(DEVINFO_INT_IMAGE_READABLE)!=0; + m_config.m_writeable = get_legacy_config_int(DEVINFO_INT_IMAGE_WRITEABLE)!=0; + m_config.m_creatable = get_legacy_config_int(DEVINFO_INT_IMAGE_CREATABLE)!=0; + m_config.m_must_be_loaded = get_legacy_config_int(DEVINFO_INT_IMAGE_MUST_BE_LOADED)!=0; + m_config.m_reset_on_load = get_legacy_config_int(DEVINFO_INT_IMAGE_RESET_ON_LOAD)!=0; + m_config.m_has_partial_hash = get_legacy_config_int(DEVINFO_FCT_IMAGE_PARTIAL_HASH)!=0; + + m_config.m_interface_name = core_strdup(get_legacy_config_string(DEVINFO_STR_IMAGE_INTERFACE)); + char *s = global_alloc_array_clear(char,strlen(get_legacy_config_string(DEVINFO_STR_IMAGE_FILE_EXTENSIONS))+2); + strcpy(s,get_legacy_config_string(DEVINFO_STR_IMAGE_FILE_EXTENSIONS)); + m_config.m_file_extensions = s; + /* convert the comma delimited list to a NUL delimited list */ + while((s = strchr(s, ',')) != NULL) + *(s++) = '\0'; + + m_config.load = reinterpret_cast<device_image_load_func>(get_legacy_config_fct(DEVINFO_FCT_IMAGE_LOAD)); + m_config.create = reinterpret_cast<device_image_create_func>(get_legacy_config_fct(DEVINFO_FCT_IMAGE_CREATE)); + m_config.unload = reinterpret_cast<device_image_unload_func>(get_legacy_config_fct(DEVINFO_FCT_IMAGE_UNLOAD)); + m_config.display = reinterpret_cast<device_image_display_func>(get_legacy_config_fct(DEVINFO_FCT_IMAGE_DISPLAY)); + m_config.partialhash = reinterpret_cast<device_image_partialhash_func>(get_legacy_config_fct(DEVINFO_FCT_IMAGE_PARTIAL_HASH)); + m_config.get_devices = reinterpret_cast<device_image_get_devices_func>(get_legacy_config_fct(DEVINFO_FCT_IMAGE_GET_DEVICES)); + + m_config.m_create_option_guide = reinterpret_cast<const option_guide *>(get_legacy_config_ptr(DEVINFO_PTR_IMAGE_CREATE_OPTGUIDE)); + + int format_count = get_legacy_config_int(DEVINFO_INT_IMAGE_CREATE_OPTCOUNT); + + for (int i = 0; i < format_count; i++) + { + // only add if creatable + if (get_legacy_config_string(DEVINFO_PTR_IMAGE_CREATE_OPTSPEC + i)) { + // allocate a new format + format = global_alloc_clear(image_device_format); + + // populate it + format->index = cnt; + format->name = core_strdup(get_legacy_config_string(DEVINFO_STR_IMAGE_CREATE_OPTNAME + i)); + format->description = core_strdup(get_legacy_config_string(DEVINFO_STR_IMAGE_CREATE_OPTDESC + i)); + format->extensions = core_strdup(get_legacy_config_string(DEVINFO_STR_IMAGE_CREATE_OPTEXTS + i)); + format->optspec = core_strdup(get_legacy_config_string(DEVINFO_PTR_IMAGE_CREATE_OPTSPEC + i)); + + // and append it to the list + *formatptr = format; + formatptr = &format->next; + cnt++; + } + } + + for (bool gotone = m_mconfig->devicelist.first(that_device); gotone; gotone = that_device->next(that_device)) + { + if (this == that_device) + index = count; + if (downcast<const legacy_image_device_config_base *>(that_device)->image_type_direct() == m_config.m_type) + count++; + } + if (count > 1) { + snprintf(buffer, 64, "%s%d", device_typename(m_config.m_type), index + 1); + m_config.m_instance_name = core_strdup(buffer); + snprintf(buffer, 64, "%s%d", device_brieftypename(m_config.m_type), index + 1); + m_config.m_brief_instance_name = core_strdup(buffer); + } + else + { + m_config.m_instance_name = core_strdup(device_typename(m_config.m_type)); + m_config.m_brief_instance_name = core_strdup(device_brieftypename(m_config.m_type)); + } + // Override in case of hardcoded values + if (strlen(get_legacy_config_string(DEVINFO_STR_IMAGE_INSTANCE_NAME))>0) { + m_config.m_instance_name = core_strdup(get_legacy_config_string(DEVINFO_STR_IMAGE_INSTANCE_NAME)); + } + if (strlen(get_legacy_config_string(DEVINFO_STR_IMAGE_BRIEF_INSTANCE_NAME))>0) { + m_config.m_brief_instance_name = core_strdup(get_legacy_config_string(DEVINFO_STR_IMAGE_BRIEF_INSTANCE_NAME)); + } +} + +const char *legacy_image_device_config_base::image_type_name() const +{ + return device_typename(m_config.m_type); +} +//------------------------------------------------- +// ~legacy_device_config_base - destructor +//------------------------------------------------- + +legacy_image_device_config_base::~legacy_image_device_config_base() +{ + global_free(m_config.m_file_extensions); + image_device_format **formatptr = &m_config.m_formatlist; + + + /* free all entries */ + while (*formatptr != NULL) + { + image_device_format *entry = *formatptr; + *formatptr = entry->next; + global_free(entry); + } +} + + +//************************************************************************** +// LIVE LEGACY IMAGE DEVICE +//************************************************************************** + +//------------------------------------------------- +// legacy_image_device_base - constructor +//------------------------------------------------- + +legacy_image_device_base::legacy_image_device_base(running_machine &machine, const device_config &config) + : legacy_device_base(machine, config), + device_image_interface(machine, config, *this) +{ +} diff --git a/src/emu/devlegcy.h b/src/emu/devlegcy.h index 5a320f840d3..d393d89478f 100644 --- a/src/emu/devlegcy.h +++ b/src/emu/devlegcy.h @@ -48,6 +48,8 @@ // CONSTANTS //************************************************************************** +#define DEVINFO_IMAGE_CREATE_OPTMAX 32 + // state constants passed to the device_get_config_func enum { @@ -130,9 +132,68 @@ enum DEVINFO_STR_CLASS_SPECIFIC = 0x34000, // R/W: device-specific values start here DEVINFO_STR_DEVICE_SPECIFIC = 0x38000, // R/W: device-specific values start here - DEVINFO_STR_LAST = 0x3ffff + DEVINFO_STR_LAST = 0x3ffff, + + /* --- image device related --- */ + /* --- the following bits of info are returned as integers --- */ + DEVINFO_INT_IMAGE_FIRST = DEVINFO_INT_FIRST + 0x7000, + DEVINFO_INT_IMAGE_TYPE, + DEVINFO_INT_IMAGE_READABLE, + DEVINFO_INT_IMAGE_WRITEABLE, + DEVINFO_INT_IMAGE_CREATABLE, + DEVINFO_INT_IMAGE_MUST_BE_LOADED, + DEVINFO_INT_IMAGE_RESET_ON_LOAD, + DEVINFO_INT_IMAGE_CREATE_OPTCOUNT, + DEVINFO_INT_IMAGE_LAST = DEVINFO_INT_IMAGE_FIRST + 0x0fff, + + /* --- the following bits of info are returned as pointers --- */ + DEVINFO_PTR_IMAGE_FIRST = DEVINFO_PTR_FIRST + 0x7000, + DEVINFO_PTR_IMAGE_CREATE_OPTGUIDE, + DEVINFO_PTR_IMAGE_CREATE_OPTSPEC, + + /* --- the following bits of info are returned as pointers to functions --- */ + DEVINFO_FCT_IMAGE_FIRST = DEVINFO_FCT_FIRST + 0x7000, + DEVINFO_FCT_IMAGE_LOAD, /* R/O: device_image_load_func */ + DEVINFO_FCT_IMAGE_CREATE, /* R/O: device_image_create_func */ + DEVINFO_FCT_IMAGE_UNLOAD, /* R/O: device_image_unload_func */ + DEVINFO_FCT_IMAGE_DISPLAY, /* R/O: device_image_display_func */ + DEVINFO_FCT_IMAGE_PARTIAL_HASH, /* R/O: device_image_partialhash_func */ + DEVINFO_FCT_IMAGE_GET_DEVICES, /* R/O: device_image_get_devices_func */ + DEVINFO_FCT_IMAGE_LAST = DEVINFO_FCT_FIRST + 0x0fff, + + /* --- the following bits of info are returned as NULL-terminated strings --- */ + DEVINFO_STR_IMAGE_FIRST = DEVINFO_STR_FIRST + 0x7000, + DEVINFO_STR_IMAGE_FILE_EXTENSIONS, + DEVINFO_STR_IMAGE_INSTANCE_NAME, + DEVINFO_STR_IMAGE_BRIEF_INSTANCE_NAME, + DEVINFO_STR_IMAGE_CREATE_OPTNAME, + DEVINFO_STR_IMAGE_CREATE_OPTDESC = DEVINFO_STR_IMAGE_CREATE_OPTNAME + DEVINFO_IMAGE_CREATE_OPTMAX, + DEVINFO_STR_IMAGE_CREATE_OPTEXTS = DEVINFO_STR_IMAGE_CREATE_OPTDESC + DEVINFO_IMAGE_CREATE_OPTMAX, + DEVINFO_STR_IMAGE_INTERFACE, + DEVINFO_STR_IMAGE_LAST = DEVINFO_STR_IMAGE_FIRST + 0x0fff }; +typedef enum +{ + /* List of all supported devices. Refer to the device by these names only */ + IO_UNKNOWN, + IO_CARTSLOT, /* 1 - Cartridge Port, as found on most console and on some computers */ + IO_FLOPPY, /* 2 - Floppy Disk unit */ + IO_HARDDISK, /* 3 - Hard Disk unit */ + IO_CYLINDER, /* 4 - Magnetically-Coated Cylinder */ + IO_CASSETTE, /* 5 - Cassette Recorder (common on early home computers) */ + IO_PUNCHCARD, /* 6 - Card Puncher/Reader */ + IO_PUNCHTAPE, /* 7 - Tape Puncher/Reader (reels instead of punchcards) */ + IO_PRINTER, /* 8 - Printer device */ + IO_SERIAL, /* 9 - Generic Serial Port */ + IO_PARALLEL, /* 10 - Generic Parallel Port */ + IO_SNAPSHOT, /* 11 - Complete 'snapshot' of the state of the computer */ + IO_QUICKLOAD, /* 12 - Allow to load program/data into memory, without matching any actual device */ + IO_MEMCARD, /* 13 - Memory card */ + IO_CDROM, /* 14 - optical CD-ROM disc */ + IO_MAGTAPE, /* 15 - Magentic tape */ + IO_COUNT /* 16 - Total Number of IO_devices for searching */ +} iodevice_t; //************************************************************************** @@ -191,11 +252,13 @@ device_t *configclass::alloc_device(running_machine &machine) const \ #define DECLARE_LEGACY_SOUND_DEVICE(name, basename) _DECLARE_LEGACY_DEVICE(SOUND_##name, basename, basename##_sound_device_config, basename##_sound_device, legacy_sound_device_config_base, legacy_sound_device_base) #define DECLARE_LEGACY_MEMORY_DEVICE(name, basename) _DECLARE_LEGACY_DEVICE(name, basename, basename##_device_config, basename##_device, legacy_memory_device_config_base, legacy_memory_device_base) #define DECLARE_LEGACY_NVRAM_DEVICE(name, basename) _DECLARE_LEGACY_DEVICE(name, basename, basename##_device_config, basename##_device, legacy_nvram_device_config_base, legacy_nvram_device_base) +#define DECLARE_LEGACY_IMAGE_DEVICE(name, basename) _DECLARE_LEGACY_DEVICE(name, basename, basename##_device_config, basename##_device, legacy_image_device_config_base, legacy_image_device_base) #define DEFINE_LEGACY_DEVICE(name, basename) _DEFINE_LEGACY_DEVICE(name, basename, basename##_device_config, basename##_device, legacy_device_config_base, legacy_device_base) #define DEFINE_LEGACY_SOUND_DEVICE(name, basename) _DEFINE_LEGACY_DEVICE(SOUND_##name, basename, basename##_sound_device_config, basename##_sound_device, legacy_sound_device_config_base, legacy_sound_device_base) #define DEFINE_LEGACY_MEMORY_DEVICE(name, basename) _DEFINE_LEGACY_DEVICE(name, basename, basename##_device_config, basename##_device, legacy_memory_device_config_base, legacy_memory_device_base) #define DEFINE_LEGACY_NVRAM_DEVICE(name, basename) _DEFINE_LEGACY_DEVICE(name, basename, basename##_device_config, basename##_device, legacy_nvram_device_config_base, legacy_nvram_device_base) +#define DEFINE_LEGACY_IMAGE_DEVICE(name, basename) _DEFINE_LEGACY_DEVICE(name, basename, basename##_device_config, basename##_device, legacy_image_device_config_base, legacy_image_device_base) // macros to wrap legacy device functions @@ -346,6 +409,13 @@ typedef INT32 (*device_execute_func)(device_t *device, INT32 clocks); typedef void (*device_reset_func)(device_t *device); typedef void (*device_nvram_func)(device_t *device, mame_file *file, int read_or_write); +// device image interface function types +typedef int (*device_image_load_func)(running_device *image); +typedef int (*device_image_create_func)(running_device *image, int format_type, option_resolution *format_options); +typedef void (*device_image_unload_func)(running_device *image); +typedef void (*device_image_display_func)(running_device *image); +typedef void (*device_image_partialhash_func)(char *, const unsigned char *, unsigned long, unsigned int); +typedef void (*device_image_get_devices_func)(running_device *device); // the actual deviceinfo union union deviceinfo @@ -530,5 +600,89 @@ protected: virtual void nvram_write(mame_file &file); }; +// ======================> legacy_image_device_config +typedef struct _image_device_format image_device_format; +struct _image_device_format +{ + image_device_format *next; + int index; + const char *name; + const char *description; + const char *extensions; + const char *optspec; +}; + +struct image_config +{ + iodevice_t m_type; + bool m_readable; + bool m_writeable; + bool m_creatable; + bool m_must_be_loaded; + bool m_reset_on_load; + bool m_has_partial_hash; + const char *m_file_extensions; + const char *m_instance_name; + const char *m_brief_instance_name; + const char *m_interface_name; + + device_image_load_func load; + device_image_create_func create; + device_image_unload_func unload; + device_image_display_func display; + device_image_partialhash_func partialhash; + device_image_get_devices_func get_devices; + + /* creation info */ + const option_guide *m_create_option_guide; + image_device_format *m_formatlist; +}; +// legacy_image_device_config is a device_config with a image interface +class legacy_image_device_config_base : public legacy_device_config_base, + public device_config_image_interface +{ +public: + virtual iodevice_t image_type() const { return m_config.m_type; } + virtual const char *image_type_name() const; + virtual iodevice_t image_type_direct() const { return static_cast<iodevice_t>(get_legacy_config_int(DEVINFO_INT_IMAGE_TYPE)); } + virtual bool is_readable() const { return m_config.m_readable; } + virtual bool is_writeable() const { return m_config.m_writeable; } + virtual bool is_creatable() const { return m_config.m_creatable; } + virtual bool must_be_loaded() const { return m_config.m_must_be_loaded; } + virtual bool is_reset_on_load() const { return m_config.m_reset_on_load; } + virtual bool has_partiah_hash() const { return m_config.m_has_partial_hash; } + virtual const char *image_interface() const { return m_config.m_interface_name; } + virtual const char *file_extensions() const { return m_config.m_file_extensions; } + virtual const char *file_extensions_list() const { return core_strdup(get_legacy_config_string(DEVINFO_STR_IMAGE_FILE_EXTENSIONS)); } + virtual const char *instance_name() const { return m_config.m_instance_name; } + virtual const char *brief_instance_name() const { return m_config.m_brief_instance_name; } +protected: + // construction/destruction + legacy_image_device_config_base(const machine_config &mconfig, device_type type, const char *tag, const device_config *owner, UINT32 clock, device_get_config_func get_config); + virtual ~legacy_image_device_config_base(); + + // device_config overrides + virtual void device_config_complete(); + + image_config m_config; + const machine_config *m_mconfig; +}; + + +// ======================> legacy_image_device + +// legacy_image_device is a legacy_device_base with a image interface +class legacy_image_device_base : public legacy_device_base, + public device_image_interface +{ +protected: + // construction/destruction + legacy_image_device_base(running_machine &machine, const device_config &config); + + // device_image_interface overrides +}; + + + #endif /* __DEVLEGCY_H__ */ diff --git a/src/emu/diimage.c b/src/emu/diimage.c new file mode 100644 index 00000000000..9a6cf74ebdc --- /dev/null +++ b/src/emu/diimage.c @@ -0,0 +1,89 @@ +/*************************************************************************** + + diimage.c + + Device image interfaces. + +**************************************************************************** + + Copyright Miodrag Milanovic + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are + met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in + the documentation and/or other materials provided with the + distribution. + * Neither the name 'MAME' nor the names of its contributors may be + used to endorse or promote products derived from this software + without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY AARON GILES ''AS IS'' AND ANY EXPRESS OR + IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + DISCLAIMED. IN NO EVENT SHALL AARON GILES BE LIABLE FOR ANY DIRECT, + INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + POSSIBILITY OF SUCH DAMAGE. + +***************************************************************************/ + +#include "emu.h" + + + +//************************************************************************** +// DEVICE CONFIG IMAGE INTERFACE +//************************************************************************** + +//------------------------------------------------- +// device_config_nvram_interface - constructor +//------------------------------------------------- + +device_config_image_interface::device_config_image_interface(const machine_config &mconfig, device_config &devconfig) + : device_config_interface(mconfig, devconfig) +{ +} + + +//------------------------------------------------- +// ~device_config_image_interface - destructor +//------------------------------------------------- + +device_config_image_interface::~device_config_image_interface() +{ +} + + + +//************************************************************************** +// DEVICE image INTERFACE +//************************************************************************** + +//------------------------------------------------- +// device_image_interface - constructor +//------------------------------------------------- + +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)) +{ +} + + +//------------------------------------------------- +// ~device_image_interface - destructor +//------------------------------------------------- + +device_image_interface::~device_image_interface() +{ +} diff --git a/src/emu/diimage.h b/src/emu/diimage.h new file mode 100644 index 00000000000..5ad80884070 --- /dev/null +++ b/src/emu/diimage.h @@ -0,0 +1,91 @@ +/*************************************************************************** + + diimage.h + + Device image interfaces. + +**************************************************************************** + + Copyright Miodrag Milanovic + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are + met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in + the documentation and/or other materials provided with the + distribution. + * Neither the name 'MAME' nor the names of its contributors may be + used to endorse or promote products derived from this software + without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY AARON GILES ''AS IS'' AND ANY EXPRESS OR + IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + DISCLAIMED. IN NO EVENT SHALL AARON GILES BE LIABLE FOR ANY DIRECT, + INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + POSSIBILITY OF SUCH DAMAGE. + +***************************************************************************/ + +#pragma once + +#ifndef __EMU_H__ +#error Dont include this file directly; include emu.h instead. +#endif + +#ifndef __DIIMAGE_H__ +#define __DIIMAGE_H__ + + +//************************************************************************** +// TYPE DEFINITIONS +//************************************************************************** + + +// ======================> device_config_image_interface + +// class representing interface-specific configuration image +class device_config_image_interface : public device_config_interface +{ +public: + // construction/destruction + device_config_image_interface(const machine_config &mconfig, device_config &device); + virtual ~device_config_image_interface(); +}; + + + +// ======================> device_image_interface + +// class representing interface-specific live image +class device_image_interface : public device_interface +{ +public: + // construction/destruction + device_image_interface(running_machine &machine, const device_config &config, device_t &device); + virtual ~device_image_interface(); + + // configuration access + const device_config_image_interface &image_config() const { return m_image_config; } + + // public accessors... for now + +protected: + // derived class overrides + + // configuration + const device_config_image_interface &m_image_config; // reference to our device_config_execute_interface +}; + + +#endif /* __DIIMAGE_H__ */ diff --git a/src/emu/emu.h b/src/emu/emu.h index 3086a64b4c6..281e23235d8 100644 --- a/src/emu/emu.h +++ b/src/emu/emu.h @@ -72,6 +72,8 @@ #include "distate.h" #include "dimemory.h" #include "diexec.h" +#include "opresolv.h" +#include "diimage.h" #include "disound.h" #include "dinvram.h" #include "didisasm.h" diff --git a/src/emu/emu.mak b/src/emu/emu.mak index 7d62845c3d3..1e83756a748 100644 --- a/src/emu/emu.mak +++ b/src/emu/emu.mak @@ -50,6 +50,7 @@ EMUOBJS = \ $(EMUOBJ)/devintrf.o \ $(EMUOBJ)/didisasm.o \ $(EMUOBJ)/diexec.o \ + $(EMUOBJ)/diimage.o \ $(EMUOBJ)/dimemory.o \ $(EMUOBJ)/dinvram.o \ $(EMUOBJ)/disound.o \ @@ -70,6 +71,7 @@ EMUOBJS = \ $(EMUOBJ)/mconfig.o \ $(EMUOBJ)/memory.o \ $(EMUOBJ)/output.o \ + $(EMUOBJ)/opresolv.o \ $(EMUOBJ)/render.o \ $(EMUOBJ)/rendfont.o \ $(EMUOBJ)/rendlay.o \ diff --git a/src/emu/info.c b/src/emu/info.c index 583eb757329..85d6d3b64d0 100644 --- a/src/emu/info.c +++ b/src/emu/info.c @@ -868,6 +868,60 @@ static void print_game_categories(FILE *out, const game_driver *game, const iopo } /*------------------------------------------------- + print_game_images - prints out all info on + image devices +-------------------------------------------------*/ + +static void print_game_images(FILE *out, const game_driver *game, const machine_config *config) +{ + const device_config_image_interface *dev; + const char *name; + const char *shortname; + const char *ext; + + for (bool gotone = config->devicelist.first(dev); gotone; gotone = dev->next(dev)) + { + const legacy_image_device_config_base *info = downcast<const legacy_image_device_config_base *>(dev); + + /* print out device type */ + fprintf(out, "\t\t<device type=\"%s\"", xml_normalize_string(info->image_type_name())); + + /* does this device have a tag? */ + if (info->tag()) + fprintf(out, " tag=\"%s\"", xml_normalize_string(info->tag())); + + /* is this device mandatory? */ + if (info->must_be_loaded()) + fprintf(out, " mandatory=\"1\""); + + if (info->image_interface()[0] ) + fprintf(out, " interface=\"%s\"", xml_normalize_string(info->image_interface())); + + /* close the XML tag */ + fprintf(out, ">\n"); + + name = info->instance_name(); + shortname = info->brief_instance_name(); + + fprintf(out, "\t\t\t<instance"); + fprintf(out, " name=\"%s\"", xml_normalize_string(name)); + fprintf(out, " briefname=\"%s\"", xml_normalize_string(shortname)); + fprintf(out, "/>\n"); + + ext = info->file_extensions(); + while (*ext) + { + fprintf(out, "\t\t\t<extension"); + fprintf(out, " name=\"%s\"", xml_normalize_string(ext)); + fprintf(out, "/>\n"); + ext += strlen(ext) + 1; + } + + fprintf(out, "\t\t</device>\n"); + } +} + +/*------------------------------------------------- print_game_info - print the XML information for one particular game driver -------------------------------------------------*/ @@ -941,6 +995,7 @@ static void print_game_info(FILE *out, const game_driver *game) print_game_categories(out, game, portlist); print_game_adjusters(out, game, portlist); print_game_driver(out, game, config); + print_game_images( out, game, config ); #ifdef MESS print_mess_game_xml(out, game, config); #endif /* MESS */ @@ -971,7 +1026,7 @@ void print_mame_xml(FILE *out, const game_driver *const games[], const char *gam #ifdef MESS "\t<!ELEMENT " XML_TOP " (description, year?, manufacturer, biosset*, rom*, disk*, sample*, chip*, display*, sound?, input?, dipswitch*, configuration*, category*, adjuster*, driver?, device*, ramoption*, softwarelist*)>\n" #else - "\t<!ELEMENT " XML_TOP " (description, year?, manufacturer, biosset*, rom*, disk*, sample*, chip*, display*, sound?, input?, dipswitch*, configuration*, category*, adjuster*, driver?)>\n" + "\t<!ELEMENT " XML_TOP " (description, year?, manufacturer, biosset*, rom*, disk*, sample*, chip*, display*, sound?, input?, dipswitch*, configuration*, category*, adjuster*, driver?, device*)>\n" #endif "\t\t<!ATTLIST " XML_TOP " name CDATA #REQUIRED>\n" "\t\t<!ATTLIST " XML_TOP " sourcefile CDATA #IMPLIED>\n" @@ -1078,7 +1133,6 @@ void print_mame_xml(FILE *out, const game_driver *const games[], const char *gam "\t\t\t<!ATTLIST driver protection (good|imperfect|preliminary) #IMPLIED>\n" "\t\t\t<!ATTLIST driver savestate (supported|unsupported) #REQUIRED>\n" "\t\t\t<!ATTLIST driver palettesize CDATA #REQUIRED>\n" -#ifdef MESS "\t\t<!ELEMENT device (instance*, extension*)>\n" "\t\t\t<!ATTLIST device type CDATA #REQUIRED>\n" "\t\t\t<!ATTLIST device tag CDATA #IMPLIED>\n" @@ -1089,6 +1143,7 @@ void print_mame_xml(FILE *out, const game_driver *const games[], const char *gam "\t\t\t\t<!ATTLIST instance briefname CDATA #REQUIRED>\n" "\t\t\t<!ELEMENT extension EMPTY>\n" "\t\t\t\t<!ATTLIST extension name CDATA #REQUIRED>\n" +#ifdef MESS "\t\t<!ELEMENT ramoption (#PCDATA)>\n" "\t\t\t<!ATTLIST ramoption default CDATA #IMPLIED>\n" "\t\t<!ELEMENT softwarelist EMPTY>\n" diff --git a/src/emu/opresolv.c b/src/emu/opresolv.c new file mode 100644 index 00000000000..aa63396804e --- /dev/null +++ b/src/emu/opresolv.c @@ -0,0 +1,585 @@ +/**************************************************************************** + + opresolv.h + + Extensible ranged option resolution handling + +****************************************************************************/ + +#include <assert.h> +#include <ctype.h> +#include <stdlib.h> +#include <string.h> + +#include "pool.h" +#include "opresolv.h" +#include "emu.h" + +enum resolution_entry_state +{ + RESOLUTION_ENTRY_STATE_UNSPECIFIED, + RESOLUTION_ENTRY_STATE_SPECIFIED +}; + +struct option_resolution_entry +{ + const option_guide *guide_entry; + enum resolution_entry_state state; + union + { + int int_value; + const char *str_value; + } u; +}; + +struct _option_resolution +{ + object_pool *pool; + const char *specification; + size_t option_count; + struct option_resolution_entry *entries; +}; + + + +/* syntax errors are generally indicative of some sort of internal error */ +static void syntaxerror(const char *str) +{ +#ifdef MAME_DEBUG + logerror("Option resolution syntax error! str='%s'\n", str); +#endif +} + + + +static optreserr_t resolve_single_param(const char *specification, int *param_value, + struct OptionRange *range, size_t range_count) +{ + int FLAG_IN_RANGE = 0x01; + int FLAG_IN_DEFAULT = 0x02; + int FLAG_DEFAULT_SPECIFIED = 0x04; + int FLAG_HALF_RANGE = 0x08; + + int last_value = 0; + int value = 0; + int flags = 0; + const char *s = specification; + + while(*s && !isalpha(*s)) + { + if (*s == '-') + { + /* range specifier */ + if (flags & (FLAG_IN_RANGE|FLAG_IN_DEFAULT)) + { + syntaxerror(NULL); + return OPTIONRESOLUTION_ERROR_SYNTAX; + } + flags |= FLAG_IN_RANGE; + s++; + + if (range) + { + range->max = -1; + if ((flags & FLAG_HALF_RANGE) == 0) + { + range->min = -1; + flags |= FLAG_HALF_RANGE; + } + } + } + else if (*s == '[') + { + /* begin default value */ + if (flags & (FLAG_IN_DEFAULT|FLAG_DEFAULT_SPECIFIED)) + { + syntaxerror(NULL); + return OPTIONRESOLUTION_ERROR_SYNTAX; + } + flags |= FLAG_IN_DEFAULT; + s++; + } + else if (*s == ']') + { + /* end default value */ + if ((flags & FLAG_IN_DEFAULT) == 0) + { + syntaxerror(NULL); + return OPTIONRESOLUTION_ERROR_SYNTAX; + } + flags &= ~FLAG_IN_DEFAULT; + flags |= FLAG_DEFAULT_SPECIFIED; + s++; + + if (param_value && *param_value == -1) + *param_value = value; + } + else if (*s == '/') + { + /* value separator */ + if (flags & (FLAG_IN_DEFAULT|FLAG_IN_RANGE)) + { + syntaxerror(NULL); + return OPTIONRESOLUTION_ERROR_SYNTAX; + } + s++; + + /* if we are spitting out ranges, complete the range */ + if (range && (flags & FLAG_HALF_RANGE)) + { + range++; + flags &= ~FLAG_HALF_RANGE; + if (--range_count == 0) + range = NULL; + } + } + else if (*s == ';') + { + /* basic separator */ + s++; + } + else if (isdigit(*s)) + { + /* numeric value */ + last_value = value; + value = 0; + do + { + value *= 10; + value += *s - '0'; + s++; + } + while(isdigit(*s)); + + if (range) + { + if ((flags & FLAG_HALF_RANGE) == 0) + { + range->min = value; + flags |= FLAG_HALF_RANGE; + } + range->max = value; + } + + /* if we have a value; check to see if it is out of range */ + if (param_value && (*param_value != -1) && (*param_value != value)) + { + if ((last_value < *param_value) && (*param_value < value)) + { + if ((flags & FLAG_IN_RANGE) == 0) + return OPTIONRESOLUTION_ERROR_PARAMOUTOFRANGE; + } + } + flags &= ~FLAG_IN_RANGE; + } + else + { + syntaxerror(NULL); + return OPTIONRESOLUTION_ERROR_SYNTAX; + } + } + + /* we can't have zero length guidelines strings */ + if (s == specification) + { + syntaxerror(NULL); + return OPTIONRESOLUTION_ERROR_SYNTAX; + } + + return OPTIONRESOLUTION_ERROR_SUCCESS; +} + + + +static const char *lookup_in_specification(const char *specification, const option_guide *option) +{ + const char *s; + s = strchr(specification, option->parameter); + return s ? s + 1 : NULL; +} + + + +option_resolution *option_resolution_create(const option_guide *guide, const char *specification) +{ + option_resolution *resolution = NULL; + const option_guide *guide_entry; + int option_count; + int opt = -1; + object_pool *pool; + + assert(guide); + + /* first count the number of options specified in the guide */ + option_count = option_resolution_countoptions(guide, specification); + + /* create a memory pool for this structure */ + pool = pool_alloc_lib(NULL); + if (!pool) + goto outofmemory; + + /* allocate the main structure */ + resolution = (option_resolution *)pool_malloc_lib(pool, sizeof(option_resolution)); + if (!resolution) + goto outofmemory; + memset(resolution, 0, sizeof(*resolution)); + resolution->pool = pool; + + /* set up the entries list */ + resolution->option_count = option_count; + resolution->specification = specification; + resolution->entries = (option_resolution_entry *)pool_malloc_lib(resolution->pool, sizeof(struct option_resolution_entry) * option_count); + if (!resolution->entries) + goto outofmemory; + memset(resolution->entries, 0, sizeof(struct option_resolution_entry) * option_count); + + /* initialize each of the entries */ + opt = 0; + guide_entry = guide; + while(guide_entry->option_type != OPTIONTYPE_END) + { + switch(guide_entry->option_type) { + case OPTIONTYPE_INT: + case OPTIONTYPE_ENUM_BEGIN: + case OPTIONTYPE_STRING: + if (lookup_in_specification(specification, guide_entry)) + resolution->entries[opt++].guide_entry = guide_entry; + break; + case OPTIONTYPE_ENUM_VALUE: + break; + default: + goto unexpected; + } + guide_entry++; + } + assert(opt == option_count); + return resolution; + +unexpected: + assert(FALSE); +outofmemory: + if (resolution) + option_resolution_close(resolution); + return NULL; +} + + + +optreserr_t option_resolution_add_param(option_resolution *resolution, const char *param, const char *value) +{ + int i; + int must_resolve; + optreserr_t err; + const char *option_specification; + struct option_resolution_entry *entry = NULL; + + for (i = 0; i < resolution->option_count; i++) + { + if (!strcmp(param, resolution->entries[i].guide_entry->identifier)) + { + entry = &resolution->entries[i]; + break; + } + } + if (!entry) + return OPTIONRESOLUTION_ERROR_PARAMNOTFOUND; + + if (entry->state != RESOLUTION_ENTRY_STATE_UNSPECIFIED) + return OPTIONRESOLUTION_ERROR_PARAMALREADYSPECIFIED; + + switch(entry->guide_entry->option_type) { + case OPTIONTYPE_INT: + entry->u.int_value = atoi(value); + entry->state = RESOLUTION_ENTRY_STATE_SPECIFIED; + must_resolve = TRUE; + break; + + case OPTIONTYPE_STRING: + entry->u.str_value = pool_strdup_lib(resolution->pool, value); + if (!entry->u.str_value) + { + err = OPTIONRESOLUTION_ERROR_OUTOFMEMORY; + goto done; + } + entry->state = RESOLUTION_ENTRY_STATE_SPECIFIED; + must_resolve = FALSE; + break; + + case OPTIONTYPE_ENUM_BEGIN: + for (i = 1; entry->guide_entry[i].option_type == OPTIONTYPE_ENUM_VALUE; i++) + { + if (!mame_stricmp(value, entry->guide_entry[i].identifier)) + { + entry->u.int_value = entry->guide_entry[i].parameter; + entry->state = RESOLUTION_ENTRY_STATE_SPECIFIED; + break; + } + } + if (entry->state != RESOLUTION_ENTRY_STATE_SPECIFIED) + { + err = OPTIONRESOLUTION_ERROR_BADPARAM; + goto done; + } + must_resolve = TRUE; + break; + + default: + err = OPTIONRESOLTUION_ERROR_INTERNAL; + assert(0); + goto done; + } + + /* do a resolution step if necessary */ + if (must_resolve) + { + option_specification = lookup_in_specification(resolution->specification, entry->guide_entry); + err = resolve_single_param(option_specification, &entry->u.int_value, NULL, 0); + if (err) + goto done; + + /* did we not get a real value? */ + if (entry->u.int_value < 0) + { + err = OPTIONRESOLUTION_ERROR_PARAMNOTSPECIFIED; + goto done; + } + } + + err = OPTIONRESOLUTION_ERROR_SUCCESS; + +done: + return err; +} + + + +void option_resolution_close(option_resolution *resolution) +{ + pool_free_lib(resolution->pool); +} + + + +optreserr_t option_resolution_finish(option_resolution *resolution) +{ + int i; + optreserr_t err; + struct option_resolution_entry *entry; + const char *option_specification; + + for (i = 0; i < resolution->option_count; i++) + { + entry = &resolution->entries[i]; + + if (entry->state == RESOLUTION_ENTRY_STATE_UNSPECIFIED) + { + switch(entry->guide_entry->option_type) { + case OPTIONTYPE_INT: + case OPTIONTYPE_ENUM_BEGIN: + option_specification = lookup_in_specification(resolution->specification, entry->guide_entry); + assert(option_specification); + entry->u.int_value = -1; + err = resolve_single_param(option_specification, &entry->u.int_value, NULL, 0); + if (err) + return err; + break; + + case OPTIONTYPE_STRING: + entry->u.str_value = ""; + break; + + default: + assert(FALSE); + return OPTIONRESOLTUION_ERROR_INTERNAL; + } + entry->state = RESOLUTION_ENTRY_STATE_SPECIFIED; + } + } + return OPTIONRESOLUTION_ERROR_SUCCESS; +} + + + +static const struct option_resolution_entry *option_resolution_lookup_entry(option_resolution *resolution, int option_char) +{ + size_t i; + const struct option_resolution_entry *entry; + + for (i = 0; i < resolution->option_count; i++) + { + entry = &resolution->entries[i]; + + switch(entry->guide_entry->option_type) { + case OPTIONTYPE_INT: + case OPTIONTYPE_STRING: + case OPTIONTYPE_ENUM_BEGIN: + if (entry->guide_entry->parameter == option_char) + return entry; + break; + + default: + assert(FALSE); + return NULL; + } + } + return NULL; +} + + + +int option_resolution_lookup_int(option_resolution *resolution, int option_char) +{ + const struct option_resolution_entry *entry; + entry = option_resolution_lookup_entry(resolution, option_char); + return entry ? entry->u.int_value : -1; +} + + + +const char *option_resolution_lookup_string(option_resolution *resolution, int option_char) +{ + const struct option_resolution_entry *entry; + entry = option_resolution_lookup_entry(resolution, option_char); + return entry ? entry->u.str_value : NULL; +} + + + +const char *option_resolution_specification(option_resolution *resolution) +{ + return resolution->specification; +} + + + +const option_guide *option_resolution_find_option(option_resolution *resolution, int option_char) +{ + const struct option_resolution_entry *entry; + entry = option_resolution_lookup_entry(resolution, option_char); + return entry ? entry->guide_entry : NULL; +} + + + +const option_guide *option_resolution_index_option(option_resolution *resolution, int indx) +{ + if ((indx < 0) || (indx >= resolution->option_count)) + return NULL; + return resolution->entries[indx].guide_entry; +} + + + +int option_resolution_countoptions(const option_guide *guide, const char *specification) +{ + int option_count = 0; + + while(guide->option_type != OPTIONTYPE_END) + { + switch(guide->option_type) { + case OPTIONTYPE_INT: + case OPTIONTYPE_STRING: + case OPTIONTYPE_ENUM_BEGIN: + if (lookup_in_specification(specification, guide)) + option_count++; + break; + case OPTIONTYPE_ENUM_VALUE: + break; + default: + assert(FALSE); + return 0; + } + guide++; + } + return option_count; +} + + + +optreserr_t option_resolution_listranges(const char *specification, int option_char, + struct OptionRange *range, size_t range_count) +{ + assert(range_count > 0); + + /* clear out range */ + memset(range, -1, sizeof(*range) * range_count); + range_count--; + + specification = strchr(specification, option_char); + if (!specification) + { + syntaxerror(NULL); + return OPTIONRESOLUTION_ERROR_SYNTAX; + } + + return resolve_single_param(specification + 1, NULL, range, range_count); +} + + + +optreserr_t option_resolution_getdefault(const char *specification, int option_char, int *val) +{ + assert(val); + + /* clear out default */ + *val = -1; + + specification = strchr(specification, option_char); + if (!specification) + { + syntaxerror(NULL); + return OPTIONRESOLUTION_ERROR_SYNTAX; + } + + return resolve_single_param(specification + 1, val, NULL, 0); +} + + + +optreserr_t option_resolution_isvalidvalue(const char *specification, int option_char, int val) +{ + optreserr_t err; + struct OptionRange ranges[256]; + int i; + + err = option_resolution_listranges(specification, option_char, ranges, ARRAY_LENGTH(ranges)); + if (err) + return err; + + for (i = 0; (ranges[i].min >= 0) && (ranges[i].max >= 0); i++) + { + if ((ranges[i].min <= val) && (ranges[i].max >= val)) + return OPTIONRESOLUTION_ERROR_SUCCESS; + } + return OPTIONRESOLUTION_ERROR_PARAMOUTOFRANGE; +} + + + +int option_resolution_contains(const char *specification, int option_char) +{ + return strchr(specification, option_char) != NULL; +} + + + +const char *option_resolution_error_string(optreserr_t err) +{ + static const char *const errors[] = + { + "The operation completed successfully", /* OPTIONRESOLUTION_ERROR_SUCCESS */ + "Out of memory", /* OPTIONRESOLUTION_ERROR_OUTOFMEMORY */ + "Parameter out of range", /* OPTIONRESOLUTION_ERROR_PARAMOUTOFRANGE */ + "Parameter not specified", /* OPTIONRESOLUTION_ERROR_PARAMNOTSPECIFIED */ + "Unknown parameter", /* OPTIONRESOLUTION_ERROR_PARAMNOTFOUND */ + "Paramter specified multiple times", /* OPTIONRESOLUTION_ERROR_PARAMALREADYSPECIFIED */ + "Invalid parameter", /* OPTIONRESOLUTION_ERROR_BADPARAM */ + "Syntax error", /* OPTIONRESOLUTION_ERROR_SYNTAX */ + "Internal error" /* OPTIONRESOLTUION_ERROR_INTERNAL */ + }; + + if ((err < 0) || (err >= ARRAY_LENGTH(errors))) + return NULL; + return errors[err]; +} + diff --git a/src/emu/opresolv.h b/src/emu/opresolv.h new file mode 100644 index 00000000000..7048e8b1538 --- /dev/null +++ b/src/emu/opresolv.h @@ -0,0 +1,160 @@ +/**************************************************************************** + + opresolv.h + + Extensible ranged option resolution handling + + An extensible mechanism for handling options is a major need in MESS and + Imgtool. Unfortunately, since we are using straight C for everything, it + can be hard and awkward to create non-arcane mechanisms for representing + these options. + + In this system, we have the following concepts: + 1. An "option specification"; a string that represents what options are + available, their defaults, and their allowed ranges. Here is an + example: + + Examples: + "H[1]-2;T[35]/40/80;S[18]" + Allow 1-2 heads; 35, 40 or 80 tracks, and 18 sectors, + defaulting to 1 heads and 35 tracks. + + "N'Simon''s desk'" + Simon's desk (strings are not subject to range checking) + + 2. An "option guide"; a struct that provides information about what the + various members of the option specification mean (i.e. - H=heads) + + 3. An "option resolution"; an object that represents a set of interpreted + options. At this stage, the option bid has been processed and it is + guaranteed that all options reside in their expected ranges. + + An option_resolution object is created based on an option guide and an + option specification. It is then possible to specify individual parameters + to the option_resolution object. Argument checks occur at this time. When + one is all done, you can then query the object for any given value. + +****************************************************************************/ + +#ifndef __OPRESOLV_H__ +#define __OPRESOLV_H__ + +#include <stdlib.h> + + +/*************************************************************************** + + Type definitions + +***************************************************************************/ + +enum option_type +{ + OPTIONTYPE_END, + OPTIONTYPE_INT, + OPTIONTYPE_STRING, + OPTIONTYPE_ENUM_BEGIN, + OPTIONTYPE_ENUM_VALUE +}; + +typedef struct _option_guide option_guide; +struct _option_guide +{ + enum option_type option_type; + int parameter; + const char *identifier; + const char *display_name; +}; + +#define OPTION_GUIDE_START(option_guide_) \ + const option_guide option_guide_[] = \ + { \ + +#define OPTION_GUIDE_END \ + { OPTIONTYPE_END } \ + }; \ + +#define OPTION_GUIDE_EXTERN(option_guide_) \ + extern const option_guide option_guide_[] \ + +#define OPTION_INT(option_char, identifier, display_name) \ + { OPTIONTYPE_INT, (option_char), (identifier), (display_name) }, \ + +#define OPTION_STRING(option_char, identifier, display_name) \ + { OPTIONTYPE_STRING, (option_char), (identifier), (display_name) }, \ + +#define OPTION_ENUM_START(option_char, identifier, display_name) \ + { OPTIONTYPE_ENUM_BEGIN, (option_char), (identifier), (display_name) }, \ + +#define OPTION_ENUM(value, identifier, display_name) \ + { OPTIONTYPE_ENUM_VALUE, (value), (identifier), (display_name) }, \ + +#define OPTION_ENUM_END + + +typedef enum +{ + OPTIONRESOLUTION_ERROR_SUCCESS, + OPTIONRESOLUTION_ERROR_OUTOFMEMORY, + OPTIONRESOLUTION_ERROR_PARAMOUTOFRANGE, + OPTIONRESOLUTION_ERROR_PARAMNOTSPECIFIED, + OPTIONRESOLUTION_ERROR_PARAMNOTFOUND, + OPTIONRESOLUTION_ERROR_PARAMALREADYSPECIFIED, + OPTIONRESOLUTION_ERROR_BADPARAM, + OPTIONRESOLUTION_ERROR_SYNTAX, + OPTIONRESOLTUION_ERROR_INTERNAL +} optreserr_t; + + + +struct OptionResolutionError +{ + const option_guide *option; + optreserr_t error; +}; + + + +typedef struct _option_resolution option_resolution; + +struct OptionRange +{ + int min, max; +}; + + + +/*************************************************************************** + + Prototypes + +***************************************************************************/ + +/* processing options with option_resolution objects */ +option_resolution *option_resolution_create(const option_guide *guide, const char *specification); +optreserr_t option_resolution_add_param(option_resolution *resolution, const char *param, const char *value); +optreserr_t option_resolution_finish(option_resolution *resolution); +void option_resolution_close(option_resolution *resolution); +int option_resolution_lookup_int(option_resolution *resolution, int option_char); +const char *option_resolution_lookup_string(option_resolution *resolution, int option_char); + +/* option resolution accessors */ +const char *option_resolution_specification(option_resolution *resolution); +const option_guide *option_resolution_find_option(option_resolution *resolution, int option_char); +const option_guide *option_resolution_index_option(option_resolution *resolution, int indx); + +/* processing option guides */ +int option_resolution_countoptions(const option_guide *guide, const char *specification); + +/* processing option specifications */ +optreserr_t option_resolution_listranges(const char *specification, int option_char, + struct OptionRange *range, size_t range_count); +optreserr_t option_resolution_getdefault(const char *specification, int option_char, int *val); +optreserr_t option_resolution_isvalidvalue(const char *specification, int option_char, int val); +int option_resolution_contains(const char *specification, int option_char); + +/* misc */ +const char *option_resolution_error_string(optreserr_t err); + +#endif /* __OPRESOLV_H__ */ + |