Refactor remaining tokensplitters

Also fixes some bugs with memory search.
This commit is contained in:
Ilari Liusvaara 2012-03-02 21:02:15 +02:00
parent 4cf07bd298
commit b1c2441da4
4 changed files with 39 additions and 117 deletions

View file

@ -71,44 +71,6 @@ private:
std::string commandname;
};
/**
* Splits string to fields on ' ' and '\t', with multiple whitespace collapsed into one.
*/
class tokensplitter
{
public:
/**
* Create a new splitter.
*
* parameter _line: The line to start splitting.
* throws std::bad_alloc: Not enough memory.
*/
tokensplitter(const std::string& _line) throw(std::bad_alloc);
/**
* Are there more tokens coming?
*
* returns: True if there is at least one token coming, false otherwise.
*/
operator bool() throw();
/**
* Get the next token.
*
* returns: The next token from line. If there are no more tokens, returns "".
* throws std::bad_alloc: Not enough memory.
*/
operator std::string() throw(std::bad_alloc);
/**
* Get all remaining line in one go.
*
* returns: All remaining parts of line as-is.
* throws std::bad_alloc: Not enough memory.
*/
std::string tail() throw(std::bad_alloc);
private:
std::string line;
size_t position;
};
/**
* Mandatory filename
*/

View file

