* 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:
Vas Crabb 2017-07-21 11:47:41 +10:00
parent 431879ef2b
commit 05e84dccc0
10 changed files with 139 additions and 126 deletions

View File

@ -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;
}

View File

@ -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;

View File

@ -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;
}

View File

@ -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;
}

View File

@ -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

View File

@ -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());
}
}
}

View File

@ -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

View File

@ -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
}
}

View File

@ -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

View File

@ -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