/* Pedantic checker for DWARF files Copyright (C) 2010, 2011 Red Hat, Inc. This file is part of Red Hat elfutils. Red Hat elfutils is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; version 2 of the License. Red Hat elfutils is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with Red Hat elfutils; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301 USA. Red Hat elfutils is an included package of the Open Invention Network. An included package of the Open Invention Network is a package for which Open Invention Network licensees cross-license their patents. No patent license is granted, either expressly or impliedly, by designation as an included package. Should you wish to participate in the Open Invention Network licensing program, please visit www.openinventionnetwork.com . */ #ifndef DWARFLINT_OPTION_HH #define DWARFLINT_OPTION_HH #include #include #include #include #include #include #include "option.ii" #include "checkdescriptor.ii" class options : private std::map { friend class argppp; mutable std::vector _m_opts; option_i *find_opt (int key) const; public: option_i const *getopt (int key) const; argp build_argp (bool toplev = false) const; void add (option_i *opt); using std::map::empty; using std::map::begin; using std::map::end; using std::map::const_iterator; }; // Wrapper of argp parsing. While in general argp does a decent job, // it's not possible to pass user arguments to the parser function // from the argp structure itself, and therefore share the same parser // for all the children. Since that's what we need to do, we need to // pass the "input" argument to argp_parse, and carefully setup the // child_inputs arguments. That means coordinating the whole parsing // process from one place. As a result this is hardly a nice, // reusable piece of code. class argppp { std::vector _m_children_argps; std::vector _m_children_headers; std::vector _m_children; std::vector _m_children_inputs; argp _m_argp; bool _m_inited; argppp (options const &global, std::vector checkdescriptors); static error_t parse_opt (int key, char *arg, argp_state *state); public: static argppp &inst (); void parse (int argc, char **argv, unsigned flags, int *remaining); void help (FILE *stream, unsigned flags, char *name); }; class option_i // we cannot call it simply "option", this conflicts // with another global declaration { // last allocated option unique identifier static int _m_last_opt; protected: // Answer either opt_short argument if it's non-0. Otherwise create // new unique identifier. static int get_short_option (char opt_short); public: virtual ~option_i () {} virtual bool seen () const = 0; virtual argp_option const &build_option () const = 0; virtual error_t parse_opt (char *arg, argp_state *state) = 0; virtual int key () const = 0; }; class option_common : public option_i { argp_option _m_opt; protected: bool _m_seen; option_common (char const *description, char const *arg_description, char const *opt_long, char opt_short, int flags = 0); public: bool seen () const { return _m_seen; } argp_option const & build_option () const { return _m_opt; } int key () const { return _m_opt.key; } }; template class value_converter; template class xoption : public option_common { arg_type _m_arg; public: xoption (char const *description, char const *arg_description, char const *opt_long, char opt_short = 0, int flags = 0) : option_common (description, arg_description, opt_long, opt_short, flags) { } arg_type const &value () const { return _m_arg; } error_t parse_opt (char *arg, __attribute__ ((unused)) argp_state *state) { _m_seen = true; _m_arg = value_converter::convert (arg); return 0; } }; template<> class xoption : public option_common { public: xoption (char const *description, char const *opt_long, char opt_short = 0, int flags = 0) : option_common (description, NULL, opt_long, opt_short, flags) { } error_t parse_opt (char *arg, __attribute__ ((unused)) argp_state *state) { assert (arg == NULL); _m_seen = true; return 0; } // This shouldn't be promoted to option_common, as // e.g. xoption will naturally have a different // implementation. operator bool () { return seen (); } }; template<> struct value_converter { static std::string convert (char const *arg) { if (arg == NULL) return ""; else return arg; } }; template<> struct value_converter { static unsigned convert (char const *arg) { unsigned u; if (std::sscanf (arg, "%u", &u) == 1) return u; else return -1; } }; typedef xoption void_option; typedef xoption string_option; typedef xoption unsigned_option; extern options global_opts; template struct global_opt : public OPT { template global_opt (Args const&... args) : OPT (args...) { global_opts.add (this); } }; #endif//DWARFLINT_OPTION_HH