Difference between revisions of "The libshore C++ Library"
Line 4: | Line 4: | ||
[http://shore.sourceforge.net/libshore-api/files.html Doxygen-generated API documentation] is available. | [http://shore.sourceforge.net/libshore-api/files.html Doxygen-generated API documentation] is available. | ||
− | Further documentation to be written. | + | == 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'' classes 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 exmaple'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) | ||
+ | |||
+ | == Further documentation to be written. == |
Revision as of 16:21, 20 June 2013
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 classes 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 exmaple'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)