The Battle for Wesnoth  1.13.4+dev
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Modules Pages
map_command_handler.hpp
Go to the documentation of this file.
1 /*
2 Copyright (C) 2006 - 2016 by Joerg Hinrichs <[email protected]>
3 wesnoth playturn Copyright (C) 2003 by David White <[email protected]>
4 Part of the Battle for Wesnoth Project http://www.wesnoth.org/
5 
6 This program is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2 of the License, or
9 (at your option) any later version.
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY.
12 
13 See the COPYING file for more details.
14 */
15 
16 #pragma once
17 #include "config.hpp"
19 #include "formula/string_utils.hpp"
20 #include "gettext.hpp"
21 
22 namespace events {
23 
24 //simple command args parser, separated from command_handler for clarity.
25 //a word begins with a nonspace
26 //n-th arg is n-th word up to the next space
27 //n-th data is n-th word up to the end
28 //cmd is 0-th arg, begins at 0 always.
30 {
31 public:
33  str_(""),
34  args(1, 0),
35  args_end(false)
36  {
37  }
38 
39  explicit cmd_arg_parser(const std::string& str) :
40  str_(str),
41  args(1, 0),
42  args_end(false)
43  {
44  }
45 
46  void parse(const std::string& str)
47  {
48  str_ = str;
49  args.clear();
50  args.push_back(0);
51  args_end = false;
52  }
53 
54  const std::string& get_str() const
55  {
56  return str_;
57  }
58  std::string get_arg(unsigned n) const
59  {
60  advance_to_arg(n);
61  if (n < args.size()) {
62  return std::string(str_, args[n], str_.find(' ', args[n]) - args[n]);
63  }
64  else {
65  return "";
66  }
67  }
68  std::string get_data(unsigned n) const
69  {
70  advance_to_arg(n);
71  if (n < args.size()) {
73  return utils::strip(data);
74  }
75  else {
76  return "";
77  }
78  }
80  {
81  return get_arg(0);
82  }
83 private:
86  void advance_to_arg(unsigned n) const
87  {
88  while (n < args.size() && !args_end) {
89  size_t first_space = str_.find_first_of(' ', args.back());
90  size_t next_arg_begin = str_.find_first_not_of(' ', first_space);
91  if (next_arg_begin != std::string::npos) {
92  args.push_back(next_arg_begin);
93  }
94  else {
95  args_end = true;
96  }
97  }
98  }
100  mutable std::vector<size_t> args;
101  mutable bool args_end;
102 };
103 
104 
105 //A helper class template with a slim public interface
106 //This represents a map of strings to void()-member-function-of-Worker-pointers
107 //with all the common functionality like general help, command help and aliases
108 //Usage (of a derived class): Derived(specific-arguments) d; d.dispatch(command);
109 //Derived classes should override virtual functions where noted.
110 //The template parameter currently must be the dervived class itself,
111 //i.e. class X : public map_command_handler<X>
112 //To add a new command in a derived class:
113 // * add a new private void function() to the derived class
114 // * add it to the function map in init_map there, setting flags like
115 // "D" for debug only (checking the flag is also done in the derived class)
116 // * remember to add some help and/or usage information in init_map()
117 template <class Worker>
119 {
120 public:
121  typedef void (Worker::*command_handler)();
122  struct command
123  {
125  std::string help; //long help text
126  std::string usage; //only args info
128  explicit command(command_handler h, const std::string help = "",
129  const std::string& usage = "", const std::string flags = "")
130  : handler(h), help(help), usage(usage), flags(flags)
131  {
132  }
133  bool has_flag(const char f) const
134  {
135  return flags.find(f) != flags.npos;
136  }
137  command& add_flag(const char f)
138  {
139  flags += f;
140  return *this;
141  }
142  };
143  typedef std::map<std::string, command> command_map;
144  typedef std::map<std::string, std::string> command_alias_map;
145 
147  {
148  }
149 
150  virtual ~map_command_handler() {}
151 
152  bool empty() const
153  {
154  return command_map_.empty();
155  }
156  //actual work function
158  {
159  if (empty()) {
161  init_map();
162  }
163 
164  // We recursively resolve alias (100 max to avoid infinite recursion)
165  for (int i = 0; i < 100; ++i) {
166  parse_cmd(cmd);
167  std::string actual_cmd = get_actual_cmd(get_cmd());
168  if (actual_cmd == get_cmd())
169  break;
171  // translate the command and add space + data if any
172  cmd = actual_cmd + (data.empty() ? "" : " ") + data;
173  }
174 
175  if (get_cmd().empty()) {
176  return;
177  }
178 
179  if (const command* c = get_command(get_cmd())) {
180  if (is_enabled(*c)) {
181  (static_cast<Worker*>(this)->*(c->handler))();
182  }
183  else {
184  print(get_cmd(), _("This command is currently unavailable."));
185  }
186  }
187  else if (help_on_unknown_) {
188  utils::string_map symbols;
189  symbols["command"] = get_cmd();
190  symbols["help_command"] = cmd_prefix_ + "help";
191  print("help", VGETTEXT("Unknown command '$command', try $help_command "
192  "for a list of available commands.", symbols));
193  }
194  }
195 
196  std::vector<std::string> get_commands_list() const
197  {
198  std::vector<std::string> res;
199  for (typename command_map::value_type i : command_map_) {
200  res.push_back(i.first);
201  }
202  return res;
203  }
204  //command error reporting shorthands
205  void command_failed(const std::string& message, bool = false)
206  {
207  print(get_cmd(), _("Error:") + std::string(" ") + message);
208  }
209 protected:
211  {
213  _("Available commands list and command-specific help. "
214  "Use \"help all\" to include currently unavailable commands."),
215  _("do not translate the 'all'^[all|<command>]"));
216  }
217  //derived classes initialize the map overriding this function
218  virtual void init_map() = 0;
219  //overridden in derived classes to actually print the messages somwehere
220  virtual void print(const std::string& title, const std::string& message) = 0;
221  //should be overridden in derived classes if the commands have flags
222  //this should return a string describing what all the flags mean
224  {
225  return "";
226  }
227  //this should return a string describing the flags of the given command
228  virtual std::string get_command_flags_description(const command& /*c*/) const
229  {
230  return "";
231  }
232  //this should be overridden if e.g. flags are used to control command
233  //availability. Return false if the command should not be executed by dispatch()
234  virtual bool is_enabled(const command& /*c*/) const
235  {
236  return true;
237  }
238  virtual void parse_cmd(const std::string& cmd_string)
239  {
240  cap_.parse(cmd_string);
241  }
242  //safe n-th argunment getter
243  virtual std::string get_arg(unsigned argn) const
244  {
245  return cap_.get_arg(argn);
246  }
247  //"data" is n-th arg and everything after it
248  virtual std::string get_data(unsigned argn = 1) const
249  {
250  return cap_.get_data(argn);
251  }
252  virtual std::string get_cmd() const
253  {
254  return cap_.get_cmd();
255  }
256  void command_failed_need_arg(int argn)
257  {
258  utils::string_map symbols;
259  symbols["arg_id"] = std::to_string(argn);
260  command_failed(VGETTEXT("Missing argument $arg_id", symbols));
261  }
262  void print_usage()
263  {
265  }
266  //take aliases into account
268  {
269  command_alias_map::const_iterator i = command_alias_map_.find(cmd);
270  return i != command_alias_map_.end() ? i->second : cmd;
271  }
272  const command* get_command(const std::string& cmd) const
273  {
274  typename command_map::const_iterator i = command_map_.find(cmd);
275  return i != command_map_.end() ? &i->second : 0;
276  }
277  command* get_command(const std::string& cmd)
278  {
279  typename command_map::iterator i = command_map_.find(cmd);
280  return i != command_map_.end() ? &i->second : 0;
281  }
282  void help()
283  {
284  //print command-specific help if available, otherwise list commands
285  if (help_command(get_arg(1))) {
286  return;
287  }
288  std::stringstream ss;
289  bool show_unavail = show_unavailable_ || get_arg(1) == "all";
290  for (typename command_map::value_type i : command_map_) {
291  if (show_unavail || is_enabled(i.second)) {
292  ss << i.first;
293  //if (!i.second.usage.empty()) {
294  // ss << " " << i.second.usage;
295  //}
296  //uncomment the above to display usage information in command list
297  //which might clutter it somewhat
298  if (!i.second.flags.empty()) {
299  ss << " (" << i.second.flags << ") ";
300  }
301  ss << "; ";
302  }
303  }
304  utils::string_map symbols;
305  symbols["flags_description"] = get_flags_description();
306  symbols["list_of_commands"] = ss.str();
307  symbols["help_command"] = cmd_prefix_ + "help";
308  print(_("help"), VGETTEXT("Available commands $flags_description:\n$list_of_commands", symbols));
309  print(_("help"), VGETTEXT("Type $help_command <command> for more info.", symbols));
310  }
311  //returns true if the command exists.
312  bool help_command(const std::string& acmd)
313  {
314  std::string cmd = get_actual_cmd(acmd);
315  const command* c = get_command(cmd);
316  if (c) {
317  std::stringstream ss;
318  ss << cmd_prefix_ << cmd;
319  if (c->help.empty() && c->usage.empty()) {
320  ss << _(" No help available.");
321  }
322  else {
323  ss << " - " << c->help;
324  }
325  if (!c->usage.empty()) {
326  ss << " " << _("Usage:") << " " << cmd_prefix_ << cmd << " " << c->usage;
327  }
329  const std::vector<std::string> l = get_aliases(cmd);
330  if (!l.empty()) {
331  ss << " (" << _("aliases:") << " " << utils::join(l, " ") << ")";
332  }
333  print(_("help"), ss.str());
334  }
335  return c != 0;
336  }
338 protected:
339  //show a "try help" message on unknown command?
340  static void set_help_on_unknown(bool value)
341  {
343  }
344  //this is display-only
346  {
347  cmd_prefix_ = value;
348  }
349  virtual void register_command(const std::string& cmd,
350  command_handler h, const std::string& help = "",
351  const std::string& usage = "", const std::string& flags = "")
352  {
353  command c = command(h, help, usage, flags);
354  std::pair<typename command_map::iterator, bool> r;
355  r = command_map_.insert(typename command_map::value_type(cmd, c));
356  if (!r.second) { //overwrite if exists
357  r.first->second = c;
358  }
359  }
360  virtual void assert_existence(const std::string& cmd) {
361  assert(command_map_.count(cmd));
362  }
363  virtual void register_alias(const std::string& to_cmd,
364  const std::string& cmd)
365  {
366  // disable the assert to allow alias to "command + args"
367  // the fonction assert_existence seems unused now
368  //assert_existence(to_cmd);
369  command_alias_map_[cmd] = to_cmd;
370  }
371  //get all aliases of a command.
372  static const std::vector<std::string> get_aliases(const std::string& cmd)
373  {
374  std::vector<std::string> aliases;
375  typedef command_alias_map::value_type p;
376  for (p i : command_alias_map_) {
377  if (i.second == cmd) {
378  aliases.push_back(i.first);
379  }
380  }
381  return aliases;
382  }
383 private:
384  static command_map command_map_;
385  static command_alias_map command_alias_map_;
386  static bool help_on_unknown_;
387  static bool show_unavailable_;
389 };
390 
391 //static member definitions
392 template <class Worker>
394 
395 template <class Worker>
397 
398 template <class Worker>
400 
401 template <class Worker>
403 
404 template <class Worker>
406 
407 }
void command_failed(const std::string &message, bool=false)
virtual std::string get_command_flags_description(const command &) const
void parse(const std::string &str)
GLvoid **typedef void(GLAPIENTRY *PFNGLGETVERTEXATTRIBDVPROC)(GLuint
Definition: glew.h:1806
void advance_to_arg(unsigned n) const
const GLfloat * c
Definition: glew.h:12741
cmd_arg_parser & operator=(const cmd_arg_parser &)
std::string get_cmd() const
command(command_handler h, const std::string help="", const std::string &usage="", const std::string flags="")
virtual void init_map()=0
virtual bool is_enabled(const command &) const
virtual void assert_existence(const std::string &cmd)
GLsizeiptr const GLvoid GLenum usage
Definition: glew.h:1649
GLint GLenum GLsizei GLint GLsizei const GLvoid * data
Definition: glew.h:1347
Definitions for the interface to Wesnoth Markup Language (WML).
std::vector< std::string > get_commands_list() const
GLdouble l
Definition: glew.h:6966
cmd_arg_parser(const std::string &str)
std::string & strip(std::string &str)
Remove whitespace from the front and back of the string 'str'.
static UNUSEDNOWARN std::string _(const char *str)
Definition: gettext.hpp:82
std::map< std::string, t_string > string_map
virtual void register_alias(const std::string &to_cmd, const std::string &cmd)
std::string get_data(unsigned n) const
GLsizei const GLfloat * value
Definition: glew.h:1817
GLfloat GLfloat p
Definition: glew.h:12766
cl_event GLbitfield flags
Definition: glew.h:3070
std::string get_arg(unsigned n) const
std::string join(T const &v, const std::string &s=",")
Generates a new string joining container items in a list.
std::map< std::string, std::string > command_alias_map
GLuint res
Definition: glew.h:9258
std::map< std::string, command > command_map
command * get_command(const std::string &cmd)
#define VGETTEXT(msgid, symbols)
static void set_cmd_prefix(std::string value)
GLfloat GLfloat GLfloat GLfloat h
Definition: glew.h:5910
size_t i
Definition: function.cpp:1057
virtual std::string get_arg(unsigned argn) const
static const std::vector< std::string > get_aliases(const std::string &cmd)
GLdouble GLdouble GLdouble r
Definition: glew.h:1374
virtual std::string get_cmd() const
const command * get_command(const std::string &cmd) const
Handling of system events.
Definition: manager.hpp:42
GLclampd n
Definition: glew.h:5903
static void set_help_on_unknown(bool value)
std::vector< size_t > args
GLsizei GLenum GLuint GLuint GLsizei char * message
Definition: glew.h:2499
#define c
Definition: glew.h:12743
virtual std::string get_data(unsigned argn=1) const
static command_alias_map command_alias_map_
Definition: help.cpp:57
bool help_command(const std::string &acmd)
virtual void parse_cmd(const std::string &cmd_string)
virtual void register_command(const std::string &cmd, command_handler h, const std::string &help="", const std::string &usage="", const std::string &flags="")
std::string::const_iterator iterator
Definition: tokenizer.hpp:21
virtual std::string get_flags_description() const
GLsizei const GLcharARB ** string
Definition: glew.h:4503
const std::string & get_str() const
virtual void print(const std::string &title, const std::string &message)=0
GLclampf f
Definition: glew.h:3024
std::string get_actual_cmd(const std::string &cmd) const