Listener object is better than 3 lambdas + handle
[lsnes.git] / include / library / command.hpp
blob1fb32883095c36467dd6b0b9c48dd6bc1e830444
1 #ifndef _library_command__hpp__included__
2 #define _library_command__hpp__included__
4 #include <stdexcept>
5 #include <string>
6 #include <set>
7 #include <map>
8 #include <list>
9 #include "threads.hpp"
11 namespace command
13 class set;
14 class base;
15 class factory_base;
17 /**
18 * Set add/drop listener.
20 class set_listener
22 public:
23 /**
24 * Dtor.
26 virtual ~set_listener();
27 /**
28 * New item in set.
30 virtual void create(set& s, const std::string& name, factory_base& cmd) = 0;
31 /**
32 * Deleted item from set.
34 virtual void destroy(set& s, const std::string& name) = 0;
35 /**
36 * Destroyed the entiere set.
38 virtual void kill(set& s) = 0;
41 /**
42 * A set of commands.
44 class set
46 public:
47 /**
48 * Create a new set.
50 set() throw(std::bad_alloc);
51 /**
52 * Destroy a set.
54 ~set() throw();
55 /**
56 * Add a command to set.
58 void do_register(const std::string& name, factory_base& cmd) throw(std::bad_alloc);
59 /**
60 * Remove a command from set.
62 void do_unregister(const std::string& name, factory_base& cmd) throw(std::bad_alloc);
63 /**
64 * Add a notification callback and call ccb on all.
66 * Parameter listener: The listener to add.
68 void add_callback(set_listener& listener) throw(std::bad_alloc);
69 /**
70 * Drop a notification callback and call dcb on all.
72 * Parameter listener: The listener to drop.
74 void drop_callback(set_listener& listener) throw();
75 /**
76 * Obtain list of all commands so far.
78 std::map<std::string, factory_base*> get_commands();
79 private:
80 char dummy;
83 /**
84 * A group of commands (with aliases).
86 class group
88 public:
89 /**
90 * Create a new command group. This also places some builtin commands in that new group.
92 group() throw(std::bad_alloc);
93 /**
94 * Destroy a group.
96 ~group() throw();
97 /**
98 * Look up and invoke a command. The command will undergo alias expansion and recursion checking.
100 * parameter cmd: Command to exeucte.
102 void invoke(const std::string& cmd) throw();
104 * Get set of aliases.
106 std::set<std::string> get_aliases() throw(std::bad_alloc);
108 * Get alias
110 std::string get_alias_for(const std::string& aname) throw(std::bad_alloc);
112 * Set alias
114 void set_alias_for(const std::string& aname, const std::string& avalue) throw(std::bad_alloc);
116 * Is alias name valid.
118 bool valid_alias_name(const std::string& aname) throw(std::bad_alloc);
120 * Register a command.
122 void do_register(const std::string& name, base& cmd) throw(std::bad_alloc);
124 * Unregister a command.
126 void do_unregister(const std::string& name, base& cmd) throw(std::bad_alloc);
128 * Add all commands (including future ones) in given set.
130 void add_set(set& s) throw(std::bad_alloc);
132 * Drop a set of commands.
134 void drop_set(set& s) throw();
136 * Set the output stream.
138 void set_output(std::ostream& s);
140 * Set the OOM panic routine.
142 void set_oom_panic(void (*fn)());
143 private:
144 class listener : public set_listener
146 public:
147 listener(group& _grp);
148 ~listener();
149 void create(set& s, const std::string& name, factory_base& cmd);
150 void destroy(set& s, const std::string& name);
151 void kill(set& s);
152 private:
153 group& grp;
154 } _listener;
155 std::set<std::string> command_stack;
156 std::map<std::string, std::list<std::string>> aliases;
157 std::ostream* output;
158 void (*oom_panic_routine)();
159 base* builtin[1];
163 * A command.
165 class base
167 public:
169 * Register a new command.
171 * parameter group: The group command will be part of.
172 * parameter cmd: The command to register.
173 * parameter dynamic: Should the object be freed when its parent group dies?
174 * throws std::bad_alloc: Not enough memory.
176 base(group& group, const std::string& cmd, bool dynamic) throw(std::bad_alloc);
179 * Deregister a command.
181 virtual ~base() throw();
184 * Invoke a command.
186 * parameter arguments: Arguments to command.
187 * throws std::bad_alloc: Not enough memory.
188 * throws std::runtime_error: Command execution failed.
190 virtual void invoke(const std::string& arguments) throw(std::bad_alloc, std::runtime_error) = 0;
192 * Get short help for command.
194 virtual std::string get_short_help() throw(std::bad_alloc);
197 * Get long help for command.
199 virtual std::string get_long_help() throw(std::bad_alloc);
201 * Get name of command.
203 const std::string& get_name() { return commandname; }
205 * Notify that the parent group died.
207 * Note: Assumed to be called with global lock held.
209 void group_died() throw();
210 private:
211 base(const base&);
212 base& operator=(const base&);
213 std::string commandname;
214 group* in_group;
215 bool is_dynamic;
219 * A command factory.
221 class factory_base
223 public:
224 factory_base() throw() {}
226 * Register a new command.
228 * parameter _set: The set command will be part of.
229 * parameter cmd: The command to register.
230 * throws std::bad_alloc: Not enough memory.
232 void _factory_base(set& _set, const std::string& cmd) throw(std::bad_alloc);
234 * Destructor.
236 virtual ~factory_base() throw();
238 * Make a new command.
240 virtual base* make(group& grp) = 0;
242 * Notify that the parent set died.
244 * Note: Assumed to be called with global lock held.
246 void set_died() throw();
247 private:
248 factory_base(const factory_base&);
249 factory_base& operator=(const factory_base&);
250 std::string commandname;
251 set* in_set;
255 * Mandatory filename
257 struct arg_filename
260 * The filename itself.
262 std::string v;
264 * Return the filename.
266 * returns: The filename.
268 operator std::string() { return v; }
272 * Run command function helper.
274 * parameter fn: Function pointer to invoke.
275 * parameter a: The arguments to pass.
277 template<typename... args>
278 void invoke_fn(void (*fn)(args... arguments), const std::string& a);
281 * Warp function pointer as command.
283 template<typename... args>
284 class _fnptr : public base
286 public:
288 * Create a new command.
290 * parameter group: The group command will be part of.
291 * parameter name: Name of the command
292 * parameter description Description for the command
293 * parameter help: Help for the command.
294 * parameter fn: Function to call on command.
295 * parameter dynamic: Should the object be freed when its parent group dies?
297 _fnptr(group& group, const std::string& name, const std::string& _description,
298 const std::string& _help, void (*_fn)(args... arguments), bool dynamic = false) throw(std::bad_alloc)
299 : base(group, name, dynamic)
301 description = _description;
302 help = _help;
303 fn = _fn;
306 * Destroy a commnad.
308 ~_fnptr() throw()
312 * Invoke a command.
314 * parameter a: Arguments to function.
316 void invoke(const std::string& a) throw(std::bad_alloc, std::runtime_error)
318 invoke_fn(fn, a);
321 * Get short description.
323 * returns: Description.
324 * throw std::bad_alloc: Not enough memory.
326 std::string get_short_help() throw(std::bad_alloc)
328 return description;
331 * Get long help.
333 * returns: help.
334 * throw std::bad_alloc: Not enough memory.
336 std::string get_long_help() throw(std::bad_alloc)
338 return help;
340 private:
341 void (*fn)(args... arguments);
342 std::string description;
343 std::string help;
347 * Function pointer command factory.
349 template<typename... args>
350 class fnptr : public factory_base
352 public:
354 * Create a new command.
356 * parameter _set: The set command will be part of.
357 * parameter name: Name of the command
358 * parameter description Description for the command
359 * parameter help: Help for the command.
360 * parameter fn: Function to call on command.
362 fnptr(set& _set, const std::string& _name, const std::string& _description,
363 const std::string& _help, void (*_fn)(args... arguments)) throw(std::bad_alloc)
365 description = _description;
366 name = _name;
367 help = _help;
368 fn = _fn;
369 _factory_base(_set, name);
372 * Destroy a commnad.
374 ~fnptr() throw()
378 * Make a command.
380 base* make(group& grp) throw(std::bad_alloc)
382 return new _fnptr<args...>(grp, name, description, help, fn, true);
384 private:
385 void (*fn)(args... arguments);
386 std::string description;
387 std::string help;
388 std::string name;
392 * Generic byname factory.
394 template<typename T>
395 class byname_factory : public factory_base
397 public:
399 * Create a new factory.
401 byname_factory(set& s, const std::string& _name)
403 name = _name;
404 _factory_base(s, name);
407 * Destroy.
409 ~byname_factory() throw()
413 * Make a command.
415 base* make(group& grp) throw(std::bad_alloc)
417 return new T(grp, name);
419 private:
420 std::string name;
423 #endif