summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
author AJR <ajrhacker@users.noreply.github.com>2021-01-01 12:18:29 -0500
committer AJR <ajrhacker@users.noreply.github.com>2021-01-01 12:22:17 -0500
commitaa29519528cb3dbdbfac56819bea670ed8c56c5d (patch)
treebdaff6e127ed377a4fc84d3e8ee1b7a99f503d0b
parent21fd9835451a5a7d7655964bfb7adb1ba9b8540f (diff)
Further additions of std::string_view
- corefile.cpp, fileio.cpp: Change puts to take a std::string_view parameter - rendlay.cpp: Use std::string_view instead of bare pointers in various functions - vecstream.h: Add std::string_view conversion operator to obtain output buffer without needing to make it a C string with explicit null termination - xmlfile.cpp: Add get_attribute_string_ptr method that distinguishes between empty strings and absent attributes without falling back to C strings
-rw-r--r--src/emu/fileio.cpp2
-rw-r--r--src/emu/fileio.h2
-rw-r--r--src/emu/image.cpp2
-rw-r--r--src/emu/rendlay.cpp307
-rw-r--r--src/frontend/mame/clifront.cpp7
-rw-r--r--src/frontend/mame/ui/inifile.cpp3
-rw-r--r--src/frontend/mame/ui/miscmenu.cpp6
-rw-r--r--src/frontend/mame/ui/ui.cpp6
-rw-r--r--src/frontend/mame/ui/utils.cpp8
-rw-r--r--src/lib/util/corefile.cpp16
-rw-r--r--src/lib/util/corefile.h3
-rw-r--r--src/lib/util/vecstream.h47
-rw-r--r--src/lib/util/xmlfile.cpp34
-rw-r--r--src/lib/util/xmlfile.h3
-rw-r--r--src/osd/modules/debugger/debuggdbstub.cpp2
15 files changed, 232 insertions, 216 deletions
diff --git a/src/emu/fileio.cpp b/src/emu/fileio.cpp
index 2a2682874c4..6149e65a048 100644
--- a/src/emu/fileio.cpp
+++ b/src/emu/fileio.cpp
@@ -622,7 +622,7 @@ u32 emu_file::write(const void *buffer, u32 length)
// puts - write a line to a text file
//-------------------------------------------------
-int emu_file::puts(const char *s)
+int emu_file::puts(std::string_view s)
{
// write the data if we can
if (m_file)
diff --git a/src/emu/fileio.h b/src/emu/fileio.h
index 20be11eb022..aaa1b564b12 100644
--- a/src/emu/fileio.h
+++ b/src/emu/fileio.h
@@ -179,7 +179,7 @@ public:
// writing
u32 write(const void *buffer, u32 length);
- int puts(const char *s);
+ int puts(std::string_view s);
int vprintf(util::format_argument_pack<std::ostream> const &args);
template <typename Format, typename... Params> int printf(Format &&fmt, Params &&...args)
{
diff --git a/src/emu/image.cpp b/src/emu/image.cpp
index 5da34b1abc5..28a704354f0 100644
--- a/src/emu/image.cpp
+++ b/src/emu/image.cpp
@@ -169,7 +169,7 @@ int image_manager::write_config(emu_options &options, const char *filename, cons
if (filerr == osd_file::error::NONE)
{
std::string inistring = options.output_ini();
- file.puts(inistring.c_str());
+ file.puts(inistring);
retval = 0;
}
return retval;
diff --git a/src/emu/rendlay.cpp b/src/emu/rendlay.cpp
index 51dd035aef2..44577c82185 100644
--- a/src/emu/rendlay.cpp
+++ b/src/emu/rendlay.cpp
@@ -378,7 +378,20 @@ private:
using entry_vector = std::vector<entry>;
- template <typename T, typename U>
+ template <typename T>
+ void try_insert(std::string &&name, T &&value)
+ {
+ entry_vector::iterator const pos(
+ std::lower_bound(
+ m_entries.begin(),
+ m_entries.end(),
+ name,
+ [] (entry const &lhs, auto const &rhs) { return lhs.name() < rhs; }));
+ if ((m_entries.end() == pos) || (pos->name() != name))
+ m_entries.emplace(pos, std::move(name), std::forward<T>(value));
+ }
+
+ template <typename T, typename U, typename = std::enable_if_t<std::is_constructible_v<std::string, T>>>
void try_insert(T &&name, U &&value)
{
entry_vector::iterator const pos(
@@ -388,7 +401,7 @@ private:
name,
[] (entry const &lhs, auto const &rhs) { return lhs.name() < rhs; }));
if ((m_entries.end() == pos) || (pos->name() != name))
- m_entries.emplace(pos, std::forward<T>(name), std::forward<U>(value));
+ m_entries.emplace(pos, std::string(name), std::forward<U>(value));
}
template <typename T, typename U>
@@ -425,33 +438,27 @@ private:
tmp.seekp(0);
util::stream_format(tmp, "scr%uphysicalxaspect", i);
- tmp.put('\0');
- try_insert(&tmp.vec()[0], s64(physaspect.first));
+ try_insert(std::string_view(tmp), s64(physaspect.first));
tmp.seekp(0);
util::stream_format(tmp, "scr%uphysicalyaspect", i);
- tmp.put('\0');
- try_insert(&tmp.vec()[0], s64(physaspect.second));
+ try_insert(std::string_view(tmp), s64(physaspect.second));
tmp.seekp(0);
util::stream_format(tmp, "scr%unativexaspect", i);
- tmp.put('\0');
- try_insert(&tmp.vec()[0], xaspect);
+ try_insert(std::string_view(tmp), xaspect);
tmp.seekp(0);
util::stream_format(tmp, "scr%unativeyaspect", i);
- tmp.put('\0');
- try_insert(&tmp.vec()[0], yaspect);
+ try_insert(std::string_view(tmp), yaspect);
tmp.seekp(0);
util::stream_format(tmp, "scr%uwidth", i);
- tmp.put('\0');
- try_insert(&tmp.vec()[0], w);
+ try_insert(std::string_view(tmp), w);
tmp.seekp(0);
util::stream_format(tmp, "scr%uheight", i);
- tmp.put('\0');
- try_insert(&tmp.vec()[0], h);
+ try_insert(std::string_view(tmp), h);
++i;
}
@@ -459,122 +466,108 @@ private:
}
}
- entry *find_entry(char const *begin, char const *end)
+ entry *find_entry(std::string_view str)
{
cache_device_entries();
entry_vector::iterator const pos(
std::lower_bound(
m_entries.begin(),
m_entries.end(),
- std::make_pair(begin, end - begin),
- [] (entry const &lhs, std::pair<char const *, std::ptrdiff_t> const &rhs)
- { return 0 > std::strncmp(lhs.name().c_str(), rhs.first, rhs.second); }));
- if ((m_entries.end() != pos) && (pos->name().length() == (end - begin)) && !std::strncmp(pos->name().c_str(), begin, end - begin))
+ str,
+ [] (entry const &lhs, std::string_view const &rhs) { return lhs.name() < rhs; }));
+ if ((m_entries.end() != pos) && pos->name() == str)
return &*pos;
else
- return m_next ? m_next->find_entry(begin, end) : nullptr;
+ return m_next ? m_next->find_entry(str) : nullptr;
}
- template <typename... T>
- std::tuple<char const *, char const *, bool> get_variable_text(T &&... args)
+ std::pair<std::string_view, bool> get_variable_text(std::string_view str)
{
- entry *const found(find_entry(std::forward<T>(args)...));
+ entry *const found(find_entry(str));
if (found)
{
- std::string const &text(found->get_text());
- char const *const begin(text.c_str());
- return std::make_tuple(begin, begin + text.length(), true);
+ return std::make_pair(std::string_view(found->get_text()), true);
}
else
{
- return std::make_tuple(nullptr, nullptr, false);
+ return std::make_pair(std::string_view(), false);
}
}
- std::pair<char const *, char const *> expand(char const *begin, char const *end)
+ std::string_view expand(std::string_view str)
{
+ constexpr char variable_start_char = '~';
+ constexpr char variable_end_char = '~';
+
// search for candidate variable references
- char const *start(begin);
- char const *pos(std::find_if(start, end, is_variable_start));
- while (pos != end)
+ std::string_view::size_type start(0);
+ for (std::string_view::size_type pos = str.find_first_of(variable_start_char); pos != std::string_view::npos; )
{
- char const *const term(std::find_if(pos + 1, end, [] (char ch) { return !is_variable_char(ch); }));
- if ((term == end) || !is_variable_end(*term))
+ auto term = std::find_if_not(str.begin() + pos + 1, str.end(), is_variable_char);
+ if ((term == str.end()) || (*term != variable_end_char))
{
// not a valid variable name - keep searching
- pos = std::find_if(term, end, is_variable_start);
+ pos = str.find_first_of(variable_start_char, term - str.begin());
}
else
{
// looks like a variable reference - try to look it up
- std::tuple<char const *, char const *, bool> const text(get_variable_text(pos + 1, term));
- if (std::get<2>(text))
+ std::pair<std::string_view, bool> const text(get_variable_text(str.substr(pos + 1, term - (str.begin() + pos + 1))));
+ if (text.second)
{
// variable found
- if (begin == start)
+ if (start == 0)
m_buffer.seekp(0);
- m_buffer.write(start, pos - start);
- m_buffer.write(std::get<0>(text), std::get<1>(text) - std::get<0>(text));
- start = term + 1;
- pos = std::find_if(start, end, is_variable_start);
+ m_buffer.write(&str[start], pos - start);
+ m_buffer.write(text.first.data(), text.first.length());
+ start = term - str.begin() + 1;
+ pos = str.find_first_of(variable_start_char, start);
}
else
{
// variable not found - move on
- pos = std::find_if(pos + 1, end, is_variable_start);
+ pos = str.find_first_of(variable_start_char, pos + 1);
}
}
}
// short-circuit the case where no substitutions were made
- if (start == begin)
+ if (start == 0)
{
- return std::make_pair(begin, end);
+ return str;
}
else
{
- m_buffer.write(start, pos - start);
- m_buffer.put('\0');
- std::vector<char> const &vec(m_buffer.vec());
- if (vec.empty())
- return std::make_pair(nullptr, nullptr);
- else
- return std::make_pair(&vec[0], &vec[0] + vec.size() - 1);
+ m_buffer.write(&str[start], str.length() - start);
+ return std::string_view(m_buffer);
}
}
- std::pair<char const *, char const *> expand(char const *str)
+ static constexpr unsigned hex_prefix(std::string_view s)
+ {
+ return ((0 != s.length()) && (s[0] == '$')) ? 1U : ((2 <= s.length()) && (s[0] == '0') && ((s[1] == 'x') || (s[1] == 'X'))) ? 2U : 0U;
+ }
+ static constexpr unsigned dec_prefix(std::string_view s)
{
- return expand(str, str + strlen(str));
+ return ((0 != s.length()) && (s[0] == '#')) ? 1U : 0U;
}
- int parse_int(char const *begin, char const *end, int defvalue)
+ int parse_int(std::string_view s, int defvalue)
{
std::istringstream stream;
stream.imbue(std::locale::classic());
int result;
- if (begin[0] == '$')
+ unsigned const hexprefix = hex_prefix(s);
+ if (hexprefix)
{
- stream.str(std::string(begin + 1, end));
+ stream.str(std::string(s.substr(hexprefix)));
unsigned uvalue;
stream >> std::hex >> uvalue;
result = int(uvalue);
}
- else if ((begin[0] == '0') && ((begin[1] == 'x') || (begin[1] == 'X')))
- {
- stream.str(std::string(begin + 2, end));
- unsigned uvalue;
- stream >> std::hex >> uvalue;
- result = int(uvalue);
- }
- else if (begin[0] == '#')
- {
- stream.str(std::string(begin + 1, end));
- stream >> result;
- }
else
{
- stream.str(std::string(begin, end));
+ stream.str(std::string(s.substr(dec_prefix(s))));
stream >> result;
}
@@ -583,21 +576,12 @@ private:
std::string parameter_name(util::xml::data_node const &node)
{
- char const *const attrib(node.get_attribute_string("name", nullptr));
+ std::string const *const attrib(node.get_attribute_string_ptr("name"));
if (!attrib)
throw layout_syntax_error("parameter lacks name attribute");
- std::pair<char const *, char const *> const expanded(expand(attrib));
- return std::string(expanded.first, expanded.second);
+ return std::string(expand(*attrib));
}
- static constexpr bool is_variable_start(char ch)
- {
- return '~' == ch;
- }
- static constexpr bool is_variable_end(char ch)
- {
- return '~' == ch;
- }
static constexpr bool is_variable_char(char ch)
{
return (('0' <= ch) && ('9' >= ch)) || (('A' <= ch) && ('Z' >= ch)) || (('a' <= ch) && ('z' >= ch)) || ('_' == ch);
@@ -658,20 +642,19 @@ public:
std::string name(parameter_name(node));
if (node.has_attribute("start") || node.has_attribute("increment") || node.has_attribute("lshift") || node.has_attribute("rshift"))
throw layout_syntax_error("start/increment/lshift/rshift attributes are only allowed for repeat parameters");
- char const *const value(node.get_attribute_string("value", nullptr));
+ std::string const *const value(node.get_attribute_string_ptr("value"));
if (!value)
throw layout_syntax_error("parameter lacks value attribute");
// expand value and stash
- std::pair<char const *, char const *> const expanded(expand(value));
- set(std::move(name), std::string(expanded.first, expanded.second));
+ set(std::move(name), std::string(expand(*value)));
}
void set_repeat_parameter(util::xml::data_node const &node, bool init)
{
// two types are allowed here - static value, and start/increment/lshift/rshift
std::string name(parameter_name(node));
- char const *const start(node.get_attribute_string("start", nullptr));
+ std::string const *const start(node.get_attribute_string_ptr("start"));
if (start)
{
// simple validity checks
@@ -685,14 +668,14 @@ public:
// increment is more complex - it may be an integer or a floating-point number
s64 intincrement(0);
double floatincrement(0);
- char const *const increment(node.get_attribute_string("increment", nullptr));
+ std::string const *const increment(node.get_attribute_string_ptr("increment"));
if (increment)
{
- std::pair<char const *, char const *> const expanded(expand(increment));
- unsigned const hexprefix((expanded.first[0] == '$') ? 1U : ((expanded.first[0] == '0') && ((expanded.first[1] == 'x') || (expanded.first[1] == 'X'))) ? 2U : 0U);
- unsigned const decprefix((expanded.first[0] == '#') ? 1U : 0U);
- bool const floatchars(std::find_if(expanded.first, expanded.second, [] (char ch) { return ('.' == ch) || ('e' == ch) || ('E' == ch); }) != expanded.second);
- std::istringstream stream(std::string(expanded.first + hexprefix + decprefix, expanded.second));
+ std::string_view const expanded(expand(*increment));
+ unsigned const hexprefix(hex_prefix(expanded));
+ unsigned const decprefix(dec_prefix(expanded));
+ bool const floatchars(expanded.find_first_of(".eE") != std::string_view::npos);
+ std::istringstream stream(std::string(expanded.substr(hexprefix + decprefix)));
stream.imbue(std::locale::classic());
if (!hexprefix && !decprefix && floatchars)
{
@@ -726,11 +709,10 @@ public:
if ((m_entries.end() != pos) && (pos->name() == name))
throw layout_syntax_error("generator parameters must be defined exactly once per scope");
- std::pair<char const *, char const *> const expanded(expand(start));
if (floatincrement)
- m_entries.emplace(pos, std::move(name), std::string(expanded.first, expanded.second), floatincrement, lshift - rshift);
+ m_entries.emplace(pos, std::move(name), std::string(expand(*start)), floatincrement, lshift - rshift);
else
- m_entries.emplace(pos, std::move(name), std::string(expanded.first, expanded.second), intincrement, lshift - rshift);
+ m_entries.emplace(pos, std::move(name), std::string(expand(*start)), intincrement, lshift - rshift);
}
}
else if (node.has_attribute("increment") || node.has_attribute("lshift") || node.has_attribute("rshift"))
@@ -739,10 +721,9 @@ public:
}
else
{
- char const *const value(node.get_attribute_string("value", nullptr));
+ std::string const *const value(node.get_attribute_string_ptr("value"));
if (!value)
throw layout_syntax_error("parameter lacks value attribute");
- std::pair<char const *, char const *> const expanded(expand(value));
entry_vector::iterator const pos(
std::lower_bound(
m_entries.begin(),
@@ -750,11 +731,11 @@ public:
name,
[] (entry const &lhs, auto const &rhs) { return lhs.name() < rhs; }));
if ((m_entries.end() == pos) || (pos->name() != name))
- m_entries.emplace(pos, std::move(name), std::string(expanded.first, expanded.second));
+ m_entries.emplace(pos, std::move(name), std::string(expand(*value)));
else if (pos->is_generator())
throw layout_syntax_error("generator parameters must be defined exactly once per scope");
else
- pos->set(std::string(expanded.first, expanded.second));
+ pos->set(std::string(expand(*value)));
}
}
@@ -774,32 +755,36 @@ public:
m_entries.end());
}
- char const *get_attribute_string(util::xml::data_node const &node, char const *name, char const *defvalue)
+ std::string_view get_attribute_string(util::xml::data_node const &node, char const *name, std::string_view defvalue = std::string_view())
{
- char const *const attrib(node.get_attribute_string(name, nullptr));
- return attrib ? expand(attrib).first : defvalue;
+ std::string const *const attrib(node.get_attribute_string_ptr(name));
+ return attrib ? expand(*attrib) : defvalue;
+ }
+
+ std::string get_attribute_subtag(util::xml::data_node const &node, char const *name)
+ {
+ std::string const *const attrib(node.get_attribute_string_ptr(name));
+ return attrib ? device().subtag(std::string(expand(*attrib)).c_str()) : std::string();
}
int get_attribute_int(util::xml::data_node const &node, const char *name, int defvalue)
{
- char const *const attrib(node.get_attribute_string(name, nullptr));
+ std::string const *const attrib(node.get_attribute_string_ptr(name));
if (!attrib)
return defvalue;
// similar to what XML nodes do
- std::pair<char const *, char const *> const expanded(expand(attrib));
- return parse_int(expanded.first, expanded.second, defvalue);
+ return parse_int(expand(*attrib), defvalue);
}
float get_attribute_float(util::xml::data_node const &node, char const *name, float defvalue)
{
- char const *const attrib(node.get_attribute_string(name, nullptr));
+ std::string const *const attrib(node.get_attribute_string_ptr(name));
if (!attrib)
return defvalue;
// similar to what XML nodes do
- std::pair<char const *, char const *> const expanded(expand(attrib));
- std::istringstream stream(std::string(expanded.first, expanded.second));
+ std::istringstream stream(std::string(expand(*attrib)));
stream.imbue(std::locale::classic());
float result;
return (stream >> result) ? result : defvalue;
@@ -807,19 +792,19 @@ public:
bool get_attribute_bool(util::xml::data_node const &node, char const *name, bool defvalue)
{
- char const *const attrib(node.get_attribute_string(name, nullptr));
+ std::string const *const attrib(node.get_attribute_string_ptr(name));
if (!attrib)
return defvalue;
// first try yes/no strings
- std::pair<char const *, char const *> const expanded(expand(attrib));
- if (!std::strcmp("yes", expanded.first) || !std::strcmp("true", expanded.first))
+ std::string_view const expanded(expand(*attrib));
+ if ("yes" == expanded || "true" == expanded)
return true;
- if (!std::strcmp("no", expanded.first) || !std::strcmp("false", expanded.first))
+ if ("no" == expanded || "false" == expanded)
return false;
// fall back to integer parsing
- return parse_int(expanded.first, expanded.second, defvalue ? 1 : 0) != 0;
+ return parse_int(expanded, defvalue ? 1 : 0) != 0;
}
void parse_bounds(util::xml::data_node const *node, render_bounds &result)
@@ -1327,8 +1312,8 @@ void layout_group::resolve_bounds(environment &env, group_map &groupmap, std::ve
// a wild loop appears!
std::ostringstream path;
for (layout_group const *const group : seen)
- path << ' ' << group->m_groupnode.get_attribute_string("name", nullptr);
- path << ' ' << m_groupnode.get_attribute_string("name", nullptr);
+ path << ' ' << group->m_groupnode.get_attribute_string("name", "");
+ path << ' ' << m_groupnode.get_attribute_string("name", "");
throw layout_syntax_error(util::string_format("recursively nested groups %s", path.str()));
}
@@ -1429,9 +1414,9 @@ void layout_group::resolve_bounds(
}
else
{
- char const *ref(env.get_attribute_string(*itemnode, "ref", nullptr));
- if (!ref)
- throw layout_syntax_error("nested group must have ref attribute");
+ std::string const ref(env.get_attribute_string(*itemnode, "ref"));
+ if (ref.empty())
+ throw layout_syntax_error("nested group must have non-empty ref attribute");
group_map::iterator const found(groupmap.find(ref));
if (groupmap.end() == found)
@@ -1471,7 +1456,7 @@ void layout_group::resolve_bounds(
}
else if (!strcmp(itemnode->get_name(), "collection"))
{
- if (!env.get_attribute_string(*itemnode, "name", nullptr))
+ if (!itemnode->has_attribute("name"))
throw layout_syntax_error("collection must have name attribute");
environment local(env);
resolve_bounds(local, *itemnode, groupmap, seen, empty, true, false, true);
@@ -1565,8 +1550,8 @@ public:
, m_rasterizer(env.svg_rasterizer())
, m_searchpath(env.search_path() ? env.search_path() : "")
, m_dirname(env.directory_name() ? env.directory_name() : "")
- , m_imagefile(env.get_attribute_string(compnode, "file", ""))
- , m_alphafile(env.get_attribute_string(compnode, "alphafile", ""))
+ , m_imagefile(env.get_attribute_string(compnode, "file"))
+ , m_alphafile(env.get_attribute_string(compnode, "alphafile"))
, m_data(get_data(compnode))
{
}
@@ -2287,7 +2272,7 @@ public:
text_component(environment &env, util::xml::data_node const &compnode)
: component(env, compnode)
{
- m_string = env.get_attribute_string(compnode, "string", "");
+ m_string = env.get_attribute_string(compnode, "string");
m_textalign = env.get_attribute_int(compnode, "align", 0);
}
@@ -3009,14 +2994,14 @@ public:
, m_searchpath(env.search_path() ? env.search_path() : "")
, m_dirname(env.directory_name() ? env.directory_name() : "")
{
- std::string symbollist = env.get_attribute_string(compnode, "symbollist", "0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15");
+ std::string_view symbollist = env.get_attribute_string(compnode, "symbollist", "0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15");
// split out position names from string and figure out our number of symbols
m_numstops = 0;
- for (std::string::size_type location = symbollist.find(','); std::string::npos != location; location = symbollist.find(','))
+ for (std::string_view::size_type location = symbollist.find(','); std::string_view::npos != location; location = symbollist.find(','))
{
m_stopnames[m_numstops] = symbollist.substr(0, location);
- symbollist.erase(0, location + 1);
+ symbollist.remove_prefix(location + 1);
m_numstops++;
}
m_stopnames[m_numstops++] = symbollist;
@@ -3476,7 +3461,7 @@ layout_element::texture &layout_element::texture::operator=(texture &&that)
//-------------------------------------------------
layout_element::component::component(environment &env, util::xml::data_node const &compnode)
- : m_statemask(env.get_attribute_int(compnode, "statemask", env.get_attribute_string(compnode, "state", "")[0] ? ~0 : 0))
+ : m_statemask(env.get_attribute_int(compnode, "statemask", env.get_attribute_string(compnode, "state").empty() ? 0 : ~0))
, m_stateval(env.get_attribute_int(compnode, "state", m_statemask) & m_statemask)
{
for (util::xml::data_node const *child = compnode.get_first_child(); child; child = child->get_next_sibling())
@@ -3942,7 +3927,7 @@ layout_view::layout_view(
group_map &groupmap)
: m_effaspect(1.0f)
, m_name(make_name(env, viewnode))
- , m_unqualified_name(env.get_attribute_string(viewnode, "name", ""))
+ , m_unqualified_name(env.get_attribute_string(viewnode, "name"))
, m_defvismask(0U)
, m_has_art(false)
{
@@ -4360,9 +4345,9 @@ void layout_view::add_items(
}
else if (!strcmp(itemnode->get_name(), "group"))
{
- char const *ref(env.get_attribute_string(*itemnode, "ref", nullptr));
- if (!ref)
- throw layout_syntax_error("group instantiation must have ref attribute");
+ std::string const ref(env.get_attribute_string(*itemnode, "ref"));
+ if (ref.empty())
+ throw layout_syntax_error("group instantiation must have non-empty ref attribute");
group_map::iterator const found(groupmap.find(ref));
if (groupmap.end() == found)
@@ -4413,9 +4398,9 @@ void layout_view::add_items(
}
else if (!strcmp(itemnode->get_name(), "collection"))
{
- char const *name(env.get_attribute_string(*itemnode, "name", nullptr));
- if (!name)
- throw layout_syntax_error("collection must have name attribute");
+ std::string_view const name(env.get_attribute_string(*itemnode, "name"));
+ if (name.empty())
+ throw layout_syntax_error("collection must have non-empty name attribute");
auto const found(std::find_if(m_vistoggles.begin(), m_vistoggles.end(), [name] (auto const &x) { return x.name() == name; }));
if (m_vistoggles.end() != found)
@@ -4423,7 +4408,7 @@ void layout_view::add_items(
m_defvismask |= u32(env.get_attribute_bool(*itemnode, "visible", true) ? 1 : 0) << m_vistoggles.size(); // TODO: make this less hacky
view_environment local(env, true);
- m_vistoggles.emplace_back(name, local.visibility_mask());
+ m_vistoggles.emplace_back(std::string(name), local.visibility_mask());
add_items(layers, local, *itemnode, elemmap, groupmap, orientation, trans, color, false, false, true);
}
else
@@ -4441,13 +4426,13 @@ void layout_view::add_items(
std::string layout_view::make_name(layout_environment &env, util::xml::data_node const &viewnode)
{
- char const *const name(env.get_attribute_string(viewnode, "name", nullptr));
- if (!name || !*name)
+ std::string_view const name(env.get_attribute_string(viewnode, "name"));
+ if (name.empty())
throw layout_syntax_error("view must have non-empty name attribute");
if (env.is_root_device())
{
- return name;
+ return std::string(name);
}
else
{
@@ -4476,7 +4461,7 @@ layout_view::item::item(
layout_group::transform const &trans,
render_color const &color)
: m_element(find_element(env, itemnode, elemmap))
- , m_output(env.device(), env.get_attribute_string(itemnode, "name", ""))
+ , m_output(env.device(), std::string(env.get_attribute_string(itemnode, "name")))
, m_animoutput(env.device(), make_animoutput_tag(env, itemnode))
, m_animinput_port(nullptr)
, m_elem_state(m_element ? m_element->default_state() : 0)
@@ -4492,14 +4477,14 @@ layout_view::item::item(
, m_color(make_color(env, itemnode, color))
, m_blend_mode(get_blend_mode(env, itemnode))
, m_visibility_mask(env.visibility_mask())
- , m_id(env.get_attribute_string(itemnode, "id", ""))
+ , m_id(env.get_attribute_string(itemnode, "id"))
, m_input_tag(make_input_tag(env, itemnode))
, m_animinput_tag(make_animinput_tag(env, itemnode))
, m_rawbounds(make_bounds(env, itemnode, trans))
- , m_have_output(env.get_attribute_string(itemnode, "name", "")[0])
+ , m_have_output(!env.get_attribute_string(itemnode, "name").empty())
, m_input_raw(env.get_attribute_bool(itemnode, "inputraw", 0))
, m_have_animoutput(!make_animoutput_tag(env, itemnode).empty())
- , m_has_clickthrough(env.get_attribute_string(itemnode, "clickthrough", "")[0])
+ , m_has_clickthrough(!env.get_attribute_string(itemnode, "clickthrough").empty())
{
// fetch common data
int index = env.get_attribute_int(itemnode, "index", -1);
@@ -4511,8 +4496,8 @@ layout_view::item::item(
{
if (itemnode.has_attribute("tag"))
{
- char const *const tag(env.get_attribute_string(itemnode, "tag", ""));
- m_screen = dynamic_cast<screen_device *>(env.device().subdevice(tag));
+ std::string_view const tag(env.get_attribute_string(itemnode, "tag"));
+ m_screen = dynamic_cast<screen_device *>(env.device().subdevice(std::string(tag).c_str()));
if (!m_screen)
throw layout_reference_error(util::string_format("invalid screen tag '%d'", tag));
}
@@ -4523,7 +4508,7 @@ layout_view::item::item(
}
else if (!m_element)
{
- throw layout_syntax_error(util::string_format("item of type %s require an element tag", itemnode.get_name()));
+ throw layout_syntax_error(util::string_format("item of type %s requires an element tag", itemnode.get_name()));
}
// this can be called before resolving tags, make it return something valid
@@ -4817,8 +4802,8 @@ void layout_view::item::get_interpolated_color(render_color &result) const
layout_element *layout_view::item::find_element(view_environment &env, util::xml::data_node const &itemnode, element_map &elemmap)
{
- char const *const name(env.get_attribute_string(itemnode, !strcmp(itemnode.get_name(), "element") ? "ref" : "element", nullptr));
- if (!name)
+ std::string const name(env.get_attribute_string(itemnode, !strcmp(itemnode.get_name(), "element") ? "ref" : "element"));
+ if (name.empty())
return nullptr;
// search the list of elements for a match, error if not found
@@ -4905,7 +4890,7 @@ std::string layout_view::item::make_animoutput_tag(view_environment &env, util::
{
util::xml::data_node const *const animate(itemnode.get_child("animate"));
if (animate)
- return env.get_attribute_string(*animate, "name", "");
+ return std::string(env.get_attribute_string(*animate, "name"));
else
return std::string();
}
@@ -4930,8 +4915,7 @@ ioport_value layout_view::item::make_animmask(view_environment &env, util::xml::
std::string layout_view::item::make_animinput_tag(view_environment &env, util::xml::data_node const &itemnode)
{
util::xml::data_node const *const animate(itemnode.get_child("animate"));
- char const *tag(animate ? env.get_attribute_string(*animate, "inputtag", nullptr) : nullptr);
- return tag ? env.device().subtag(tag) : std::string();
+ return animate ? env.get_attribute_subtag(*animate, "inputtag") : std::string();
}
@@ -4941,8 +4925,7 @@ std::string layout_view::item::make_animinput_tag(view_environment &env, util::x
std::string layout_view::item::make_input_tag(view_environment &env, util::xml::data_node const &itemnode)
{
- char const *tag(env.get_attribute_string(itemnode, "inputtag", nullptr));
- return tag ? env.device().subtag(tag) : std::string();
+ return env.get_attribute_subtag(itemnode, "inputtag");
}
@@ -4953,19 +4936,19 @@ std::string layout_view::item::make_input_tag(view_environment &env, util::xml::
int layout_view::item::get_blend_mode(view_environment &env, util::xml::data_node const &itemnode)
{
// see if there's a blend mode attribute
- char const *const mode(env.get_attribute_string(itemnode, "blend", nullptr));
+ std::string const *const mode(itemnode.get_attribute_string_ptr("blend"));
if (mode)
{
- if (!strcmp(mode, "none"))
+ if (*mode == "none")
return BLENDMODE_NONE;
- else if (!strcmp(mode, "alpha"))
+ else if (*mode == "alpha")
return BLENDMODE_ALPHA;
- else if (!strcmp(mode, "multiply"))
+ else if (*mode == "multiply")
return BLENDMODE_RGB_MULTIPLY;
- else if (!strcmp(mode, "add"))
+ else if (*mode == "add")
return BLENDMODE_ADD;
else
- throw layout_syntax_error(util::string_format("unknown blend mode %s", mode));
+ throw layout_syntax_error(util::string_format("unknown blend mode %s", *mode));
}
// fall back to implicit blend mode based on element type
@@ -5060,7 +5043,7 @@ layout_file::layout_file(
}
catch (layout_reference_error const &err)
{
- osd_printf_warning("Error instantiating layout view %s: %s\n", env.get_attribute_string(*viewnode, "name", ""), err.what());
+ osd_printf_warning("Error instantiating layout view %s: %s\n", env.get_attribute_string(*viewnode, "name"), err.what());
}
}
@@ -5132,17 +5115,17 @@ void layout_file::add_elements(
}
else if (!strcmp(childnode->get_name(), "element"))
{
- char const *const name(env.get_attribute_string(*childnode, "name", nullptr));
- if (!name)
- throw layout_syntax_error("element lacks name attribute");
+ std::string_view const name(env.get_attribute_string(*childnode, "name"));
+ if (name.empty())
+ throw layout_syntax_error("element must have non-empty name attribute");
if (!m_elemmap.emplace(std::piecewise_construct, std::forward_as_tuple(name), std::forward_as_tuple(env, *childnode)).second)
throw layout_syntax_error(util::string_format("duplicate element name %s", name));
}
else if (!strcmp(childnode->get_name(), "group"))
{
- char const *const name(env.get_attribute_string(*childnode, "name", nullptr));
- if (!name)
- throw layout_syntax_error("group lacks name attribute");
+ std::string_view const name(env.get_attribute_string(*childnode, "name"));
+ if (name.empty())
+ throw layout_syntax_error("group must have non-empty name attribute");
if (!groupmap.emplace(std::piecewise_construct, std::forward_as_tuple(name), std::forward_as_tuple(*childnode)).second)
throw layout_syntax_error(util::string_format("duplicate group name %s", name));
}
diff --git a/src/frontend/mame/clifront.cpp b/src/frontend/mame/clifront.cpp
index c284fc879d5..cf5bd408151 100644
--- a/src/frontend/mame/clifront.cpp
+++ b/src/frontend/mame/clifront.cpp
@@ -1085,7 +1085,6 @@ const char cli_frontend::s_softlist_xml_dtd[] =
void cli_frontend::output_single_softlist(std::ostream &out, software_list_device &swlistdev)
{
- util::stream_format(out, "\t<softwarelist name=\"%s\" description=\"%s\">\n", swlistdev.list_name(), util::xml::normalize_string(swlistdev.description().c_str()));
for (const software_info &swinfo : swlistdev.get_info())
{
util::stream_format(out, "\t\t<software name=\"%s\"", util::xml::normalize_string(swinfo.shortname().c_str()));
@@ -1655,7 +1654,7 @@ void cli_frontend::execute_commands(const char *exename)
throw emu_fatalerror("Unable to create file %s.ini\n",emulator_info::get_configname());
// generate the updated INI
- file.puts(m_options.output_ini().c_str());
+ file.puts(m_options.output_ini());
ui_options ui_opts;
emu_file file_ui(OPEN_FLAG_WRITE | OPEN_FLAG_CREATE | OPEN_FLAG_CREATE_PATHS);
@@ -1663,7 +1662,7 @@ void cli_frontend::execute_commands(const char *exename)
throw emu_fatalerror("Unable to create file ui.ini\n");
// generate the updated INI
- file_ui.puts(ui_opts.output_ini().c_str());
+ file_ui.puts(ui_opts.output_ini());
plugin_options plugin_opts;
path_iterator iter(m_options.plugins_path());
@@ -1678,7 +1677,7 @@ void cli_frontend::execute_commands(const char *exename)
throw emu_fatalerror("Unable to create file plugin.ini\n");
// generate the updated INI
- file_plugin.puts(plugin_opts.output_ini().c_str());
+ file_plugin.puts(plugin_opts.output_ini());
return;
}
diff --git a/src/frontend/mame/ui/inifile.cpp b/src/frontend/mame/ui/inifile.cpp
index 77dfd1088dc..1bcdce69aba 100644
--- a/src/frontend/mame/ui/inifile.cpp
+++ b/src/frontend/mame/ui/inifile.cpp
@@ -570,8 +570,7 @@ void favorite_manager::save_favorites()
buf << info.devicetype << '\n';
util::stream_format(buf, "%d\n", info.available);
- buf.put('\0');
- file.puts(&buf.vec()[0]);
+ file.puts(std::string_view(buf));
}
}
file.close();
diff --git a/src/frontend/mame/ui/miscmenu.cpp b/src/frontend/mame/ui/miscmenu.cpp
index b9b55264ca4..1c917e3aefe 100644
--- a/src/frontend/mame/ui/miscmenu.cpp
+++ b/src/frontend/mame/ui/miscmenu.cpp
@@ -640,7 +640,7 @@ void menu_export::handle()
// iterate through drivers and output the info
while (drvlist.next())
util::stream_format(buffer, "%-18s\"%s\"\n", drvlist.driver().name, drvlist.driver().type.fullname());
- file.puts(buffer.str().c_str());
+ file.puts(buffer.str());
file.close();
machine().popmessage(_("%s.txt saved under ui folder."), filename);
}
@@ -728,7 +728,7 @@ void menu_machine_configure::handle()
if (filerr == osd_file::error::NONE)
{
std::string inistring = m_opts.output_ini();
- file.puts(inistring.c_str());
+ file.puts(inistring);
ui().popup_time(2, "%s", _("\n Configuration saved \n\n"));
}
}
@@ -868,7 +868,7 @@ menu_plugins_configure::~menu_plugins_configure()
// throw emu_fatalerror("Unable to create file plugin.ini\n");
return;
// generate the updated INI
- file_plugin.puts(mame_machine_manager::instance()->plugins().output_ini().c_str());
+ file_plugin.puts(mame_machine_manager::instance()->plugins().output_ini());
}
//-------------------------------------------------
diff --git a/src/frontend/mame/ui/ui.cpp b/src/frontend/mame/ui/ui.cpp
index 64f68d92049..e2ea6745f86 100644
--- a/src/frontend/mame/ui/ui.cpp
+++ b/src/frontend/mame/ui/ui.cpp
@@ -2262,8 +2262,7 @@ void mame_ui_manager::save_ui_options()
if (file.open("ui.ini") == osd_file::error::NONE)
{
// generate the updated INI
- std::string initext = options().output_ini();
- file.puts(initext.c_str());
+ file.puts(options().output_ini());
file.close();
}
else
@@ -2321,8 +2320,7 @@ void mame_ui_manager::save_main_option()
if (file.open(std::string(emulator_info::get_configname()) + ".ini") == osd_file::error::NONE)
{
// generate the updated INI
- std::string initext = options.output_ini();
- file.puts(initext.c_str());
+ file.puts(options.output_ini());
file.close();
}
else {
diff --git a/src/frontend/mame/ui/utils.cpp b/src/frontend/mame/ui/utils.cpp
index a1f0e11051b..52833a37252 100644
--- a/src/frontend/mame/ui/utils.cpp
+++ b/src/frontend/mame/ui/utils.cpp
@@ -124,7 +124,7 @@ public:
virtual void save_ini(emu_file &file, unsigned indent) const override
{
- file.puts(util::string_format("%2$*1$s%3$s = 1\n", 2 * indent, "", config_name()).c_str());
+ file.puts(util::string_format("%2$*1$s%3$s = 1\n", 2 * indent, "", config_name()));
}
virtual typename Base::type get_type() const override { return Type; }
@@ -203,7 +203,7 @@ public:
virtual void save_ini(emu_file &file, unsigned indent) const override
{
char const *const text(filter_text());
- file.puts(util::string_format("%2$*1$s%3$s = %4$s\n", 2 * indent, "", this->config_name(), text ? text : "").c_str());
+ file.puts(util::string_format("%2$*1$s%3$s = %4$s\n", 2 * indent, "", this->config_name(), text ? text : ""));
}
protected:
@@ -247,7 +247,7 @@ public:
virtual void save_ini(emu_file &file, unsigned indent) const override
{
auto const tail(std::find_if(std::begin(m_filters), std::end(m_filters), [] (typename Base::ptr const &flt) { return !flt; }));
- file.puts(util::string_format("%2$*1$s%3$s = %4$d\n", 2 * indent, "", this->config_name(), std::distance(std::begin(m_filters), tail)).c_str());
+ file.puts(util::string_format("%2$*1$s%3$s = %4$d\n", 2 * indent, "", this->config_name(), std::distance(std::begin(m_filters), tail)));
for (auto it = std::begin(m_filters); tail != it; ++it)
(*it)->save_ini(file, indent + 1);
}
@@ -883,7 +883,7 @@ public:
virtual void save_ini(emu_file &file, unsigned indent) const override
{
char const *const text(filter_text());
- file.puts(util::string_format("%2$*1$s%3$s = %4$s\n", 2 * indent, "", this->config_name(), text ? text : "").c_str());
+ file.puts(util::string_format("%2$*1$s%3$s = %4$s\n", 2 * indent, "", this->config_name(), text ? text : ""));
}
virtual bool apply(ui_system_info const &system) const override
diff --git a/src/lib/util/corefile.cpp b/src/lib/util/corefile.cpp
index 2de0d7c378d..fe0747c66a8 100644
--- a/src/lib/util/corefile.cpp
+++ b/src/lib/util/corefile.cpp
@@ -158,7 +158,7 @@ public:
virtual const void *buffer() override { return m_file.buffer(); }
virtual std::uint32_t write(const void *buffer, std::uint32_t length) override { return m_file.write(buffer, length); }
- virtual int puts(const char *s) override { return m_file.puts(s); }
+ virtual int puts(std::string_view s) override { return m_file.puts(s); }
virtual int vprintf(util::format_argument_pack<std::ostream> const &args) override { return m_file.vprintf(args); }
virtual osd_file::error truncate(std::uint64_t offset) override { return m_file.truncate(offset); }
@@ -185,7 +185,7 @@ public:
virtual int getc() override;
virtual int ungetc(int c) override;
virtual char *gets(char *s, int n) override;
- virtual int puts(char const *s) override;
+ virtual int puts(std::string_view s) override;
virtual int vprintf(util::format_argument_pack<std::ostream> const &args) override;
protected:
@@ -542,7 +542,7 @@ char *core_text_file::gets(char *s, int n)
puts - write a line to a text file
-------------------------------------------------*/
-int core_text_file::puts(char const *s)
+int core_text_file::puts(std::string_view s)
{
char convbuf[1024];
char *pconvbuf = convbuf;
@@ -557,9 +557,9 @@ int core_text_file::puts(char const *s)
}
// convert '\n' to platform dependant line endings
- while (*s != '\0')
+ for (char ch : s)
{
- if (*s == '\n')
+ if (ch == '\n')
{
if (CRLF == 1) // CR only
*pconvbuf++ = 13;
@@ -572,8 +572,7 @@ int core_text_file::puts(char const *s)
}
}
else
- *pconvbuf++ = *s;
- s++;
+ *pconvbuf++ = ch;
// if we overflow, break into chunks
if (pconvbuf >= convbuf + ARRAY_LENGTH(convbuf) - 10)
@@ -601,8 +600,7 @@ int core_text_file::vprintf(util::format_argument_pack<std::ostream> const &args
m_printf_buffer.reserve(1024);
m_printf_buffer.seekp(0, ovectorstream::beg);
util::stream_format<std::ostream, std::ostream>(m_printf_buffer, args);
- m_printf_buffer.put('\0');
- return puts(&m_printf_buffer.vec()[0]);
+ return puts(std::string_view(m_printf_buffer));
}
diff --git a/src/lib/util/corefile.h b/src/lib/util/corefile.h
index d286cb866ac..3af0bddafb6 100644
--- a/src/lib/util/corefile.h
+++ b/src/lib/util/corefile.h
@@ -20,6 +20,7 @@
#include <cstdint>
#include <memory>
#include <string>
+#include <string_view>
namespace util {
@@ -111,7 +112,7 @@ public:
virtual std::uint32_t write(const void *buffer, std::uint32_t length) = 0;
// write a line of text to the file
- virtual int puts(const char *s) = 0;
+ virtual int puts(std::string_view s) = 0;
// printf-style text write to a file
virtual int vprintf(util::format_argument_pack<std::ostream> const &args) = 0;
diff --git a/src/lib/util/vecstream.h b/src/lib/util/vecstream.h
index 1af7dd0cd86..863bf39d94a 100644
--- a/src/lib/util/vecstream.h
+++ b/src/lib/util/vecstream.h
@@ -28,6 +28,7 @@
#include <ostream>
#include <streambuf>
#include <string>
+#include <string_view>
#include <type_traits>
#include <utility>
#include <vector>
@@ -44,6 +45,7 @@ public:
typedef typename std::basic_streambuf<CharT, Traits>::off_type off_type;
typedef Allocator allocator_type;
typedef std::vector<char_type, Allocator> vector_type;
+ typedef std::basic_string_view<char_type> string_view_type;
basic_vectorbuf(std::ios_base::openmode mode = std::ios_base::in | std::ios_base::out) : std::basic_streambuf<CharT, Traits>(), m_mode(mode), m_storage(), m_threshold(nullptr)
{
@@ -72,23 +74,16 @@ public:
vector_type const &vec() const
{
- if (m_mode & std::ios_base::out)
- {
- if (this->pptr() > m_threshold) m_threshold = this->pptr();
- auto const base(this->pbase());
- auto const end(m_threshold - base);
- if (m_storage.size() > std::make_unsigned_t<decltype(end)>(end))
- {
- m_storage.resize(std::make_unsigned_t<decltype(end)>(end));
- assert(&m_storage[0] == base);
- auto const put_offset(this->pptr() - base);
- const_cast<basic_vectorbuf *>(this)->setp(base, base + put_offset);
- const_cast<basic_vectorbuf *>(this)->pbump(put_offset);
- }
- }
+ finalize();
return m_storage;
}
+ explicit operator string_view_type() const
+ {
+ finalize();
+ return string_view_type(this->pbase(), this->pptr() - this->pbase());
+ }
+
void vec(const vector_type &content)
{
m_storage = content;
@@ -307,6 +302,24 @@ private:
}
}
+ void finalize() const
+ {
+ if (m_mode & std::ios_base::out)
+ {
+ if (this->pptr() > m_threshold) m_threshold = this->pptr();
+ auto const base(this->pbase());
+ auto const end(m_threshold - base);
+ if (m_storage.size() > std::make_unsigned_t<decltype(end)>(end))
+ {
+ m_storage.resize(std::make_unsigned_t<decltype(end)>(end));
+ assert(&m_storage[0] == base);
+ auto const put_offset(this->pptr() - base);
+ const_cast<basic_vectorbuf *>(this)->setp(base, base + put_offset);
+ const_cast<basic_vectorbuf *>(this)->pbump(put_offset);
+ }
+ }
+ }
+
std::ios_base::openmode m_mode;
mutable vector_type m_storage;
mutable CharT *m_threshold;
@@ -317,12 +330,14 @@ class basic_ivectorstream : public std::basic_istream<CharT, Traits>
{
public:
typedef typename basic_vectorbuf<CharT, Traits, Allocator>::vector_type vector_type;
+ typedef typename basic_vectorbuf<CharT, Traits, Allocator>::string_view_type string_view_type;
basic_ivectorstream(std::ios_base::openmode mode = std::ios_base::in) : std::basic_istream<CharT, Traits>(&m_rdbuf), m_rdbuf(mode) { }
basic_ivectorstream(vector_type const &content, std::ios_base::openmode mode = std::ios_base::in) : std::basic_istream<CharT, Traits>(&m_rdbuf), m_rdbuf(content, mode) { }
basic_ivectorstream(vector_type &&content, std::ios_base::openmode mode = std::ios_base::in) : std::basic_istream<CharT, Traits>(&m_rdbuf), m_rdbuf(std::move(content), mode) { }
basic_vectorbuf<CharT, Traits, Allocator> *rdbuf() const { return static_cast<basic_vectorbuf<CharT, Traits, Allocator> *>(std::basic_istream<CharT, Traits>::rdbuf()); }
+ explicit operator string_view_type() const { return string_view_type(*rdbuf()); }
vector_type const &vec() const { return rdbuf()->vec(); }
void vec(const vector_type &content) { rdbuf()->vec(content); }
void vec(vector_type &&content) { rdbuf()->vec(std::move(content)); }
@@ -338,6 +353,7 @@ class basic_ovectorstream : public std::basic_ostream<CharT, Traits>
{
public:
typedef typename basic_vectorbuf<CharT, Traits, Allocator>::vector_type vector_type;
+ typedef typename basic_vectorbuf<CharT, Traits, Allocator>::string_view_type string_view_type;
basic_ovectorstream(std::ios_base::openmode mode = std::ios_base::out) : std::basic_ostream<CharT, Traits>(&m_rdbuf), m_rdbuf(mode) { }
basic_ovectorstream(vector_type const &content, std::ios_base::openmode mode = std::ios_base::out) : std::basic_ostream<CharT, Traits>(&m_rdbuf), m_rdbuf(content, mode) { }
@@ -346,6 +362,7 @@ public:
basic_vectorbuf<CharT, Traits, Allocator> *rdbuf() const { return static_cast<basic_vectorbuf<CharT, Traits, Allocator> *>(std::basic_ostream<CharT, Traits>::rdbuf()); }
vector_type const &vec() const { return rdbuf()->vec(); }
+ explicit operator string_view_type() const { return string_view_type(*rdbuf()); }
void vec(const vector_type &content) { rdbuf()->vec(content); }
void vec(vector_type &&content) { rdbuf()->vec(std::move(content)); }
basic_ovectorstream &reserve(typename vector_type::size_type size) { rdbuf()->reserve(size); return *this; }
@@ -361,6 +378,7 @@ class basic_vectorstream : public std::basic_iostream<CharT, Traits>
{
public:
typedef typename basic_vectorbuf<CharT, Traits, Allocator>::vector_type vector_type;
+ typedef typename basic_vectorbuf<CharT, Traits, Allocator>::string_view_type string_view_type;
basic_vectorstream(std::ios_base::openmode mode = std::ios_base::in | std::ios_base::out) : std::basic_iostream<CharT, Traits>(&m_rdbuf), m_rdbuf(mode) { }
basic_vectorstream(vector_type const &content, std::ios_base::openmode mode = std::ios_base::in | std::ios_base::out) : std::basic_iostream<CharT, Traits>(&m_rdbuf), m_rdbuf(content, mode) { }
@@ -369,6 +387,7 @@ public:
basic_vectorbuf<CharT, Traits, Allocator> *rdbuf() const { return static_cast<basic_vectorbuf<CharT, Traits, Allocator> *>(std::basic_iostream<CharT, Traits>::rdbuf()); }
vector_type const &vec() const { return rdbuf()->vec(); }
+ explicit operator string_view_type() const { return string_view_type(*rdbuf()); }
void vec(const vector_type &content) { rdbuf()->vec(content); }
void vec(vector_type &&content) { rdbuf()->vec(std::move(content)); }
basic_vectorstream &reserve(typename vector_type::size_type size) { rdbuf()->reserve(size); return *this; }
diff --git a/src/lib/util/xmlfile.cpp b/src/lib/util/xmlfile.cpp
index 2a1bedc7c2c..cfa6bbd8ff5 100644
--- a/src/lib/util/xmlfile.cpp
+++ b/src/lib/util/xmlfile.cpp
@@ -603,6 +603,19 @@ data_node::attribute_node const *data_node::get_attribute(const char *attribute)
//-------------------------------------------------
+// get_attribute_string_ptr - get a pointer to
+// the string value of the specified attribute;
+// if not found, return = nullptr
+//-------------------------------------------------
+
+std::string const *data_node::get_attribute_string_ptr(const char *attribute) const
+{
+ attribute_node const *attr = get_attribute(attribute);
+ return attr ? &attr->value : nullptr;
+}
+
+
+//-------------------------------------------------
// get_attribute_string - get the string
// value of the specified attribute; if not
// found, return = the provided default
@@ -623,9 +636,10 @@ const char *data_node::get_attribute_string(const char *attribute, const char *d
long long data_node::get_attribute_int(const char *attribute, long long defvalue) const
{
- char const *const string = get_attribute_string(attribute, nullptr);
- if (!string)
+ attribute_node const *attr = get_attribute(attribute);
+ if (!attr)
return defvalue;
+ std::string const &string = attr->value;
std::istringstream stream;
stream.imbue(std::locale::classic());
@@ -666,14 +680,16 @@ long long data_node::get_attribute_int(const char *attribute, long long defvalue
data_node::int_format data_node::get_attribute_int_format(const char *attribute) const
{
- char const *const string = get_attribute_string(attribute, nullptr);
- if (!string)
+ attribute_node const *attr = get_attribute(attribute);
+ if (!attr)
return int_format::DECIMAL;
- else if (string[0] == '$')
+ std::string const &string = attr->value;
+
+ if (string[0] == '$')
return int_format::HEX_DOLLAR;
else if (string[0] == '0' && string[1] == 'x')
return int_format::HEX_C;
- if (string[0] == '#')
+ else if (string[0] == '#')
return int_format::DECIMAL_HASH;
else
return int_format::DECIMAL;
@@ -688,11 +704,11 @@ data_node::int_format data_node::get_attribute_int_format(const char *attribute)
float data_node::get_attribute_float(const char *attribute, float defvalue) const
{
- char const *const string = get_attribute_string(attribute, nullptr);
- if (!string)
+ attribute_node const *attr = get_attribute(attribute);
+ if (!attr)
return defvalue;
- std::istringstream stream(string);
+ std::istringstream stream(attr->value);
stream.imbue(std::locale::classic());
float result;
return (stream >> result) ? result : defvalue;
diff --git a/src/lib/util/xmlfile.h b/src/lib/util/xmlfile.h
index ac4e9864f13..b4bcf3e17e7 100644
--- a/src/lib/util/xmlfile.h
+++ b/src/lib/util/xmlfile.h
@@ -134,6 +134,9 @@ public:
// return whether a node has the specified attribute
bool has_attribute(const char *attribute) const;
+ // return a pointer to the string value of an attribute, or nullptr if not present
+ std::string const *get_attribute_string_ptr(const char *attribute) const;
+
// return the string value of an attribute, or the specified default if not present
const char *get_attribute_string(const char *attribute, const char *defvalue) const;
diff --git a/src/osd/modules/debugger/debuggdbstub.cpp b/src/osd/modules/debugger/debuggdbstub.cpp
index 1dce80aaf52..8f3b670dc39 100644
--- a/src/osd/modules/debugger/debuggdbstub.cpp
+++ b/src/osd/modules/debugger/debuggdbstub.cpp
@@ -678,7 +678,7 @@ void debug_gdbstub::send_reply(const char *str)
checksum += str[i];
std::string reply = string_format("$%s#%02x", str, checksum);
- m_socket.puts(reply.c_str());
+ m_socket.puts(reply);
}