Skip to content

Commit fc41ef0

Browse files
committed
emu/ioport.cpp: Improved validation of DIP switch locations.
* Treat an empty switch name as an error. * Treat a non-positive switch number as an error. * Also allocate fewer temporary strings.
1 parent 1228725 commit fc41ef0

File tree

6 files changed

+98
-73
lines changed

6 files changed

+98
-73
lines changed

src/emu/ioport.cpp

+50-41
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@
3232
#include <algorithm>
3333
#include <cctype>
3434
#include <ctime>
35+
#include <sstream>
3536

3637

3738
namespace {
@@ -420,16 +421,13 @@ u8 const inp_header::MAGIC[inp_header::OFFS_BASETIME - inp_header::OFFS_MAGIC] =
420421
// to the current list
421422
//-------------------------------------------------
422423

423-
void ioport_list::append(device_t &device, std::string &errorbuf)
424+
void ioport_list::append(device_t &device, std::ostream &errorbuf)
424425
{
425426
// no constructor, no list
426427
ioport_constructor constructor = device.input_ports();
427-
if (constructor == nullptr)
428+
if (!constructor)
428429
return;
429430

430-
// reset error buffer
431-
errorbuf.clear();
432-
433431
// detokenize into the list
434432
(*constructor)(device, *this, errorbuf);
435433

@@ -692,7 +690,7 @@ ioport_setting::ioport_setting(ioport_field &field, ioport_value _value, const c
692690
// ioport_diplocation - constructor
693691
//-------------------------------------------------
694692

695-
ioport_diplocation::ioport_diplocation(const char *name, u8 swnum, bool invert) :
693+
ioport_diplocation::ioport_diplocation(std::string_view name, u8 swnum, bool invert) :
696694
m_name(name),
697695
m_number(swnum),
698696
m_invert(invert)
@@ -1359,7 +1357,7 @@ float ioport_field::crosshair_read() const
13591357
// descriptions
13601358
//-------------------------------------------------
13611359

1362-
void ioport_field::expand_diplocation(const char *location, std::string &errorbuf)
1360+
void ioport_field::expand_diplocation(const char *location, std::ostream &errorbuf)
13631361
{
13641362
// if nothing present, bail
13651363
if (!location)
@@ -1368,70 +1366,76 @@ void ioport_field::expand_diplocation(const char *location, std::string &errorbu
13681366
m_diploclist.clear();
13691367

13701368
// parse the string
1371-
std::string name; // Don't move this variable inside the loop, lastname's lifetime depends on it being outside
1372-
const char *lastname = nullptr;
1369+
std::string_view lastname;
13731370
const char *curentry = location;
13741371
int entries = 0;
1375-
while (*curentry != 0)
1372+
while (*curentry)
13761373
{
13771374
// find the end of this entry
13781375
const char *comma = strchr(curentry, ',');
1379-
if (comma == nullptr)
1376+
if (!comma)
13801377
comma = curentry + strlen(curentry);
13811378

13821379
// extract it to tempbuf
1383-
std::string tempstr(curentry, comma - curentry);
1380+
std::string_view tempstr(curentry, comma - curentry);
13841381

13851382
// first extract the switch name if present
1386-
const char *number = tempstr.c_str();
1387-
const char *colon = strchr(tempstr.c_str(), ':');
1383+
std::string_view::size_type number = 0;
1384+
std::string_view::size_type const colon = tempstr.find(':');
13881385

1389-
if (colon != nullptr)
1386+
std::string_view name;
1387+
if (colon != std::string_view::npos)
13901388
{
13911389
// allocate and copy the name if it is present
1392-
lastname = name.assign(number, colon - number).c_str();
1390+
lastname = tempstr.substr(0, colon);
13931391
number = colon + 1;
1392+
if (lastname.empty())
1393+
{
1394+
util::stream_format(errorbuf, "Switch location '%s' has empty switch name!\n", location);
1395+
lastname = "UNK";
1396+
}
1397+
name = lastname;
13941398
}
13951399
else
13961400
{
13971401
// otherwise, just copy the last name
1398-
if (lastname == nullptr)
1402+
if (lastname.empty())
13991403
{
1400-
errorbuf.append(string_format("Switch location '%s' missing switch name!\n", location));
1401-
lastname = (char *)"UNK";
1404+
util::stream_format(errorbuf, "Switch location '%s' missing switch name!\n", location);
1405+
lastname = "UNK";
14021406
}
1403-
name.assign(lastname);
1407+
name = lastname;
14041408
}
14051409

14061410
// if the number is preceded by a '!' it's active high
1407-
bool invert = false;
1408-
if (*number == '!')
1409-
{
1410-
invert = true;
1411-
number++;
1412-
}
1411+
bool const invert = tempstr[number] == '!';
1412+
if (invert)
1413+
++number;
14131414

14141415
// now scan the switch number
14151416
int swnum = -1;
1416-
if (sscanf(number, "%d", &swnum) != 1)
1417-
errorbuf.append(string_format("Switch location '%s' has invalid format!\n", location));
1417+
if (sscanf(&tempstr[number], "%d", &swnum) != 1)
1418+
util::stream_format(errorbuf, "Switch location '%s' has invalid format!\n", location);
1419+
else if (0 >= swnum)
1420+
util::stream_format(errorbuf, "Switch location '%s' has switch number that is not positive!\n", location);
14181421

14191422
// allocate a new entry
1420-
m_diploclist.emplace_back(name.c_str(), swnum, invert);
1423+
if (0 < swnum)
1424+
m_diploclist.emplace_back(name, swnum, invert);
14211425
entries++;
14221426

14231427
// advance to the next item
14241428
curentry = comma;
1425-
if (*curentry != 0)
1429+
if (*curentry)
14261430
curentry++;
14271431
}
14281432

14291433
// then verify the number of bits in the mask matches
14301434
int const bits = population_count_32(m_mask);
14311435
if (bits > entries)
1432-
errorbuf.append(string_format("Switch location '%s' does not describe enough bits for mask %X\n", location, m_mask));
1436+
util::stream_format(errorbuf, "Switch location '%s' does not describe enough bits for mask %X\n", location, m_mask);
14331437
else if (bits < entries)
1434-
errorbuf.append(string_format("Switch location '%s' describes too many bits for mask %X\n", location, m_mask));
1438+
util::stream_format(errorbuf, "Switch location '%s' describes too many bits for mask %X\n", location, m_mask);
14351439
}
14361440

14371441

@@ -1638,7 +1642,7 @@ void ioport_port::frame_update()
16381642
// wholly overlapped by other fields
16391643
//-------------------------------------------------
16401644

1641-
void ioport_port::collapse_fields(std::string &errorbuf)
1645+
void ioport_port::collapse_fields(std::ostream &errorbuf)
16421646
{
16431647
ioport_value maskbits = 0;
16441648
int lastmodcount = -1;
@@ -1667,13 +1671,13 @@ void ioport_port::collapse_fields(std::string &errorbuf)
16671671
// for errors
16681672
//-------------------------------------------------
16691673

1670-
void ioport_port::insert_field(ioport_field &newfield, ioport_value &disallowedbits, std::string &errorbuf)
1674+
void ioport_port::insert_field(ioport_field &newfield, ioport_value &disallowedbits, std::ostream &errorbuf)
16711675
{
16721676
// verify against the disallowed bits, but only if we are condition-free
16731677
if (newfield.condition().none())
16741678
{
16751679
if ((newfield.mask() & disallowedbits) != 0)
1676-
errorbuf.append(string_format("INPUT_TOKEN_FIELD specifies duplicate port bits (port=%s mask=%X)\n", tag(), newfield.mask()));
1680+
util::stream_format(errorbuf, "INPUT_TOKEN_FIELD specifies duplicate port bits (port=%s mask=%X)\n", tag(), newfield.mask());
16771681
disallowedbits |= newfield.mask();
16781682
}
16791683

@@ -1812,12 +1816,17 @@ time_t ioport_manager::initialize()
18121816

18131817
// if we have a token list, proceed
18141818
device_enumerator iter(machine().root_device());
1815-
for (device_t &device : iter)
18161819
{
1817-
std::string errors;
1818-
m_portlist.append(device, errors);
1819-
if (!errors.empty())
1820-
osd_printf_error("Input port errors:\n%s", errors);
1820+
std::ostringstream errors;
1821+
for (device_t &device : iter)
1822+
{
1823+
m_portlist.append(device, errors);
1824+
if (errors.tellp())
1825+
{
1826+
osd_printf_error("Input port errors:\n%s", std::move(errors).str());
1827+
errors.str("");
1828+
}
1829+
}
18211830
}
18221831

18231832
// renumber player numbers for controller ports
@@ -3274,7 +3283,7 @@ void ioport_manager::record_port(ioport_port &port)
32743283
// ioport_configurer - constructor
32753284
//-------------------------------------------------
32763285

3277-
ioport_configurer::ioport_configurer(device_t &owner, ioport_list &portlist, std::string &errorbuf) :
3286+
ioport_configurer::ioport_configurer(device_t &owner, ioport_list &portlist, std::ostream &errorbuf) :
32783287
m_owner(owner),
32793288
m_portlist(portlist),
32803289
m_errorbuf(errorbuf),

src/emu/ioport.h

+12-10
Original file line numberDiff line numberDiff line change
@@ -25,9 +25,11 @@
2525
#include <cstdint>
2626
#include <cstring>
2727
#include <ctime>
28+
#include <iosfwd>
2829
#include <initializer_list>
2930
#include <list>
3031
#include <memory>
32+
#include <string_view>
3133
#include <vector>
3234

3335

@@ -325,7 +327,7 @@ enum
325327
//**************************************************************************
326328

327329
// constructor function pointer
328-
typedef void(*ioport_constructor)(device_t &owner, ioport_list &portlist, std::string &errorbuf);
330+
typedef void(*ioport_constructor)(device_t &owner, ioport_list &portlist, std::ostream &errorbuf);
329331

330332
// I/O port callback function delegates
331333
typedef device_delegate<ioport_value ()> ioport_field_read_delegate;
@@ -529,7 +531,7 @@ class ioport_diplocation
529531
{
530532
public:
531533
// construction/destruction
532-
ioport_diplocation(const char *name, u8 swnum, bool invert);
534+
ioport_diplocation(std::string_view name, u8 swnum, bool invert);
533535

534536
// getters
535537
const char *name() const { return m_name.c_str(); }
@@ -664,7 +666,7 @@ class ioport_field
664666
void set_user_settings(const user_settings &settings);
665667

666668
private:
667-
void expand_diplocation(const char *location, std::string &errorbuf);
669+
void expand_diplocation(const char *location, std::ostream &errorbuf);
668670

669671
// internal state
670672
ioport_field * m_next; // pointer to next field in sequence
@@ -744,7 +746,7 @@ class ioport_list : public std::map<std::string, std::unique_ptr<ioport_port>>
744746
public:
745747
ioport_list() { }
746748

747-
void append(device_t &device, std::string &errorbuf);
749+
void append(device_t &device, std::ostream &errorbuf);
748750
};
749751

750752

@@ -779,13 +781,13 @@ class ioport_port
779781

780782
// other operations
781783
ioport_field *field(ioport_value mask) const;
782-
void collapse_fields(std::string &errorbuf);
784+
void collapse_fields(std::ostream &errorbuf);
783785
void frame_update();
784786
void init_live_state();
785787
void update_defvalue(bool flush_defaults);
786788

787789
private:
788-
void insert_field(ioport_field &newfield, ioport_value &disallowedbits, std::string &errorbuf);
790+
void insert_field(ioport_field &newfield, ioport_value &disallowedbits, std::ostream &errorbuf);
789791

790792
// internal state
791793
ioport_port * m_next; // pointer to next port
@@ -1033,7 +1035,7 @@ class ioport_configurer
10331035
{
10341036
public:
10351037
// construction/destruction
1036-
ioport_configurer(device_t &owner, ioport_list &portlist, std::string &errorbuf);
1038+
ioport_configurer(device_t &owner, ioport_list &portlist, std::ostream &errorbuf);
10371039

10381040
// static helpers
10391041
static const char *string_from_token(const char *string);
@@ -1083,7 +1085,7 @@ class ioport_configurer
10831085
// internal state
10841086
device_t & m_owner;
10851087
ioport_list & m_portlist;
1086-
std::string & m_errorbuf;
1088+
std::ostream & m_errorbuf;
10871089

10881090
ioport_port * m_curport;
10891091
ioport_field * m_curfield;
@@ -1123,7 +1125,7 @@ class ioport_configurer
11231125

11241126
// start of table
11251127
#define INPUT_PORTS_START(_name) \
1126-
ATTR_COLD void INPUT_PORTS_NAME(_name)(device_t &owner, ioport_list &portlist, std::string &errorbuf) \
1128+
ATTR_COLD void INPUT_PORTS_NAME(_name)(device_t &owner, ioport_list &portlist, std::ostream &errorbuf) \
11271129
{ \
11281130
ioport_configurer configurer(owner, portlist, errorbuf);
11291131
// end of table
@@ -1132,7 +1134,7 @@ ATTR_COLD void INPUT_PORTS_NAME(_name)(device_t &owner, ioport_list &portlist, s
11321134

11331135
// aliasing
11341136
#define INPUT_PORTS_EXTERN(_name) \
1135-
extern void INPUT_PORTS_NAME(_name)(device_t &owner, ioport_list &portlist, std::string &errorbuf)
1137+
extern void INPUT_PORTS_NAME(_name)(device_t &owner, ioport_list &portlist, std::ostream &errorbuf)
11361138

11371139
// including
11381140
#define PORT_INCLUDE(_name) \

src/emu/validity.cpp

+8-6
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@
2222
#include "unicode.h"
2323

2424
#include <cctype>
25+
#include <sstream>
2526
#include <type_traits>
2627
#include <typeinfo>
2728

@@ -2495,12 +2496,13 @@ void validity_checker::validate_inputs(device_t &root)
24952496

24962497
// allocate the input ports
24972498
ioport_list portlist;
2498-
std::string errorbuf;
2499-
portlist.append(device, errorbuf);
2500-
2501-
// report any errors during construction
2502-
if (!errorbuf.empty())
2503-
osd_printf_error("I/O port error during construction:\n%s\n", errorbuf);
2499+
{
2500+
// report any errors during construction
2501+
std::ostringstream errorbuf;
2502+
portlist.append(device, errorbuf);
2503+
if (errorbuf.tellp())
2504+
osd_printf_error("I/O port error during construction:\n%s\n", std::move(errorbuf).str());
2505+
}
25042506

25052507
// do a first pass over ports to add their names and find duplicates
25062508
for (auto &port : portlist)

0 commit comments

Comments
 (0)