/* * An event-driven parser for command-line arguments. * * Copyright (c) 2004-2005 by N.Okazaki * * This software is provided 'as-is', without any express or implied * warranty. In no event will the authors be held liable for any damages * arising from the use of this software. * * Permission is granted to anyone to use this software for any purpose, * including commercial applications, and to alter it and redistribute it * freely, subject to the following restrictions (known as zlib license): * * 1. The origin of this software must not be misrepresented; you must not * claim that you wrote the original software. If you use this software * in a product, an acknowledgment in the product documentation would be * appreciated but is not required. * 2. Altered source versions must be plainly marked as such, and must not be * misrepresented as being the original software. * 3. This notice may not be removed or altered from any source distribution. * * Naoaki Okazaki <okazaki at chokkan.org> * */ /* $Id: optparse.h 2 2006-10-31 00:57:57Z naoaki $ */ /* * Class 'optparse' implements a parser for GNU-style command-line arguments. * Inherit this class to define your own option variables and to implement an * option handler with macros, BEGIN_OPTION_MAP, ON_OPTION(_WITH_ARG), and * END_OPTION_MAP. Consult the sample program attached at the bottom of this * source code. * * This code was comfirmed to be compiled with MCVC++ 2003 and gcc 3.3. * Define _BUILD_NCL_SAMPLE if you want to build a sample program. * $ g++ -D_BUILD_NCL_SAMPLE -xc++ optparse.h */ #ifndef __NCL_OPTPRASE_H__ #define __NCL_OPTPRASE_H__ #include <cstring> #include <sstream> #include <stdexcept> #include <string> #ifdef USE_NCL_NAMESPACE namespace ncl { #endif/*USE_NCL_NAMESPACE*/ /** * An event-driven parser for command-line arguments. * @author Naoaki Okazaki */ class optparse { public: /** * Exception class for unrecognized options. */ class unrecognized_option : public std::invalid_argument { public: unrecognized_option(char shortopt) : std::invalid_argument(std::string("-") + shortopt) {} unrecognized_option(const std::string& longopt) : std::invalid_argument(std::string("--") + longopt) {} }; /** * Exception class for invalid values. */ class invalid_value : public std::invalid_argument { public: std::string optionstr; invalid_value(const std::string& message) : std::invalid_argument(message) {} invalid_value(char shortopt, const char *longopt, const std::string& message) : std::invalid_argument(message), optionstr( shortopt ? (std::string("-") + shortopt) : (longopt ? (std::string("--") + longopt) : std::string("")) ) {} const std::string& option() const {return optionstr; } }; public: /** Construct. */ optparse() {} /** Destruct. */ virtual ~optparse() {} /** * Parse options. * @param argv array of null-terminated strings to be parsed * @param num_argv specifies the number, in strings, of the array * @return the number of used arguments * @throws optparse_exception */ int parse(char * const argv[], int num_argv) { int i; for (i = 0;i < num_argv;++i) { const char *token = argv[i]; if (*token++ == '-') { const char *next_token = (i+1 < num_argv) ? argv[i+1] : ""; if (!*token) { break; // only '-' was found. } else if (*token == '-') { const char *arg = std::strchr(++token, '='); if (arg) { arg++; } else { arg = next_token; } int ret = handle_option(0, token, arg); if (ret < 0) { throw unrecognized_option(token); } if (arg == next_token) { i += ret; } } else { char c; while ((c = *token++) != '\0') { const char *arg = *token ? token : next_token; int ret = handle_option(c, token, arg); if (ret < 0) { throw unrecognized_option(c); } if (ret > 0) { if (arg == token) { token = ""; } else { i++; } } } // while } // else (*token == '-') } else { break; // a non-option argument was fonud. } } // for (i) return i; } protected: /** * Option handler * This function should be overridden by inheritance class. * @param c short option character, 0 for long option * @param longname long option name * @param arg an argument for the option * @return 0 (success); 1 (success with use of an argument); -1 (failed, unrecognized option) * @throws option_parser_exception */ virtual int handle_option(char c, const char *longname, const char *arg) { return 0; } int __optstrcmp(const char *option, const char *longname) { const char *p = std::strchr(option, '='); return p ? std::strncmp(option, longname, p-option) : std::strcmp(option, longname); } }; /** The begin of inline option map. */ #define BEGIN_OPTION_MAP_INLINE() \ virtual int handle_option(char __c, const char *__longname, const char *arg) \ { \ int used_args = 0; \ if (0) { \ /** Define of option map. */ #define DEFINE_OPTION_MAP() \ virtual int handle_option(char __c, const char *__longname, const char *arg); /** Begin of option map implimentation. */ #define BEGIN_OPTION_MAP(_Class) \ int _Class::handle_option(char __c, const char *__longname, const char *arg) \ { \ int used_args = 0; \ if (0) { \ /** An entry of option map */ #define ON_OPTION(test) \ return used_args; \ } else if (test) { \ used_args = 0; \ #define ON_OPTION_WITH_ARG(test) \ return used_args; \ } else if (test) { \ used_args = 1; \ /** The end of option map implementation */ #define END_OPTION_MAP() \ return used_args; \ } \ return -1; \ } \ /** A predicator for short options */ #define SHORTOPT(x) (__c == x) /** A predicator for long options */ #define LONGOPT(x) (!__c && __optstrcmp(__longname, x) == 0) #ifdef USE_NCL_NAMESPACE }; #endif/*USE_NCL_NAMESPACE*/ #ifdef _BUILD_NCL_SAMPLE #include <cstdio> #include <iostream> /** * A class to store parameters specified by command-line arguments */ class option : public optparse { public: int bytes; int lines; bool quiet; option() : bytes(0), lines(0), quiet(false) {} BEGIN_OPTION_MAP_INLINE() ON_OPTION(SHORTOPT('b') || LONGOPT("bytes")) bytes = std::atoi(arg); used_args = 1; // Notify the parser of a consumption of argument. ON_OPTION_WITH_ARG(SHORTOPT('l') || LONGOPT("lines")) lines = std::atoi(arg); // no need of the notification: used_args variable will be set to 1. ON_OPTION(SHORTOPT('q') || LONGOPT("quiet") || LONGOPT("silent")) quiet = true; END_OPTION_MAP() }; int main(int argc, char *argv[]) { try { option opt; int argused = opt.parse(&argv[1], argc-1); // Skip argv[0]. std::cout << "used argv: " << argused << std::endl; std::cout << "bytes: " << opt.bytes << std::endl; std::cout << "lines: " << opt.lines << std::endl; std::cout << "quiet: " << opt.quiet << std::endl; } catch (const optparse::unrecognized_option& e) { std::cout << "unrecognized option: " << e.what() << std::endl; return 1; } catch (const optparse::invalid_value& e) { std::cout << "invalid value: " << e.what() << std::endl; return 1; } return 0; } #endif/*_BUILD_NCL_SAMPLE*/ #endif/*__NCL_OPTPRASE_H__*/