OpenFPGA/libs/libopenfpgashell/src/shell.h

308 lines
12 KiB
C++

#ifndef SHELL_H
#define SHELL_H
#include <ctime>
#include <functional>
#include <map>
#include <string>
#include <vector>
#include "command.h"
#include "command_context.h"
#include "command_exit_codes.h"
#include "shell_fwd.h"
#include "vtr_range.h"
#include "vtr_vector.h"
/* Begin namespace openfpga */
namespace openfpga {
/*********************************************************************
* Data structure to define a working environment of a mini shell
*
* An example of how to use
* -----------------------
* // Create a new shell with a name of 'OpenFPGA' which use data structure
*OpenfpgaContext for data exchange Shell<OpenfpgaContext> shell("OpenFPGA");
*
* // Add a command 'read_arch' with a description
* ShellCommandId cmd_read_arch = shell.add_command("read_arch", "Command to
*read an architecture");
* // Create a new category and classify the command to it
* ShellCommandCategoryId cmd_category = shell.add_command_category("io");
* shell.set_command_category(cmd_read_arch, cmd_category);
*
* // Add options to the command 'read_arch'
* const Command* cmd_read_arch_obj = shell.command(cmd_read_arch);
* // Detailed examples can be found in Command.h
* ...
*
* // Add execute function to the command 'read_arch'
* // This is the function to be called when the command is used
* // Assume that you have a function read_arch() which does the job of read
*architecture
* // Note that the function read_arch() should return a void with only three
*arguments
* // void read_arch(T, const Command&, const CommandContext&);
* // The first argument is the template type you set when define the shell
* // The second argument is a read-only object storing the options for the
*command
* // The third argument is a read-only object storing the parsing results for
*the command shell.set_command_execute_function(cmd_read_arch, &read_arch);
*
* // Run a shell
* shell.run();
*
********************************************************************/
template <class T>
class Shell {
public: /* Types */
typedef vtr::vector<ShellCommandId, ShellCommandId>::const_iterator
shell_command_iterator;
/* Create range */
typedef vtr::Range<shell_command_iterator> shell_command_range;
/* Enumeration of command types in a shell
* Built-in commands have their own execute functions inside the shell
*/
enum e_exec_func_type {
CONST_STANDARD, /* A standard function requires to read data from the
command context, need the shell to provide command
parsing */
STANDARD, /* A standard function requires to write data to the command
context, need the shell to provide command parsing */
CONST_SHORT, /* A short function requries to read data from the common
context without any command-line options */
SHORT, /* A short function requries to write data to the common context
without any command-line options */
BUILTIN, /* A built-in function which requires no input arguments at all */
FLOATING, /* A floating function which does not need to write/read any data
from the common context. Need shell to provide command parsing
*/
MACRO, /* A black-box function which has its own command-line
parser/interface. No need for shell to provide command parsing */
PLUGIN, /* A plug-in function which is based on other commands, require
shell methods */
NUM_EXEC_FUNC_TYPES
};
public: /* Constructor */
Shell<T>();
public: /* Public accessors */
std::string name() const;
std::string title() const;
shell_command_range commands() const;
ShellCommandId command(const std::string& name) const;
std::string command_description(const ShellCommandId& cmd_id) const;
ShellCommandClassId command_class(const ShellCommandId& cmd_id) const;
std::string command_class_name(const ShellCommandClassId& cmd_class_id) const;
/* We force a read-only return objects for command and command context
* because users should NOT modify any of them!
*/
const Command& command(const ShellCommandId& cmd_id) const;
const CommandContext& command_context(const ShellCommandId& cmd_id) const;
std::vector<ShellCommandId> command_dependency(
const ShellCommandId& cmd_id) const;
std::vector<ShellCommandId> commands_by_class(
const ShellCommandClassId& cmd_class_id) const;
public: /* Public mutators */
void set_name(const char* name);
void add_title(const char* title);
ShellCommandId add_command(const Command& cmd, const char* descr,
const bool& hidden = false);
void set_command_class(const ShellCommandId& cmd_id,
const ShellCommandClassId& cmd_class_id);
/* Link the execute function to a command
* We support here different types of functions to be executed in the shell
* Users just need to specify the function object and its type will be
* automatically inferred
*
* Note that all the function should return exit codes complying to the
* shell_exit_code.h execept the internal functions
*/
/* Standard function, including the data exchange <T> and commands
* This function requires the data exchange <T> to be constant
* This is designed for outputting functions requiring external data than the
* <T>
*/
void set_command_const_execute_function(
const ShellCommandId& cmd_id,
std::function<int(const T&, const Command&, const CommandContext&)>
exec_func);
/* Standard function, including the data exchange <T> and commands
* This function allows modification to the data exchange <T>
* This is designed for implementing functions requiring external data than
* the <T>
*/
void set_command_execute_function(
const ShellCommandId& cmd_id,
std::function<int(T&, const Command&, const CommandContext&)> exec_func);
/* Short function, including only the data exchange <T>
* This function requires the data exchange <T> to be constant
* This is designed for outputting functions without external data than the
* <T>
*/
void set_command_const_execute_function(
const ShellCommandId& cmd_id, std::function<int(const T&)> exec_func);
/* Short function, including only the data exchange <T>
* This function allows modification to the data exchange <T>
* This is designed for internal implementing functions without external data
* than the <T>
*/
void set_command_execute_function(const ShellCommandId& cmd_id,
std::function<int(T&)> exec_func);
/* Built-in function, including only the shell envoriment variables */
void set_command_execute_function(const ShellCommandId& cmd_id,
std::function<void()> exec_func);
/* Floating function, including the only commands
* This is designed for implementing functions which is totally independent
* from <T>
*/
void set_command_execute_function(
const ShellCommandId& cmd_id,
std::function<int(const Command&, const CommandContext&)> exec_func);
/* Marco function, which directly call a macro function without command
* parsing */
void set_command_execute_function(const ShellCommandId& cmd_id,
std::function<int(int, char**)> exec_func);
/* Plug-in function, which calls other command thru shell's APIs */
void set_command_execute_function(
const ShellCommandId& cmd_id,
std::function<int(Shell<T>*, T&, const Command&, const CommandContext&)>
exec_func);
void set_command_dependency(
const ShellCommandId& cmd_id,
const std::vector<ShellCommandId>& cmd_dependency);
ShellCommandClassId add_command_class(const char* name);
public: /* Public validators */
bool valid_command_id(const ShellCommandId& cmd_id) const;
bool valid_command_class_id(const ShellCommandClassId& cmd_class_id) const;
public: /* Public executors */
/* Start the interactive mode, where users will type-in command by command */
void run_interactive_mode(T& context, const bool& quiet_mode = false);
/* Start the script mode, where users provide a file which includes all the
* commands to run */
void run_script_mode(const char* script_file_name, T& context,
const bool& batch_mode = false);
/* Print all the commands by their classes. This is actually the help desk */
void print_commands(const bool& show_hidden = false) const;
/* Find the exit code (assume quit shell now) */
int exit_code() const;
/* Show statistics of errors during command execution */
int execution_errors() const;
/* Quit the shell */
void exit(const int& init_err = 0) const;
/* Execute a command, the command line is the user's input to launch a command
* The common_context is the data structure to exchange data between commands
* Optionally, hidden commands may be forbidden to call. User can allow them
* to be called under different situations
*/
int execute_command(const char* cmd_line, T& common_context,
const bool& allow_hidden_command = true);
private: /* Internal data */
/* Name of the shell, this will appear in the interactive mode */
std::string name_;
/* Title of the shell, this will appear in the interactive mode as an
* introduction */
std::string title_;
/* Unique ids for each class of command */
vtr::vector<ShellCommandClassId, ShellCommandClassId> command_class_ids_;
/* Names for each class of command */
vtr::vector<ShellCommandClassId, std::string> command_class_names_;
/* Unique ids for each command */
vtr::vector<ShellCommandId, ShellCommandId> command_ids_;
/* If this is a hidden command which will not appear in help desk */
vtr::vector<ShellCommandId, bool> command_hidden_;
/* Objects for each command */
vtr::vector<ShellCommandId, Command> commands_;
/* Parsing results for each command */
vtr::vector<ShellCommandId, CommandContext> command_contexts_;
/* Description of the command, this is going to be printed out in the help
* desk */
vtr::vector<ShellCommandId, std::string> command_description_;
/* Class ids for each command */
vtr::vector<ShellCommandId, ShellCommandClassId> command_classes_;
/* Function pointers to execute each command
* We support here three types of functions to be executed in the shell
* 1. Standard function, including the data exchange <T> and commands
* 2. Short function, including only the data exchange <T>
* 3. Built-in function, including only the shell envoriment variables
* 4. Marco function, which directly call a macro function without command
* parsing
*/
vtr::vector<ShellCommandId, std::function<int(const T&, const Command&,
const CommandContext&)>>
command_const_execute_functions_;
vtr::vector<ShellCommandId,
std::function<int(T&, const Command&, const CommandContext&)>>
command_standard_execute_functions_;
vtr::vector<ShellCommandId, std::function<int(const T&)>>
command_short_const_execute_functions_;
vtr::vector<ShellCommandId, std::function<int(T&)>>
command_short_execute_functions_;
vtr::vector<ShellCommandId,
std::function<int(const Command&, const CommandContext&)>>
command_floating_execute_functions_;
vtr::vector<ShellCommandId, std::function<void()>>
command_builtin_execute_functions_;
vtr::vector<ShellCommandId, std::function<int(int, char**)>>
command_macro_execute_functions_;
vtr::vector<ShellCommandId, std::function<int(Shell<T>*, T&, const Command&,
const CommandContext&)>>
command_plugin_execute_functions_;
/* Type of execute functions for each command.
* This is supposed to be an internal data ONLY
*/
vtr::vector<ShellCommandId, e_exec_func_type> command_execute_function_types_;
/* A flag to indicate if the command has been executed */
vtr::vector<ShellCommandId, int> command_status_;
/* Dependency graph for different commands,
* This helps the shell interface to check if a command need other commands to
* be run before its execution
*/
vtr::vector<ShellCommandId, std::vector<ShellCommandId>>
command_dependencies_;
/* Fast name look-up */
std::map<std::string, ShellCommandId> command_name2ids_;
std::map<std::string, ShellCommandClassId> command_class2ids_;
vtr::vector<ShellCommandClassId, std::vector<ShellCommandId>>
commands_by_classes_;
/* Timer */
std::clock_t time_start_;
};
} /* End namespace openfpga */
/* Include the template implementation functions in the header file */
#include "shell.tpp"
#endif