The libshore C++ Library
Basic functionality used by SHORE is provided as a C++ programming library residing below the directory src/CoreLib of the SHORE source package. The make install command will by default install the libshore library and headers below /usr/local/lib and /usr/local/include, respectively; see the file INSTALL distributed with the SHORE sources for details.
Doxygen-generated API documentation is available.
Contents
The program class
The program class is a command line interface base class providing command line option parsing and documentation as well as application-level exception handling and reporting.
Hello world
// file hello_program.cpp #include <iostream> #include "shore/program/program.hpp" class hello_program :public shore::program { protected: virtual int main() { std::cout << "\nHello, world!\n" << std::endl; } }; int main(int ac, char **av) { hello_program p; p(ac, av); return p.status(); }
Given libshore is installed system-wide, this program may be compiled using the command
$ g++ -lshore -o hello hello_program.cpp
The default behavior of the program base class is to display usage instructions when no command line arguments are provided:
$ ./hello ./hello Usage: ./hello
However, the main() method is invoked if the command's input is a pipe:
$ true | ./hello Hello, world!
This default behavior is sensible for many applications. It may however be altered by overriding the protected base class method basic_sanity_check():
virtual void basic_sanity_check() {}
As a result, the default is no longer to display the help page:
$ ./hello Hello, world!
Adding command line options
Command line options and further usage instructions may be defined in the class's constructor.
For clarity, command line option variables are grouped in a struct config in our example.
For validation of provided user input, the protected base class method sanity_check() may be implemented.
Invalid user input is indicated by throwing an exception of class usage_error defined by the program class:
class hello_program :public shore::program { private: struct config { std::string name; }; config m_conf; protected: virtual void sanity_check() { if(m_conf.name == "Joe") throw usage_error("Joe is not around"); } virtual int main() { std::cout << "\nHello, " << m_conf.name << "!\n" <<std::endl; } public: hello_program() { set_description("Greeter program"); add_option("name,n", &m_conf.name, "The person to greet (but not Joe)"); } }; int main(int ac, char **av) { hello_program p; p(ac, av); return p.status(); }
When called without command line options, the output is now
$ ./hello ./hello --- Greeter program Usage: ./hello [OPTIONS] Allowed options: -n, --name=STRING (not set) The person to greet (but not Joe)
Command line options are automatically verified through sanity_check():
$ ./hello -n Jim Hello, Jim! $ ./hello -n Joe ./hello --- Greeter program Usage: ./hello [OPTIONS] Allowed options: -n, --name=STRING (=Joe) The person to greet (but not Joe) error: Joe is not around
Command line option variables are not restricted to the std::string class, but may be of any class for which an operator>> for std::istream objects is defined. Furthermore, certain classes such as std::vector<T> are handled explicitly by the command line option parser:
#include <iostream> #include <string> #include <vector> #include "shore/program/program.hpp" #include "shore/base/stringops.hpp" // for shore::join() and shore::to_string() class hello_program :public shore::program { private: struct config { std::vector<std::string> names; int times; }; config m_conf; protected: virtual void sanity_check() { if(m_conf.times < 1) throw usage_error("invalid value " + shore::to_string(m_conf.times) + " for --times"); } virtual int main() { for(int i = 0; i < m_conf.times; ++i) std::cout << "Hello, " << shore::join(m_conf.names, ", ") << '!' <<std::endl; } public: hello_program() { m_conf.times=1; set_description("Greeter program"); add_option("names,n", &m_conf.names, "The people to greet", shore::OPT_MANDATORY); add_option("times,t", &m_conf.times, "Greet multiple times"); } };
When correctly invoked, the example's output is
$ ./hello -t 2 -n Jim -n Joe Hello, Jim, Joe! Hello, Jim, Joe!
In this example, the sanity_check() method was changed to ensure correct specification of the --times option. Furthermore, the default value for times was set to 1 in the constructor, which is displayed accordingly in the middle column of the new help page:
$ ./hello ./hello --- Greeter program Usage: ./hello OPTIONS Allowed options: -n, --names=STRING[,...] (mandatory) The people to greet -t, --times=INT (=1) Greet multiple times
For options that do not have a default value, output of the default may be suppressed by specifying shore::OPT_NOTSET as an additional parameter to the add_option() method.
Furthermore, as shown in the example's constructor, shore::OPT_MANDATORY may be specified to instruct the command line option parser to automatically verify that an option was specified by the user:
$ ./hello -t 2 ./hello --- Greeter program Usage: ./hello OPTIONS Allowed options: -n, --names=STRING[,...] (mandatory) The people to greet -t, --times=INT (=2) Greet multiple times error: need `--names' (mandatory)