mirror of
https://github.com/holub/mame
synced 2025-10-05 08:41:31 +03:00
* Make XML file a class of its own managed with smart poitners
* Save/restore a little more of Cocoa debugger state
This commit is contained in:
parent
431879ef2b
commit
05e84dccc0
@ -1707,7 +1707,6 @@ ti99_cartridge_device::rpk* ti99_cartridge_device::rpk_reader::open(emu_options
|
||||
util::archive_file::ptr zipfile;
|
||||
|
||||
std::vector<char> layout_text;
|
||||
util::xml::data_node *layout_xml = nullptr;
|
||||
|
||||
int i;
|
||||
|
||||
@ -1736,7 +1735,7 @@ ti99_cartridge_device::rpk* ti99_cartridge_device::rpk_reader::open(emu_options
|
||||
layout_text[zipfile->current_uncompressed_length()] = '\0'; // Null-terminate
|
||||
|
||||
/* parse the layout text */
|
||||
layout_xml = util::xml::data_node::string_read(&layout_text[0], nullptr);
|
||||
util::xml::file::ptr const layout_xml = util::xml::file::string_read(&layout_text[0], nullptr);
|
||||
if (!layout_xml) throw rpk_exception(RPK_XML_ERROR);
|
||||
|
||||
// Now we work within the XML tree
|
||||
@ -1815,14 +1814,11 @@ ti99_cartridge_device::rpk* ti99_cartridge_device::rpk_reader::open(emu_options
|
||||
catch (rpk_exception &)
|
||||
{
|
||||
newrpk->close();
|
||||
if (layout_xml) layout_xml->file_free();
|
||||
|
||||
// rethrow the exception
|
||||
throw;
|
||||
}
|
||||
|
||||
if (layout_xml) layout_xml->file_free();
|
||||
|
||||
return newrpk;
|
||||
}
|
||||
|
||||
|
@ -132,9 +132,7 @@ void configuration_manager::save_settings()
|
||||
int configuration_manager::load_xml(emu_file &file, config_type which_type)
|
||||
{
|
||||
/* read the file */
|
||||
std::unique_ptr<util::xml::data_node, void (*)(util::xml::data_node *)> const root(
|
||||
util::xml::data_node::file_read(file, nullptr),
|
||||
[] (util::xml::data_node *node) { node->file_free(); });
|
||||
util::xml::file::ptr const root(util::xml::file::read(file, nullptr));
|
||||
if (!root)
|
||||
return 0;
|
||||
|
||||
@ -225,9 +223,7 @@ int configuration_manager::load_xml(emu_file &file, config_type which_type)
|
||||
|
||||
int configuration_manager::save_xml(emu_file &file, config_type which_type)
|
||||
{
|
||||
std::unique_ptr<util::xml::data_node, void (*)(util::xml::data_node *)> const root(
|
||||
util::xml::data_node::file_create(),
|
||||
[] (util::xml::data_node *node) { node->file_free(); });
|
||||
util::xml::file::ptr root(util::xml::file::create());
|
||||
|
||||
/* if we don't have a root, bail */
|
||||
if (!root)
|
||||
@ -260,7 +256,7 @@ int configuration_manager::save_xml(emu_file &file, config_type which_type)
|
||||
}
|
||||
|
||||
/* flush the file */
|
||||
root->file_write(file);
|
||||
root->write(file);
|
||||
|
||||
/* free and get out of here */
|
||||
return 1;
|
||||
|
@ -226,8 +226,8 @@ bool debugger_cpu::comment_save()
|
||||
bool comments_saved = false;
|
||||
|
||||
// if we don't have a root, bail
|
||||
util::xml::data_node *const root = util::xml::data_node::file_create();
|
||||
if (root == nullptr)
|
||||
util::xml::file::ptr const root = util::xml::file::create();
|
||||
if (!root)
|
||||
return false;
|
||||
|
||||
// wrap in a try/catch to handle errors
|
||||
@ -269,19 +269,17 @@ bool debugger_cpu::comment_save()
|
||||
osd_file::error filerr = file.open(m_machine.basename(), ".cmt");
|
||||
if (filerr == osd_file::error::NONE)
|
||||
{
|
||||
root->file_write(file);
|
||||
root->write(file);
|
||||
comments_saved = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (emu_exception &)
|
||||
{
|
||||
root->file_free();
|
||||
return false;
|
||||
}
|
||||
|
||||
// free and get out of here
|
||||
root->file_free();
|
||||
return comments_saved;
|
||||
}
|
||||
|
||||
@ -301,11 +299,11 @@ bool debugger_cpu::comment_load(bool is_inline)
|
||||
return false;
|
||||
|
||||
// wrap in a try/catch to handle errors
|
||||
util::xml::data_node *const root = util::xml::data_node::file_read(file, nullptr);
|
||||
util::xml::file::ptr const root = util::xml::file::read(file, nullptr);
|
||||
try
|
||||
{
|
||||
// read the file
|
||||
if (root == nullptr)
|
||||
if (!root)
|
||||
throw emu_exception();
|
||||
|
||||
// find the config node
|
||||
@ -342,13 +340,10 @@ bool debugger_cpu::comment_load(bool is_inline)
|
||||
catch (emu_exception &)
|
||||
{
|
||||
// clean up in case of error
|
||||
if (root != nullptr)
|
||||
root->file_free();
|
||||
return false;
|
||||
}
|
||||
|
||||
// free the parser
|
||||
root->file_free();
|
||||
// success!
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -1700,14 +1700,16 @@ bool render_target::load_layout_file(const char *dirname, const internal_layout
|
||||
|
||||
bool render_target::load_layout_file(const char *dirname, const char *filename)
|
||||
{
|
||||
// if the first character of the "file" is an open brace, assume it is an XML string
|
||||
util::xml::data_node *rootnode;
|
||||
util::xml::file::ptr rootnode;
|
||||
if (filename[0] == '<')
|
||||
rootnode = util::xml::data_node::string_read(filename, nullptr);
|
||||
|
||||
// otherwise, assume it is a file
|
||||
{
|
||||
// if the first character of the "file" is an open brace, assume it is an XML string
|
||||
rootnode = util::xml::file::string_read(filename, nullptr);
|
||||
}
|
||||
else
|
||||
{
|
||||
// otherwise, assume it is a file
|
||||
|
||||
// build the path and optionally prepend the directory
|
||||
std::string fname = std::string(filename).append(".lay");
|
||||
if (dirname != nullptr)
|
||||
@ -1720,7 +1722,7 @@ bool render_target::load_layout_file(const char *dirname, const char *filename)
|
||||
return false;
|
||||
|
||||
// read the file
|
||||
rootnode = util::xml::data_node::file_read(layoutfile, nullptr);
|
||||
rootnode = util::xml::file::read(layoutfile, nullptr);
|
||||
}
|
||||
|
||||
// if we didn't get a properly-formatted XML file, record a warning and exit
|
||||
@ -1751,7 +1753,6 @@ bool render_target::load_layout_file(const char *dirname, const char *filename)
|
||||
emulator_info::layout_file_cb(*rootnode);
|
||||
|
||||
// free the root node
|
||||
rootnode->file_free();
|
||||
return result;
|
||||
}
|
||||
|
||||
|
@ -1403,10 +1403,10 @@ void cheat_manager::load_cheats(const char *filename)
|
||||
util::xml::parse_options options = { nullptr };
|
||||
util::xml::parse_error error;
|
||||
options.error = &error;
|
||||
std::unique_ptr<util::xml::data_node, void (*)(util::xml::data_node *)> rootnode(util::xml::data_node::file_read(cheatfile, &options), [] (util::xml::data_node *node) { node->file_free(); });
|
||||
util::xml::file::ptr const rootnode(util::xml::file::read(cheatfile, &options));
|
||||
|
||||
// if unable to parse the file, just bail
|
||||
if (rootnode == nullptr)
|
||||
if (!rootnode)
|
||||
throw emu_fatalerror("%s.xml(%d): error parsing XML (%s)\n", filename, error.error_line, error.error_message);
|
||||
|
||||
// find the layout node
|
||||
|
@ -37,7 +37,7 @@ namespace util { namespace xml {
|
||||
struct parse_info
|
||||
{
|
||||
XML_Parser parser;
|
||||
data_node * rootnode;
|
||||
file::ptr rootnode;
|
||||
data_node * curnode;
|
||||
uint32_t flags;
|
||||
};
|
||||
@ -60,31 +60,33 @@ static void expat_element_end(void *data, const XML_Char *name);
|
||||
XML FILE OBJECTS
|
||||
***************************************************************************/
|
||||
|
||||
file::file() { }
|
||||
file::~file() { }
|
||||
|
||||
|
||||
/*-------------------------------------------------
|
||||
file_create - create a new xml file
|
||||
object
|
||||
create - create a new, empty XML file
|
||||
-------------------------------------------------*/
|
||||
|
||||
data_node *data_node::file_create()
|
||||
file::ptr file::create()
|
||||
{
|
||||
try { return new data_node(); }
|
||||
catch (...) { return nullptr; }
|
||||
try { return ptr(new file()); }
|
||||
catch (...) { return ptr(); }
|
||||
}
|
||||
|
||||
|
||||
/*-------------------------------------------------
|
||||
file_read - parse an XML file into its
|
||||
nodes
|
||||
read - parse an XML file into its nodes
|
||||
-------------------------------------------------*/
|
||||
|
||||
data_node *data_node::file_read(util::core_file &file, parse_options const *opts)
|
||||
file::ptr file::read(util::core_file &file, parse_options const *opts)
|
||||
{
|
||||
parse_info info;
|
||||
int done;
|
||||
|
||||
/* set up the parser */
|
||||
if (!expat_setup_parser(info, opts))
|
||||
return nullptr;
|
||||
return ptr();
|
||||
|
||||
/* loop through the file and parse it */
|
||||
do
|
||||
@ -105,9 +107,9 @@ data_node *data_node::file_read(util::core_file &file, parse_options const *opts
|
||||
opts->error->error_column = XML_GetCurrentColumnNumber(info.parser);
|
||||
}
|
||||
|
||||
info.rootnode->file_free();
|
||||
info.rootnode.reset();
|
||||
XML_ParserFree(info.parser);
|
||||
return nullptr;
|
||||
return ptr();
|
||||
}
|
||||
}
|
||||
while (!done);
|
||||
@ -116,7 +118,7 @@ data_node *data_node::file_read(util::core_file &file, parse_options const *opts
|
||||
XML_ParserFree(info.parser);
|
||||
|
||||
/* return the root node */
|
||||
return info.rootnode;
|
||||
return std::move(info.rootnode);
|
||||
}
|
||||
|
||||
|
||||
@ -125,14 +127,14 @@ data_node *data_node::file_read(util::core_file &file, parse_options const *opts
|
||||
nodes
|
||||
-------------------------------------------------*/
|
||||
|
||||
data_node *data_node::string_read(const char *string, parse_options const *opts)
|
||||
file::ptr file::string_read(const char *string, parse_options const *opts)
|
||||
{
|
||||
parse_info info;
|
||||
int length = (int)strlen(string);
|
||||
|
||||
/* set up the parser */
|
||||
if (!expat_setup_parser(info, opts))
|
||||
return nullptr;
|
||||
return ptr();
|
||||
|
||||
/* parse the data */
|
||||
if (XML_Parse(info.parser, string, length, 1) == XML_STATUS_ERROR)
|
||||
@ -144,16 +146,16 @@ data_node *data_node::string_read(const char *string, parse_options const *opts)
|
||||
opts->error->error_column = XML_GetCurrentColumnNumber(info.parser);
|
||||
}
|
||||
|
||||
info.rootnode->file_free();
|
||||
info.rootnode.reset();
|
||||
XML_ParserFree(info.parser);
|
||||
return nullptr;
|
||||
return ptr();
|
||||
}
|
||||
|
||||
/* free the parser */
|
||||
XML_ParserFree(info.parser);
|
||||
|
||||
/* return the root node */
|
||||
return info.rootnode;
|
||||
return std::move(info.rootnode);
|
||||
}
|
||||
|
||||
|
||||
@ -161,33 +163,17 @@ data_node *data_node::string_read(const char *string, parse_options const *opts)
|
||||
file_write - write an XML tree to a file
|
||||
-------------------------------------------------*/
|
||||
|
||||
void data_node::file_write(util::core_file &file) const
|
||||
void file::write(util::core_file &file) const
|
||||
{
|
||||
/* ensure this is a root node */
|
||||
if (get_name())
|
||||
return;
|
||||
assert(!get_name());
|
||||
|
||||
/* output a simple header */
|
||||
file.printf("<?xml version=\"1.0\"?>\n");
|
||||
file.printf("<!-- This file is autogenerated; comments and unknown tags will be stripped -->\n");
|
||||
|
||||
/* loop over children of the root and output */
|
||||
for (data_node const *node = get_first_child(); node; node = node->get_next_sibling())
|
||||
node->write_recursive(0, file);
|
||||
}
|
||||
|
||||
|
||||
/*-------------------------------------------------
|
||||
file_free - free an XML file object
|
||||
-------------------------------------------------*/
|
||||
|
||||
void data_node::file_free()
|
||||
{
|
||||
/* ensure this is a root node */
|
||||
if (get_name())
|
||||
return;
|
||||
|
||||
delete this;
|
||||
write_recursive(0, file);
|
||||
}
|
||||
|
||||
|
||||
@ -211,7 +197,7 @@ data_node::data_node(data_node *parent, const char *name, const char *value)
|
||||
: line(0)
|
||||
, m_next(nullptr)
|
||||
, m_first_child(nullptr)
|
||||
, m_name(name ? name : "")
|
||||
, m_name(name)
|
||||
, m_value(value ? value : "")
|
||||
, m_parent(parent)
|
||||
, m_attributes()
|
||||
@ -356,6 +342,9 @@ data_node const *data_node::find_next_matching_sibling(const char *name, const c
|
||||
|
||||
data_node *data_node::add_child(const char *name, const char *value)
|
||||
{
|
||||
if (!name || !*name)
|
||||
return nullptr;
|
||||
|
||||
/* new element: create a new node */
|
||||
data_node *node;
|
||||
try { node = new data_node(this, name, value); }
|
||||
@ -743,10 +732,10 @@ static bool expat_setup_parser(parse_info &info, parse_options const *opts)
|
||||
}
|
||||
|
||||
/* create a root node */
|
||||
info.rootnode = data_node::file_create();
|
||||
if (info.rootnode == nullptr)
|
||||
info.rootnode = file::create();
|
||||
if (!info.rootnode)
|
||||
return false;
|
||||
info.curnode = info.rootnode;
|
||||
info.curnode = info.rootnode.get();
|
||||
|
||||
/* create the XML parser */
|
||||
memcallbacks.malloc_fcn = expat_malloc;
|
||||
@ -755,7 +744,7 @@ static bool expat_setup_parser(parse_info &info, parse_options const *opts)
|
||||
info.parser = XML_ParserCreate_MM(nullptr, &memcallbacks, nullptr);
|
||||
if (info.parser == nullptr)
|
||||
{
|
||||
info.rootnode->file_free();
|
||||
info.rootnode.reset();
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -867,36 +856,45 @@ void data_node::add_attribute(const char *name, const char *value)
|
||||
|
||||
void data_node::write_recursive(int indent, util::core_file &file) const
|
||||
{
|
||||
/* output this tag */
|
||||
file.printf("%*s<%s", indent, "", get_name());
|
||||
|
||||
/* output any attributes */
|
||||
for (attribute_node const &anode : m_attributes)
|
||||
file.printf(" %s=\"%s\"", anode.name, anode.value);
|
||||
|
||||
if (!get_first_child() && !get_value())
|
||||
if (!get_name())
|
||||
{
|
||||
/* if there are no children and no value, end the tag here */
|
||||
file.printf(" />\n");
|
||||
/* root node doesn't generate tag */
|
||||
for (data_node const *child = this->get_first_child(); child; child = child->get_next_sibling())
|
||||
child->write_recursive(indent, file);
|
||||
}
|
||||
else
|
||||
{
|
||||
/* otherwise, close this tag and output more stuff */
|
||||
file.printf(">\n");
|
||||
/* output this tag */
|
||||
file.printf("%*s<%s", indent, "", get_name());
|
||||
|
||||
/* if there is a value, output that here */
|
||||
if (get_value())
|
||||
file.printf("%*s%s\n", indent + 4, "", get_value());
|
||||
/* output any attributes */
|
||||
for (attribute_node const &anode : m_attributes)
|
||||
file.printf(" %s=\"%s\"", anode.name, anode.value);
|
||||
|
||||
/* loop over children and output them as well */
|
||||
if (get_first_child())
|
||||
if (!get_first_child() && !get_value())
|
||||
{
|
||||
for (data_node const *child = this->get_first_child(); child; child = child->get_next_sibling())
|
||||
child->write_recursive(indent + 4, file);
|
||||
/* if there are no children and no value, end the tag here */
|
||||
file.printf(" />\n");
|
||||
}
|
||||
else
|
||||
{
|
||||
/* otherwise, close this tag and output more stuff */
|
||||
file.printf(">\n");
|
||||
|
||||
/* write a closing tag */
|
||||
file.printf("%*s</%s>\n", indent, "", get_name());
|
||||
/* if there is a value, output that here */
|
||||
if (get_value())
|
||||
file.printf("%*s%s\n", indent + 4, "", get_value());
|
||||
|
||||
/* loop over children and output them as well */
|
||||
if (get_first_child())
|
||||
{
|
||||
for (data_node const *child = this->get_first_child(); child; child = child->get_next_sibling())
|
||||
child->write_recursive(indent + 4, file);
|
||||
}
|
||||
|
||||
/* write a closing tag */
|
||||
file.printf("%*s</%s>\n", indent, "", get_name());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -73,25 +73,6 @@ public:
|
||||
};
|
||||
|
||||
|
||||
|
||||
/* ----- XML file objects ----- */
|
||||
|
||||
// create a new empty xml file object
|
||||
static data_node *file_create();
|
||||
|
||||
// parse an XML file into its nodes */
|
||||
static data_node *file_read(util::core_file &file, parse_options const *opts);
|
||||
|
||||
/* parse an XML string into its nodes */
|
||||
static data_node *string_read(const char *string, parse_options const *opts);
|
||||
|
||||
// write an XML tree to a file
|
||||
void file_write(util::core_file &file) const;
|
||||
|
||||
// free an XML file object
|
||||
void file_free();
|
||||
|
||||
|
||||
/* ----- XML node management ----- */
|
||||
|
||||
char const *get_name() const { return m_name.empty() ? nullptr : m_name.c_str(); }
|
||||
@ -141,7 +122,6 @@ public:
|
||||
void delete_node();
|
||||
|
||||
|
||||
|
||||
/* ----- XML attribute management ----- */
|
||||
|
||||
// return whether a node has the specified attribute
|
||||
@ -176,6 +156,13 @@ public:
|
||||
int line; /* line number for this node's start */
|
||||
|
||||
|
||||
protected:
|
||||
data_node();
|
||||
~data_node();
|
||||
|
||||
void write_recursive(int indent, util::core_file &file) const;
|
||||
|
||||
|
||||
private:
|
||||
// a node representing an attribute
|
||||
struct attribute_node
|
||||
@ -187,9 +174,7 @@ private:
|
||||
};
|
||||
|
||||
|
||||
data_node();
|
||||
data_node(data_node *parent, const char *name, const char *value);
|
||||
~data_node();
|
||||
|
||||
data_node(data_node const &) = delete;
|
||||
data_node(data_node &&) = delete;
|
||||
@ -204,8 +189,6 @@ private:
|
||||
attribute_node *get_attribute(const char *attribute);
|
||||
attribute_node const *get_attribute(const char *attribute) const;
|
||||
|
||||
void write_recursive(int indent, util::core_file &file) const;
|
||||
|
||||
|
||||
data_node * m_next;
|
||||
data_node * m_first_child;
|
||||
@ -216,6 +199,33 @@ private:
|
||||
};
|
||||
|
||||
|
||||
// a node representing the root of a document
|
||||
class file : public data_node
|
||||
{
|
||||
public:
|
||||
using ptr = std::unique_ptr<file>;
|
||||
|
||||
|
||||
~file();
|
||||
|
||||
// create a new empty xml file object
|
||||
static ptr create();
|
||||
|
||||
// parse an XML file into its nodes
|
||||
static ptr read(util::core_file &file, parse_options const *opts);
|
||||
|
||||
// parse an XML string into its nodes
|
||||
static ptr string_read(const char *string, parse_options const *opts);
|
||||
|
||||
// write an XML tree to a file
|
||||
void write(util::core_file &file) const;
|
||||
|
||||
|
||||
private:
|
||||
file();
|
||||
};
|
||||
|
||||
|
||||
|
||||
/***************************************************************************
|
||||
FUNCTION PROTOTYPES
|
||||
|
@ -844,11 +844,14 @@ static void debugwin_view_update(debug_view &view, void *osdprivate)
|
||||
|
||||
|
||||
- (void)keyUp:(NSEvent *)event {
|
||||
debug_view_xy const pos = view->cursor_position();
|
||||
[self scrollRectToVisible:NSMakeRect((pos.x * fontWidth) + [textContainer lineFragmentPadding],
|
||||
pos.y * fontHeight,
|
||||
fontWidth,
|
||||
fontHeight)]; // FIXME: metrics
|
||||
if (view->cursor_supported() && view->cursor_visible())
|
||||
{
|
||||
debug_view_xy const pos = view->cursor_position();
|
||||
[self scrollRectToVisible:NSMakeRect((pos.x * fontWidth) + [textContainer lineFragmentPadding],
|
||||
pos.y * fontHeight,
|
||||
fontWidth,
|
||||
fontHeight)]; // FIXME: metrics
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
@ -18,7 +18,8 @@
|
||||
|
||||
@interface MAMEPointsViewer : MAMEAuxiliaryDebugWindowHandler
|
||||
{
|
||||
NSTabView *tabs;
|
||||
NSTabView *tabs;
|
||||
NSPopUpButton *subviewButton;
|
||||
}
|
||||
|
||||
- (id)initWithMachine:(running_machine &)m console:(MAMEDebugConsole *)c;
|
||||
@ -26,5 +27,6 @@
|
||||
- (IBAction)changeSubview:(id)sender;
|
||||
|
||||
- (void)saveConfigurationToNode:(util::xml::data_node *)node;
|
||||
- (void)restoreConfigurationFromNode:(util::xml::data_node const *)node;
|
||||
|
||||
@end
|
||||
|
@ -21,7 +21,7 @@
|
||||
MAMEDebugView *breakView, *watchView;
|
||||
NSScrollView *breakScroll, *watchScroll;
|
||||
NSTabViewItem *breakTab, *watchTab;
|
||||
NSPopUpButton *actionButton, *subviewButton;
|
||||
NSPopUpButton *actionButton;
|
||||
NSRect subviewFrame;
|
||||
|
||||
if (!(self = [super initWithMachine:m title:@"(Break|Watch)points" console:c]))
|
||||
@ -147,6 +147,18 @@
|
||||
- (void)saveConfigurationToNode:(util::xml::data_node *)node {
|
||||
[super saveConfigurationToNode:node];
|
||||
node->set_attribute_int("type", MAME_DEBUGGER_WINDOW_TYPE_POINTS_VIEWER);
|
||||
node->set_attribute_int("bwtype", [tabs indexOfTabViewItem:[tabs selectedTabViewItem]]);
|
||||
}
|
||||
|
||||
|
||||
- (void)restoreConfigurationFromNode:(util::xml::data_node const *)node {
|
||||
[super restoreConfigurationFromNode:node];
|
||||
int const tab = node->get_attribute_int("bwtype", [tabs indexOfTabViewItem:[tabs selectedTabViewItem]]);
|
||||
if ((0 <= tab) && ([tabs numberOfTabViewItems] > tab))
|
||||
{
|
||||
[subviewButton selectItemAtIndex:tab];
|
||||
[self changeSubview:subviewButton];
|
||||
}
|
||||
}
|
||||
|
||||
@end
|
||||
|
Loading…
Reference in New Issue
Block a user