Fix recently broken :/command arg parsing.

Allows easy use of any number of args in worker functions.
This commit is contained in:
Tomasz Śniatowski 2008-04-16 23:06:11 +01:00
parent 4ca9eedf50
commit 9e0987c8b3

View File

@ -1801,6 +1801,78 @@ private:
gui_->add_chat_message(time, speaker, side, message, type, false); gui_->add_chat_message(time, speaker, side, message, type, false);
} }
//simple command args parser, separated from command_handler for clarity.
//a word begins with a nonspace
//n-th arg is n-th word up to the next space
//n-th data is n-th word up to the end
//cmd is 0-th arg, begins at 0 always.
class cmd_arg_parser
{
public:
cmd_arg_parser()
: str_(""), args_end(false)
{
args.push_back(0);
}
explicit cmd_arg_parser(const std::string& str)
: str_(str), args_end(false)
{
args.push_back(0);
}
void parse(const std::string& str)
{
str_ = str;
args.clear();
args.push_back(0);
args_end = false;
}
const std::string& get_str() const
{
return str_;
}
std::string get_arg(unsigned n) const
{
advance_to_arg(n);
if (n < args.size()) {
return std::string(str_, args[n], str_.find(' ', args[n]) - args[n]);
} else {
return "";
}
}
std::string get_data(unsigned n) const
{
advance_to_arg(n);
if (n < args.size()) {
return std::string(str_, args[n]);
} else {
return "";
}
}
std::string get_cmd() const
{
return get_arg(0);
}
private:
cmd_arg_parser& operator=(const cmd_arg_parser&);
cmd_arg_parser(const cmd_arg_parser&);
void advance_to_arg(unsigned n) const
{
while (n < args.size() && !args_end) {
size_t first_space = str_.find_first_of(' ', args.back());
size_t next_arg_begin = str_.find_first_not_of(' ', first_space);
if (next_arg_begin != std::string::npos) {
args.push_back(next_arg_begin);
} else {
args_end = true;
}
}
}
std::string str_;
mutable std::vector<size_t> args;
mutable bool args_end;
};
//A helper class template with a slim public interface //A helper class template with a slim public interface
//This represents a map of strings to void()-member-function-of-Worker-pointers //This represents a map of strings to void()-member-function-of-Worker-pointers
//with all the common functionality like general help, command help and aliases //with all the common functionality like general help, command help and aliases
@ -1842,7 +1914,7 @@ private:
typedef std::map<std::string, command> command_map; typedef std::map<std::string, command> command_map;
typedef std::map<std::string, std::string> command_alias_map; typedef std::map<std::string, std::string> command_alias_map;
map_command_handler() map_command_handler() : cap_("")
{ {
} }
@ -1864,16 +1936,16 @@ private:
init_map_default(); init_map_default();
init_map(); init_map();
} }
if (cmd_.empty()) { if (get_cmd().empty()) {
return; return;
} }
std::string actual_cmd = get_actual_cmd(cmd_); std::string actual_cmd = get_actual_cmd(get_cmd());
if (const command* c = get_command(actual_cmd)) { if (const command* c = get_command(actual_cmd)) {
if (is_enabled(*c)) { if (is_enabled(*c)) {
(static_cast<Worker*>(this)->*(c->handler))(); (static_cast<Worker*>(this)->*(c->handler))();
} }
} else if (help_on_unknown_) { } else if (help_on_unknown_) {
print("help", "Unknown command, try " + cmd_prefix_ + "help " print("help", "Unknown command (" + get_cmd() + "), try " + cmd_prefix_ + "help "
"for a list of available commands"); "for a list of available commands");
} }
} }
@ -1900,21 +1972,27 @@ private:
} }
//this should be overriden if e.g. flags are used to control command //this should be overriden if e.g. flags are used to control command
//availability. Return false if the command should not be executed by dispach() //availability. Return false if the command should not be executed by dispach()
virtual bool is_enabled(const command& c) const virtual bool is_enabled(const command& /*c*/) const
{ {
return true; return true;
} }
void parse_cmd(const std::string& cmd_string) virtual void parse_cmd(const std::string& cmd_string)
{ {
args_ = utils::split(cmd_string, ' '); cap_.parse(cmd_string);
cmd_ = args_.empty() ? "" : args_[0];
data_ = (cmd_string.begin() + cmd_.size() == cmd_string.end()) ? ""
: std::string(cmd_string.begin() + cmd_.size() + 1, cmd_string.end());
} }
//safe n-th argunment getter //safe n-th argunment getter
std::string get_arg(unsigned argn) const virtual std::string get_arg(unsigned argn) const
{ {
return (argn < args_.size()) ? args_[argn] : ""; return cap_.get_arg(argn);
}
//"data" is n-th arg and everything after it
virtual std::string get_data(unsigned argn = 1) const
{
return cap_.get_data(argn);
}
std::string get_cmd() const
{
return cap_.get_cmd();
} }
//take aliases into account //take aliases into account
std::string get_actual_cmd(const std::string& cmd) const std::string get_actual_cmd(const std::string& cmd) const
@ -1970,9 +2048,7 @@ private:
} }
return c != 0; return c != 0;
} }
std::vector<std::string> args_; cmd_arg_parser cap_;
std::string cmd_;
std::string data_;
protected: protected:
//show a "try help" message on unknown command? //show a "try help" message on unknown command?
static void set_help_on_unknown(bool value) static void set_help_on_unknown(bool value)
@ -2115,16 +2191,13 @@ private:
console_handler(menu_handler& menu_handler, console_handler(menu_handler& menu_handler,
mouse_handler& mouse_handler, const unsigned int team_num) mouse_handler& mouse_handler, const unsigned int team_num)
: chmap(), chat_command_handler(menu_handler, true), menu_handler_(menu_handler), mouse_handler_(mouse_handler) : chmap(), chat_command_handler(menu_handler, true), menu_handler_(menu_handler), mouse_handler_(mouse_handler)
, team_num_(team_num), cmd_(chmap::cmd_), data_(chmap::data_), args_(chmap::args_) , team_num_(team_num)
{ {
} }
void dispatch(const std::string& cmd) using chmap::dispatch; //disambiguate
{
chat_command_handler::parse_cmd(cmd);
chmap::dispatch(cmd);
}
protected: protected:
//chat_command_handler's init_map() will end up calling these. //chat_command_handler's init_map() and hanlers will end up calling these.
//this makes sure the commands end up in our map //this makes sure the commands end up in our map
virtual void register_command(const std::string& cmd, virtual void register_command(const std::string& cmd,
chat_command_handler::command_handler h, const std::string& help="", chat_command_handler::command_handler h, const std::string& help="",
@ -2140,12 +2213,24 @@ private:
{ {
chmap::register_alias(to_cmd, cmd); chmap::register_alias(to_cmd, cmd);
} }
virtual std::string get_arg(unsigned i) const
{
return chmap::get_arg(i);
}
virtual std::string get_cmd() const
{
return chmap::get_cmd();
}
virtual std::string get_data(unsigned n = 1) const
{
return chmap::get_data(n);
}
//these are needed to avoid ambiguities introduced by inheriting from console_command_handler //these are needed to avoid ambiguities introduced by inheriting from console_command_handler
using chmap::register_command; using chmap::register_command;
using chmap::register_alias; using chmap::register_alias;
using chmap::help; using chmap::help;
using chmap::get_arg; using chmap::is_enabled;
void do_refresh(); void do_refresh();
void do_droid(); void do_droid();
@ -2256,10 +2341,6 @@ private:
menu_handler& menu_handler_; menu_handler& menu_handler_;
mouse_handler& mouse_handler_; mouse_handler& mouse_handler_;
const unsigned int team_num_; const unsigned int team_num_;
//these are needed to avoid ambiguities introduced by inhriting from console_command_handler
const std::string & cmd_;
const std::string & data_;
const std::vector<std::string> & args_;
}; };
chat_handler::chat_handler() chat_handler::chat_handler()
@ -2342,19 +2423,19 @@ private:
} }
void chat_command_handler::do_emote() void chat_command_handler::do_emote()
{ {
chat_handler_.send_chat_message("/me " + data_, allies_only_); chat_handler_.send_chat_message("/me " + get_data(), allies_only_);
} }
void chat_command_handler::do_network_send() void chat_command_handler::do_network_send()
{ {
chat_handler_.send_command(cmd_, data_); chat_handler_.send_command(get_cmd(), get_data());
} }
void chat_command_handler::do_whisper() void chat_command_handler::do_whisper()
{ {
if (args_.size() < 3) return; if (get_data(2).empty()) return;
config cwhisper, data; config cwhisper, data;
cwhisper["message"] = get_arg(2);
cwhisper["sender"] = preferences::login();
cwhisper["receiver"] = get_arg(1); cwhisper["receiver"] = get_arg(1);
cwhisper["message"] = get_data(2);
cwhisper["sender"] = preferences::login();
data.add_child("whisper", cwhisper); data.add_child("whisper", cwhisper);
chat_handler_.add_chat_message(time(NULL), chat_handler_.add_chat_message(time(NULL),
"whisper to " + cwhisper["receiver"], 0, "whisper to " + cwhisper["receiver"], 0,
@ -2363,7 +2444,7 @@ private:
} }
void chat_command_handler::do_log() void chat_command_handler::do_log()
{ {
chat_handler_.change_logging(data_); chat_handler_.change_logging(get_data());
} }
void chat_command_handler::do_ignore() void chat_command_handler::do_ignore()
@ -2587,22 +2668,22 @@ private:
preferences::show_theme_dialog(*menu_handler_.gui_); preferences::show_theme_dialog(*menu_handler_.gui_);
} }
void console_handler::do_network_send_cmd() { void console_handler::do_network_send_cmd() {
menu_handler_.send_command(cmd_); menu_handler_.send_command(get_cmd());
} }
void console_handler::do_network_send_cmd_data() { void console_handler::do_network_send_cmd_data() {
menu_handler_.send_command(cmd_, data_); menu_handler_.send_command(get_cmd(), get_data());
} }
void console_handler::do_control() { void console_handler::do_control() {
// :control <side> <nick> // :control <side> <nick>
if (network::nconnections() == 0) return; if (network::nconnections() == 0) return;
const std::string::const_iterator j = std::find(data_.begin(),data_.end(),' '); const std::string side = get_arg(1);
if(j == data_.end()) const std::string player = get_arg(2);
if(player.empty())
{ {
print(_("error"), _("Usage: control <side> <nick>")); print(_("error"), _("Usage: control <side> <nick>"));
return; return;
} }
const std::string side = get_arg(1);
const std::string player = get_arg(2);
unsigned int side_num; unsigned int side_num;
try { try {
side_num = lexical_cast<unsigned int>(side); side_num = lexical_cast<unsigned int>(side);
@ -2644,7 +2725,7 @@ private:
menu_handler_.gui_->clear_chat_messages(); menu_handler_.gui_->clear_chat_messages();
} }
void console_handler::do_sunset() { void console_handler::do_sunset() {
int delay = lexical_cast_default<int>(data_); int delay = lexical_cast_default<int>(get_data());
menu_handler_.gui_->sunset(delay); menu_handler_.gui_->sunset(delay);
} }
void console_handler::do_fps() { void console_handler::do_fps() {
@ -2654,42 +2735,43 @@ private:
menu_handler_.gui_->toggle_benchmark(); menu_handler_.gui_->toggle_benchmark();
} }
void console_handler::do_save() { void console_handler::do_save() {
menu_handler_.save_game(data_,gui::NULL_DIALOG); menu_handler_.save_game(get_data(),gui::NULL_DIALOG);
} }
void console_handler::do_save_quit() { void console_handler::do_save_quit() {
menu_handler_.save_game(data_,gui::NULL_DIALOG); menu_handler_.save_game(get_data(),gui::NULL_DIALOG);
throw end_level_exception(QUIT); throw end_level_exception(QUIT);
} }
void console_handler::do_quit() { void console_handler::do_quit() {
throw end_level_exception(QUIT); throw end_level_exception(QUIT);
} }
void console_handler::do_ignore_replay_errors() { void console_handler::do_ignore_replay_errors() {
game_config::ignore_replay_errors = (data_ != "off") ? true : false; game_config::ignore_replay_errors = (get_data() != "off") ? true : false;
} }
void console_handler::do_nosaves() { void console_handler::do_nosaves() {
game_config::disable_autosave = (data_ != "off") ? true : false; game_config::disable_autosave = (get_data() != "off") ? true : false;
} }
void console_handler::do_next_level() { void console_handler::do_next_level() {
throw end_level_exception(LEVEL_CONTINUE_NO_SAVE); throw end_level_exception(LEVEL_CONTINUE_NO_SAVE);
} }
void console_handler::do_debug() { void console_handler::do_debug() {
print(cmd_, _("Debug mode activated!")); print(get_cmd(), _("Debug mode activated!"));
game_config::debug = true; game_config::debug = true;
} }
void console_handler::do_nodebug() { void console_handler::do_nodebug() {
print(cmd_, _("Debug mode deactivated!")); print(get_cmd(), _("Debug mode deactivated!"));
game_config::debug = false; game_config::debug = false;
} }
void console_handler::do_set_var() { void console_handler::do_set_var() {
const std::string::const_iterator j = std::find(data_.begin(),data_.end(),'='); const std::string data = get_data();
if(j != data_.end()) { const std::string::const_iterator j = std::find(data.begin(),data.end(),'=');
const std::string name(data_.begin(),j); if(j != data.end()) {
const std::string value(j+1,data_.end()); const std::string name(data.begin(),j);
const std::string value(j+1,data.end());
menu_handler_.gamestate_.set_variable(name,value); menu_handler_.gamestate_.set_variable(name,value);
} }
} }
void console_handler::do_show_var() { void console_handler::do_show_var() {
gui::message_dialog to_show(*menu_handler_.gui_,"",menu_handler_.gamestate_.get_variable(data_)); gui::message_dialog to_show(*menu_handler_.gui_,"",menu_handler_.gamestate_.get_variable(get_data()));
to_show.show(); to_show.show();
} }
void console_handler::do_unit() { void console_handler::do_unit() {
@ -2698,11 +2780,9 @@ private:
return; return;
const unit_map::iterator i = menu_handler_.current_unit(mouse_handler_); const unit_map::iterator i = menu_handler_.current_unit(mouse_handler_);
if (i == menu_handler_.units_.end()) return; if (i == menu_handler_.units_.end()) return;
const std::string::const_iterator j = std::find(data_.begin(),data_.end(),'='); const std::string name = get_arg(1);
if (j == data_.end()) return; const std::string value = get_data(2);
if (value.empty()) return;
const std::string name(data_.begin(),j);
const std::string value(j+1,data_.end());
// FIXME: Avoids a core dump on display // FIXME: Avoids a core dump on display
// because alignment strings get reduced // because alignment strings get reduced
// to an enum, then used to index an // to an enum, then used to index an
@ -2725,7 +2805,7 @@ private:
void console_handler::do_buff() { void console_handler::do_buff() {
const unit_map::iterator i = menu_handler_.current_unit(mouse_handler_); const unit_map::iterator i = menu_handler_.current_unit(mouse_handler_);
if(i != menu_handler_.units_.end()) { if(i != menu_handler_.units_.end()) {
i->second.add_trait(data_); i->second.add_trait(get_data());
menu_handler_.gui_->invalidate(i->first); menu_handler_.gui_->invalidate(i->first);
menu_handler_.gui_->invalidate_unit(); menu_handler_.gui_->invalidate_unit();
} }
@ -2741,7 +2821,7 @@ private:
} }
void console_handler::do_create() { void console_handler::do_create() {
if (menu_handler_.map_.on_board(mouse_handler_.get_last_hex())) { if (menu_handler_.map_.on_board(mouse_handler_.get_last_hex())) {
const unit_type_data::unit_type_map::const_iterator i = unit_type_data::types().find(data_); const unit_type_data::unit_type_map::const_iterator i = unit_type_data::types().find(get_data());
if(i == unit_type_data::types().end()) { if(i == unit_type_data::types().end()) {
return; return;
} }
@ -2764,11 +2844,11 @@ private:
menu_handler_.gui_->redraw_everything(); menu_handler_.gui_->redraw_everything();
} }
void console_handler::do_gold() { void console_handler::do_gold() {
menu_handler_.teams_[team_num_ - 1].spend_gold(-lexical_cast_default<int>(data_,1000)); menu_handler_.teams_[team_num_ - 1].spend_gold(-lexical_cast_default<int>(get_data(),1000));
menu_handler_.gui_->redraw_everything(); menu_handler_.gui_->redraw_everything();
} }
void console_handler::do_event() { void console_handler::do_event() {
game_events::fire(data_); game_events::fire(get_data());
menu_handler_.gui_->redraw_everything(); menu_handler_.gui_->redraw_everything();
} }
void console_handler::do_version() { void console_handler::do_version() {