From aa29519528cb3dbdbfac56819bea670ed8c56c5d Mon Sep 17 00:00:00 2001 From: AJR Date: Fri, 1 Jan 2021 12:18:29 -0500 Subject: 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 --- src/emu/fileio.cpp | 2 +- src/emu/fileio.h | 2 +- src/emu/image.cpp | 2 +- src/emu/rendlay.cpp | 307 ++++++++++++++---------------- src/frontend/mame/clifront.cpp | 7 +- src/frontend/mame/ui/inifile.cpp | 3 +- src/frontend/mame/ui/miscmenu.cpp | 6 +- src/frontend/mame/ui/ui.cpp | 6 +- src/frontend/mame/ui/utils.cpp | 8 +- src/lib/util/corefile.cpp | 16 +- src/lib/util/corefile.h | 3 +- src/lib/util/vecstream.h | 47 +++-- src/lib/util/xmlfile.cpp | 34 +++- src/lib/util/xmlfile.h | 3 + src/osd/modules/debugger/debuggdbstub.cpp | 2 +- 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 const &args); template 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; - template + template + 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(value)); + } + + template >> 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(name), std::forward(value)); + m_entries.emplace(pos, std::string(name), std::forward(value)); } template @@ -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 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 - std::tuple get_variable_text(T &&... args) + std::pair get_variable_text(std::string_view str) { - entry *const found(find_entry(std::forward(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 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 const text(get_variable_text(pos + 1, term)); - if (std::get<2>(text)) + std::pair 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 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 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 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 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 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 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 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 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 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 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(env.device().subdevice(tag)); + std::string_view const tag(env.get_attribute_string(itemnode, "tag")); + m_screen = dynamic_cast(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\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\tplugins().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 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 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 const &args m_printf_buffer.reserve(1024); m_printf_buffer.seekp(0, ovectorstream::beg); util::stream_format(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 #include #include +#include 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 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 #include #include +#include #include #include #include @@ -44,6 +45,7 @@ public: typedef typename std::basic_streambuf::off_type off_type; typedef Allocator allocator_type; typedef std::vector vector_type; + typedef std::basic_string_view string_view_type; basic_vectorbuf(std::ios_base::openmode mode = std::ios_base::in | std::ios_base::out) : std::basic_streambuf(), 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(end)) - { - m_storage.resize(std::make_unsigned_t(end)); - assert(&m_storage[0] == base); - auto const put_offset(this->pptr() - base); - const_cast(this)->setp(base, base + put_offset); - const_cast(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(end)) + { + m_storage.resize(std::make_unsigned_t(end)); + assert(&m_storage[0] == base); + auto const put_offset(this->pptr() - base); + const_cast(this)->setp(base, base + put_offset); + const_cast(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 { public: typedef typename basic_vectorbuf::vector_type vector_type; + typedef typename basic_vectorbuf::string_view_type string_view_type; basic_ivectorstream(std::ios_base::openmode mode = std::ios_base::in) : std::basic_istream(&m_rdbuf), m_rdbuf(mode) { } basic_ivectorstream(vector_type const &content, std::ios_base::openmode mode = std::ios_base::in) : std::basic_istream(&m_rdbuf), m_rdbuf(content, mode) { } basic_ivectorstream(vector_type &&content, std::ios_base::openmode mode = std::ios_base::in) : std::basic_istream(&m_rdbuf), m_rdbuf(std::move(content), mode) { } basic_vectorbuf *rdbuf() const { return static_cast *>(std::basic_istream::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 { public: typedef typename basic_vectorbuf::vector_type vector_type; + typedef typename basic_vectorbuf::string_view_type string_view_type; basic_ovectorstream(std::ios_base::openmode mode = std::ios_base::out) : std::basic_ostream(&m_rdbuf), m_rdbuf(mode) { } basic_ovectorstream(vector_type const &content, std::ios_base::openmode mode = std::ios_base::out) : std::basic_ostream(&m_rdbuf), m_rdbuf(content, mode) { } @@ -346,6 +362,7 @@ public: basic_vectorbuf *rdbuf() const { return static_cast *>(std::basic_ostream::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 { public: typedef typename basic_vectorbuf::vector_type vector_type; + typedef typename basic_vectorbuf::string_view_type string_view_type; basic_vectorstream(std::ios_base::openmode mode = std::ios_base::in | std::ios_base::out) : std::basic_iostream(&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(&m_rdbuf), m_rdbuf(content, mode) { } @@ -369,6 +387,7 @@ public: basic_vectorbuf *rdbuf() const { return static_cast *>(std::basic_iostream::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 @@ -602,6 +602,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 @@ -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); } -- cgit v1.2.3