|
BashSpark
|
This section provides detailed instructions on how to utilize the BashSpark library effectively. It covers essential operations such as creating a shell instance, initializing a shell session, executing commands, and developing custom commands.
By following these guidelines, developers can manage command execution securely and efficiently while avoiding common pitfalls. The examples included showcase practical implementations, helping users to grasp each concept through hands-on coding snippets. Whether you are new to the library or seeking to enhance your command structures, this section serves as a comprehensive guide for operational success.
The first step to run commands is to create a shell. This class is named bs::shell. This class manages the available commands.
This command management method allow the programmer to strictly control the allowed behaviors, preventing security holes. This enhances the safety and reliability of command execution, ensuring that only authorized commands are executed and that errors are handled gracefully.
It is possible to obtain the default shell using method std::unique_ptr<bs::shell> bs::shell::make_default_shell(). The user may also use the default constructor bs::shell() to create a custom shell.
The class shell session may have the following methods overridden to change behavior (such as internationalization):
void shell::msg_error_command_not_found(shell_session &, const std::string &) const: error message on command not found.void shell::msg_error_syntax_error(const shell_session &, const shell_exception &) const: error message on syntax error.Example on obtaining the default session:
Example on building the default session:
In order to execute shell commands a shell session is needed. This class is named bs::shell_session. The class bs::shell_session contains the streams (stdin, stdout, stderr), the environment variables, the function arguments, the local variables, the last exit status code and the shell depth. See the documentation on bs::shell_session for more details.
A bs::shell_session is constructed as shell_session(const shell *pShell, std::istream &oStdIn, std::ostream &oStdOut, std::ostream &oStdErr).
The class bs::shell_session may be extended in order to add custom information to the session. If a custom command uses the custom session, on method bs::command::run(const std::span<const std::string> &, shell_session &) const, it will be necessary to use auto pCustomSession = dynamic_cast<shell_session_custom*>(&oSession) in order to acquire it.
Example of shell session directly linked to terminal:
Running a command requires instantiating the sell session and using the methods shell_status shell::run(std::istream &oCommand,shell_session &oSession);, shell_status run(const std::string &sCommand, shell_session &oSession); or shell_status run(const std::string_view &sCommand, shell_session &oSession);.
Example of hello world:
Creating a custom command requires implementing the bs::command interface.
The custom command class has to override the method bs::command::run(const std::span<const std::string> &, shell_session &) const. On success, the run method must return bs::shell_status::SHELL_SUCCESS. On failure, the run method must return return bs::make_user_code(USER_ERROR_CODE) (see bs::make_user_code) where USER_ERROR_CODE is an unsigned int.
It is recommended to define supplementary functions to print the error messages. Such functions would have a prototype like: print_error(std::ostream& oStderr) const.
Use the function bs::shell::set_command(std::unique_ptr<command> &&) to add the custom commands. The helper template template<typename CommandT, typename... Args> void bs::shell::set_command(Args &&...) may also be useful.
If the custom command uses a custom session, on method bs::command::run(const std::span<const std::string> &, shell_session &) const, it will be necessary to use auto pCustomSession = dynamic_cast<shell_session_custom*>(&oSession) in order to acquire it.
If the custom command calls subshells, to prevent SIGSEGV by stack overflow it is recommended to check the shell depth. Custom commands should not modify this depth lightly.
Example:
Example of adding it to a shell instance:
Example of shell depth check: