// Copyright (C) 2006 Davis E. King (davis@dlib.net) // License: Boost Software License See LICENSE.txt for the full license. #ifndef DLIB_CMD_LINE_PARSER_CHECk_1_ #define DLIB_CMD_LINE_PARSER_CHECk_1_ #include "cmd_line_parser_kernel_abstract.h" #include <sstream> #include <string> #include "../string.h" #include <vector> namespace dlib { template < typename clp_base > class cmd_line_parser_check_1 : public clp_base { /*! This extension doesn't add any state. !*/ public: typedef typename clp_base::char_type char_type; typedef typename clp_base::string_type string_type; // ------------------------------------------------------------------------------------ class cmd_line_check_error : public dlib::error { friend class cmd_line_parser_check_1; cmd_line_check_error( error_type t, const string_type& opt_, const string_type& arg_ ) : dlib::error(t), opt(opt_), opt2(), arg(arg_), required_opts() { set_info_string(); } cmd_line_check_error( error_type t, const string_type& opt_, const string_type& opt2_, int // this is just to make this constructor different from the one above ) : dlib::error(t), opt(opt_), opt2(opt2_), arg(), required_opts() { set_info_string(); } cmd_line_check_error ( error_type t, const string_type& opt_, const std::vector<string_type>& vect ) : dlib::error(t), opt(opt_), opt2(), arg(), required_opts(vect) { set_info_string(); } cmd_line_check_error( error_type t, const string_type& opt_ ) : dlib::error(t), opt(opt_), opt2(), arg(), required_opts() { set_info_string(); } ~cmd_line_check_error() throw() {} void set_info_string ( ) { std::ostringstream sout; switch (type) { case EINVALID_OPTION_ARG: sout << "Command line error: '" << narrow(arg) << "' is not a valid argument to " << "the '" << narrow(opt) << "' option."; break; case EMISSING_REQUIRED_OPTION: if (required_opts.size() == 1) { sout << "Command line error: The '" << narrow(opt) << "' option requires the presence of " << "the '" << required_opts[0] << "' option."; } else { sout << "Command line error: The '" << narrow(opt) << "' option requires the presence of " << "one of the following options: "; for (unsigned long i = 0; i < required_opts.size(); ++i) { if (i == required_opts.size()-2) sout << "'" << required_opts[i] << "' or "; else if (i == required_opts.size()-1) sout << "'" << required_opts[i] << "'."; else sout << "'" << required_opts[i] << "', "; } } break; case EINCOMPATIBLE_OPTIONS: sout << "Command line error: The '" << narrow(opt) << "' and '" << narrow(opt2) << "' options cannot be given together on the command line."; break; case EMULTIPLE_OCCURANCES: sout << "Command line error: The '" << narrow(opt) << "' option can only " << "be given on the command line once."; break; default: sout << "Command line error."; break; } const_cast<std::string&>(info) = wrap_string(sout.str(),0,0); } public: const string_type opt; const string_type opt2; const string_type arg; const std::vector<string_type> required_opts; }; // ------------------------------------------------------------------------------------ template < typename T > void check_option_arg_type ( const string_type& option_name ) const; template < typename T > void check_option_arg_range ( const string_type& option_name, const T& first, const T& last ) const; template < typename T, size_t length > void check_option_arg_range ( const string_type& option_name, const T (&arg_set)[length] ) const; template < size_t length > void check_option_arg_range ( const string_type& option_name, const char_type* (&arg_set)[length] ) const; template < size_t length > void check_incompatible_options ( const char_type* (&option_set)[length] ) const; template < size_t length > void check_one_time_options ( const char_type* (&option_set)[length] ) const; void check_incompatible_options ( const string_type& option_name1, const string_type& option_name2 ) const; void check_sub_option ( const string_type& parent_option, const string_type& sub_option ) const; template < size_t length > void check_sub_options ( const string_type& parent_option, const char_type* (&sub_option_set)[length] ) const; template < size_t length > void check_sub_options ( const char_type* (&parent_option_set)[length], const string_type& sub_option ) const; template < size_t parent_length, size_t sub_length > void check_sub_options ( const char_type* (&parent_option_set)[parent_length], const char_type* (&sub_option_set)[sub_length] ) const; }; template < typename clp_base > inline void swap ( cmd_line_parser_check_1<clp_base>& a, cmd_line_parser_check_1<clp_base>& b ) { a.swap(b); } // ---------------------------------------------------------------------------------------- // ---------------------------------------------------------------------------------------- // member function definitions // ---------------------------------------------------------------------------------------- // ---------------------------------------------------------------------------------------- template <typename clp_base> template <typename T> void cmd_line_parser_check_1<clp_base>:: check_option_arg_type ( const string_type& option_name ) const { try { const typename clp_base::option_type& opt = this->option(option_name); const unsigned long number_of_arguments = opt.number_of_arguments(); const unsigned long count = opt.count(); for (unsigned long i = 0; i < number_of_arguments; ++i) { for (unsigned long j = 0; j < count; ++j) { string_cast<T>(opt.argument(i,j)); } } } catch (string_cast_error& e) { throw cmd_line_check_error(EINVALID_OPTION_ARG,option_name,e.info); } } // ---------------------------------------------------------------------------------------- template <typename clp_base> template <typename T> void cmd_line_parser_check_1<clp_base>:: check_option_arg_range ( const string_type& option_name, const T& first, const T& last ) const { try { const typename clp_base::option_type& opt = this->option(option_name); const unsigned long number_of_arguments = opt.number_of_arguments(); const unsigned long count = opt.count(); for (unsigned long i = 0; i < number_of_arguments; ++i) { for (unsigned long j = 0; j < count; ++j) { T temp(string_cast<T>(opt.argument(i,j))); if (temp < first || last < temp) { throw cmd_line_check_error( EINVALID_OPTION_ARG, option_name, opt.argument(i,j) ); } } } } catch (string_cast_error& e) { throw cmd_line_check_error(EINVALID_OPTION_ARG,option_name,e.info); } } // ---------------------------------------------------------------------------------------- template <typename clp_base> template < typename T, size_t length > void cmd_line_parser_check_1<clp_base>:: check_option_arg_range ( const string_type& option_name, const T (&arg_set)[length] ) const { try { const typename clp_base::option_type& opt = this->option(option_name); const unsigned long number_of_arguments = opt.number_of_arguments(); const unsigned long count = opt.count(); for (unsigned long i = 0; i < number_of_arguments; ++i) { for (unsigned long j = 0; j < count; ++j) { T temp(string_cast<T>(opt.argument(i,j))); size_t k = 0; for (; k < length; ++k) { if (arg_set[k] == temp) break; } if (k == length) { throw cmd_line_check_error( EINVALID_OPTION_ARG, option_name, opt.argument(i,j) ); } } } } catch (string_cast_error& e) { throw cmd_line_check_error(EINVALID_OPTION_ARG,option_name,e.info); } } // ---------------------------------------------------------------------------------------- template <typename clp_base> template < size_t length > void cmd_line_parser_check_1<clp_base>:: check_option_arg_range ( const string_type& option_name, const char_type* (&arg_set)[length] ) const { const typename clp_base::option_type& opt = this->option(option_name); const unsigned long number_of_arguments = opt.number_of_arguments(); const unsigned long count = opt.count(); for (unsigned long i = 0; i < number_of_arguments; ++i) { for (unsigned long j = 0; j < count; ++j) { size_t k = 0; for (; k < length; ++k) { if (arg_set[k] == opt.argument(i,j)) break; } if (k == length) { throw cmd_line_check_error( EINVALID_OPTION_ARG, option_name, opt.argument(i,j) ); } } } } // ---------------------------------------------------------------------------------------- template <typename clp_base> template < size_t length > void cmd_line_parser_check_1<clp_base>:: check_incompatible_options ( const char_type* (&option_set)[length] ) const { for (size_t i = 0; i < length; ++i) { for (size_t j = i+1; j < length; ++j) { if (this->option(option_set[i]).count() > 0 && this->option(option_set[j]).count() > 0 ) { throw cmd_line_check_error( EINCOMPATIBLE_OPTIONS, option_set[i], option_set[j], 0 // this argument has no meaning and is only here to make this // call different from the other constructor ); } } } } // ---------------------------------------------------------------------------------------- template <typename clp_base> void cmd_line_parser_check_1<clp_base>:: check_incompatible_options ( const string_type& option_name1, const string_type& option_name2 ) const { if (this->option(option_name1).count() > 0 && this->option(option_name2).count() > 0 ) { throw cmd_line_check_error( EINCOMPATIBLE_OPTIONS, option_name1, option_name2, 0 // this argument has no meaning and is only here to make this // call different from the other constructor ); } } // ---------------------------------------------------------------------------------------- template <typename clp_base> void cmd_line_parser_check_1<clp_base>:: check_sub_option ( const string_type& parent_option, const string_type& sub_option ) const { if (this->option(parent_option).count() == 0) { if (this->option(sub_option).count() != 0) { std::vector<string_type> vect; vect.resize(1); vect[0] = parent_option; throw cmd_line_check_error( EMISSING_REQUIRED_OPTION, sub_option, vect); } } } // ---------------------------------------------------------------------------------------- template <typename clp_base> template < size_t length > void cmd_line_parser_check_1<clp_base>:: check_sub_options ( const string_type& parent_option, const char_type* (&sub_option_set)[length] ) const { if (this->option(parent_option).count() == 0) { size_t i = 0; for (; i < length; ++i) { if (this->option(sub_option_set[i]).count() > 0) break; } if (i != length) { std::vector<string_type> vect; vect.resize(1); vect[0] = parent_option; throw cmd_line_check_error( EMISSING_REQUIRED_OPTION, sub_option_set[i], vect); } } } // ---------------------------------------------------------------------------------------- template <typename clp_base> template < size_t length > void cmd_line_parser_check_1<clp_base>:: check_sub_options ( const char_type* (&parent_option_set)[length], const string_type& sub_option ) const { // first check if the sub_option is present if (this->option(sub_option).count() > 0) { // now check if any of the parents are present bool parents_present = false; for (size_t i = 0; i < length; ++i) { if (this->option(parent_option_set[i]).count() > 0) { parents_present = true; break; } } if (!parents_present) { std::vector<string_type> vect(parent_option_set, parent_option_set+length); throw cmd_line_check_error( EMISSING_REQUIRED_OPTION, sub_option, vect); } } } // ---------------------------------------------------------------------------------------- template <typename clp_base> template < size_t parent_length, size_t sub_length > void cmd_line_parser_check_1<clp_base>:: check_sub_options ( const char_type* (&parent_option_set)[parent_length], const char_type* (&sub_option_set)[sub_length] ) const { // first check if any of the parent options are present bool parents_present = false; for (size_t i = 0; i < parent_length; ++i) { if (this->option(parent_option_set[i]).count() > 0) { parents_present = true; break; } } if (!parents_present) { // none of these sub options should be present size_t i = 0; for (; i < sub_length; ++i) { if (this->option(sub_option_set[i]).count() > 0) break; } if (i != sub_length) { std::vector<string_type> vect(parent_option_set, parent_option_set+parent_length); throw cmd_line_check_error( EMISSING_REQUIRED_OPTION, sub_option_set[i], vect); } } } // ---------------------------------------------------------------------------------------- template <typename clp_base> template < size_t length > void cmd_line_parser_check_1<clp_base>:: check_one_time_options ( const char_type* (&option_set)[length] ) const { size_t i = 0; for (; i < length; ++i) { if (this->option(option_set[i]).count() > 1) break; } if (i != length) { throw cmd_line_check_error( EMULTIPLE_OCCURANCES, option_set[i] ); } } // ---------------------------------------------------------------------------------------- } #endif // DLIB_CMD_LINE_PARSER_CHECk_1_