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
This commit is contained in:
AJR 2021-01-01 12:18:29 -05:00
parent 21fd983545
commit aa29519528
15 changed files with 232 additions and 216 deletions

View File

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

View File

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

View File

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

View File

@ -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 expand(str, str + strlen(str));
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 ((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));
}

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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