@ -39,30 +39,25 @@ namespace
messages << "alias " << i.first << " " << j << std::endl;
});
function_ptr_command<tokensplitter&> unalias_command("unalias-command", "unalias a command",
function_ptr_command<const std::string&> unalias_command("unalias-command", "unalias a command",
"Syntax: unalias-command <aliasname>\nClear expansion of alias <aliasname>\n",
[](tokensplitter& t) throw(std::bad_alloc, std::runtime_error) {
std::string aliasname = t;
if(t)
throw std::runtime_error("This command only takes one argument");
if(!command::valid_alias_name(aliasname))
[](const std::string& t) throw(std::bad_alloc, std::runtime_error) {
auto r = regex("([^ \t]+)[ \t]*", t, "This command only takes one argument");
if(!command::valid_alias_name(r[1]))
throw std::runtime_error("Illegal alias name");
aliases[aliasname].clear();
messages << "Command '" << aliasname << "' unaliased" << std::endl;
aliases[r[1]].clear();
messages << "Command '" << r[1] << "' unaliased" << std::endl;
});
function_ptr_command<tokensplitter&> alias_command("alias-command", "alias a command",
function_ptr_command<const std::string&> alias_command("alias-command", "alias a command",
"Syntax: alias-command <aliasname> <command>\nAppend <command> to expansion of alias <aliasname>\n"
"Valid alias names can't be empty nor start with '*' or '?'\n",
[](tokensplitter& t) throw(std::bad_alloc, std::runtime_error) {
std::string aliasname = t;
std::string command = t.tail();
if(command == "")
throw std::runtime_error("Alias name and command needed");
if(!command::valid_alias_name(aliasname))
[](const std::string& t) throw(std::bad_alloc, std::runtime_error) {
auto r = regex("([^ \t]+)[ \t]+([^ \t].*)", t, "Alias name and command needed");
if(!command::valid_alias_name(r[1]))
throw std::runtime_error("Illegal alias name");
aliases[aliasname].push_back(command);
messages << "Command '" << aliasname << "' aliased to '" << command << "'" << std::endl;
aliases[r[1]].push_back(r[2]);
messages << "Command '" << r[1] << "' aliased to '" << r[2] << "'" << std::endl;
});
}
@ -206,37 +201,6 @@ bool command::valid_alias_name(const std::string& aliasname) throw(std::bad_allo
return true;
}
tokensplitter::tokensplitter(const std::string& _line) throw(std::bad_alloc)
{
line = _line;
position = 0;
}
tokensplitter::operator bool() throw()
{
return (position < line.length());
}
tokensplitter::operator std::string() throw(std::bad_alloc)
{
size_t nextp, oldp = position;
nextp = line.find_first_of(" \t", position);
if(nextp > line.length()) {
position = line.length();
return line.substr(oldp);
} else {
position = nextp;
while(position < line.length() && (line[position] == ' ' || line[position] == '\t'))
position++;
return line.substr(oldp, nextp - oldp);
}
}
std::string tokensplitter::tail() throw(std::bad_alloc)
{
return line.substr(position);
}
template<>
void invoke_command_fn(void (*fn)(const std::string& args), const std::string& args)
{
@ -260,10 +224,3 @@ void invoke_command_fn(void (*fn)(struct arg_filename a), const std::string& arg
b.v = args;
fn(b);
}
template<>
void invoke_command_fn(void (*fn)(tokensplitter& a), const std::string& args)
{
tokensplitter t(args);
fn(t);
}

View file

@ -67,15 +67,16 @@ namespace
controls.analog(pcid, x / 2 , y / 2);
}
function_ptr_command<tokensplitter&> autofire("autofire", "Set autofire pattern",
function_ptr_command<const std::string&> autofire("autofire", "Set autofire pattern",
"Syntax: autofire <buttons|->...\nSet autofire pattern\n",
[](tokensplitter& t) throw(std::bad_alloc, std::runtime_error) {
if(!t)
throw std::runtime_error("Need at least one frame for autofire");
[](const std::string& a) throw(std::bad_alloc, std::runtime_error) {
auto r = regex(".*[^ \t].*", a, "Need at least one frame for autofire");
std::vector<controller_frame> new_autofire_pattern;
init_buttonmap();
while(t) {
std::string fpattern = t;
std::string pattern = a;
while(pattern != "") {
std::string fpattern;
extract_token(pattern, fpattern, " \t", true);
if(fpattern == "-")
new_autofire_pattern.push_back(controls.get_blank());
else {

View file

@ -7,6 +7,7 @@
#include "core/memorymanip.hpp"
#include "core/misc.hpp"
#include "core/rom.hpp"
#include "library/string.hpp"
#include <iostream>
#include <limits>
@ -791,20 +792,20 @@ namespace
~memorymanip_command() throw() {}
void invoke(const std::string& args) throw(std::bad_alloc, std::runtime_error)
{
tokensplitter t(args);
firstword = static_cast<std::string>(t);
secondword = static_cast<std::string>(t);
has_tail = t;
regex_results t = regex("(([^ \t]+)([ \t]+([^ \t]+)([ \t]+([^ \t].*)?)?)?)?", args);
firstword = t[2];
secondword = t[4];
has_tail = (t[6] != "");
address_bad = true;
value_bad = true;
has_value = (secondword != "");
try {
if(firstword.length() >= 2 && firstword.substr(0, 2) == "0x") {
if(firstword.length() > 10)
if(t = regex("0x(.+)", firstword)) {
if(t[1].length() > 8)
throw 42;
address = 0;
for(unsigned i = 2; i < firstword.length(); i++)
address = 16 * address + hex(firstword[i]);
for(unsigned i = 0; i < t[1].length(); i++)
address = 16 * address + hex(t[1][i]);
} else {
address = parse_value<uint32_t>(firstword);
}
@ -812,13 +813,13 @@ namespace
} catch(...) {
}
try {
if(secondword.length() >= 2 && secondword.substr(0, 2) == "0x") {
if(secondword.length() > 18)
if(t = regex("0x(.+)", secondword)) {
if(t[1].length() > 16)
throw 42;
value = 0;
for(unsigned i = 2; i < secondword.length(); i++)
value = 16 * value + hex(secondword[i]);
} else if(secondword.length() > 0 && secondword[0] == '-') {
for(unsigned i = 0; i < t[1].length(); i++)
value = 16 * value + hex(t[1][i]);
} else if(regex("-.*", secondword)) {
value = static_cast<uint64_t>(parse_value<int64_t>(secondword));
} else {
value = parse_value<uint64_t>(secondword);
@ -885,7 +886,8 @@ namespace
{
if(address_bad || value_bad || has_tail)
throw std::runtime_error("Syntax: " + _command + " <address> <value>");
if(static_cast<int64_t>(value) < low || value > high)
int64_t value2 = static_cast<int64_t>(value);
if(value2 < low || (value > high && value2 >= 0))
throw std::runtime_error("Value to write out of range");
wfn(address, value & high);
}
@ -961,7 +963,7 @@ namespace
else if(firstword == "w" && has_value) {
if(static_cast<int64_t>(value) < -32768 || value > 65535)
throw std::runtime_error("Value to compare out of range");
isrch->word_value(value & 0xFF);
isrch->word_value(value & 0xFFFF);
} else if(firstword == "sdlt" && !has_value)
isrch->dword_slt();
else if(firstword == "sdle" && !has_value)
@ -989,7 +991,7 @@ namespace
else if(firstword == "d" && has_value) {
if(static_cast<int64_t>(value) < -2147483648LL || value > 4294967295ULL)
throw std::runtime_error("Value to compare out of range");
isrch->dword_value(value & 0xFF);
isrch->dword_value(value & 0xFFFFFFFFULL);
} else if(firstword == "sqlt" && !has_value)
isrch->qword_slt();
else if(firstword == "sqle" && !has_value)
@ -1015,7 +1017,7 @@ namespace
else if(firstword == "uqgt" && !has_value)
isrch->qword_ugt();
else if(firstword == "q" && has_value)
isrch->qword_value(value & 0xFF);
isrch->qword_value(value);
else if(firstword == "update" && !has_value)
isrch->update();
else if(firstword == "reset" && !has_value)