From: Petr Machata Date: Fri, 24 Sep 2010 14:00:28 +0000 (+0200) Subject: dwarflint: Recognize options local to check X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=ad52525a24de367ae6965bb96905ef3e721def07;p=thirdparty%2Felfutils.git dwarflint: Recognize options local to check --- diff --git a/dwarflint/main.cc b/dwarflint/main.cc index 0c13bd0a4..c68e35da4 100644 --- a/dwarflint/main.cc +++ b/dwarflint/main.cc @@ -152,12 +152,10 @@ main (int argc, char *argv[]) textdomain (PACKAGE_TARNAME); /* Parse and process arguments. */ - argp_full args (global_opts, - dwarflint::check_registrar::inst ()->get_descriptors ()); - + argppp &argp = argppp::inst (); int remaining; - argp_parse (&args.get (), argc, argv, 0, &remaining, NULL); + argp.parse (argc, argv, 0, &remaining); if (opt_list_checks.seen ()) { @@ -167,7 +165,7 @@ main (int argc, char *argv[]) else if (remaining == argc) { fputs (gettext ("Missing file name.\n"), stderr); - argp_help (&args.get (), stderr, ARGP_HELP_SEE | ARGP_HELP_EXIT_ERR, + argp.help (stderr, ARGP_HELP_SEE | ARGP_HELP_EXIT_ERR, program_invocation_short_name); std::exit (1); } diff --git a/dwarflint/option.cc b/dwarflint/option.cc index a42e05253..99277270e 100644 --- a/dwarflint/option.cc +++ b/dwarflint/option.cc @@ -49,16 +49,6 @@ options::getopt (int key) const return find_opt (key); } -error_t -options::parse_opt (int key, char *arg, - __attribute__ ((unused)) argp_state *state) -{ - option_i *o = global_opts.find_opt (key); // XXX temporary - if (o == NULL) - return ARGP_ERR_UNKNOWN; - return o->parse_opt (arg, state); -} - struct last_option : public argp_option { @@ -88,7 +78,7 @@ options::build_argp (bool toplev) const _m_opts.push_back (last_option ()); argp a = { &_m_opts.front (), - &options::parse_opt, + NULL, // needs to be initialized later, in argppp !toplev ? NULL : "FILE...", !toplev ? NULL : "\ Pedantic checking of DWARF stored in ELF files.", @@ -97,8 +87,18 @@ Pedantic checking of DWARF stored in ELF files.", return a; } -argp_full::argp_full (options const &global, - std::vector checkdescriptors) +argppp & +argppp::inst () +{ + static argppp my + (global_opts, + dwarflint::check_registrar::inst ()->get_descriptors ()); + return my; +} + +argppp::argppp (options const &global, + std::vector checkdescriptors) + : _m_inited (false) { argp main = global.build_argp (true); @@ -108,9 +108,11 @@ argp_full::argp_full (options const &global, if (!(*it)->opts ().empty ()) { _m_children_argps.push_back ((*it)->opts ().build_argp ()); + _m_children_argps.back ().parser = &parse_opt; _m_children_headers.push_back (std::string ("Options for ") + (*it)->name () + ":"); + _m_children_inputs.push_back (&(*it)->opts ()); } unsigned pos = 0; @@ -131,9 +133,46 @@ argp_full::argp_full (options const &global, main.children = &_m_children.front (); } + main.parser = &parse_opt; _m_argp = main; } +error_t +argppp::parse_opt (int key, char *arg, argp_state *state) +{ + if (key == ARGP_KEY_INIT && !inst ()._m_inited) + { + inst ()._m_inited = true; + unsigned i = 0; + for (std::vector::const_iterator it + = inst ()._m_children_inputs.begin (); + it != inst ()._m_children_inputs.end (); ++it) + state->child_inputs[i++] = const_cast (*it); + return 0; + } + else + { + assert (state->input != NULL); + options const *opts = static_cast (state->input); + option_i *o = opts->find_opt (key); + if (o == NULL) + return ARGP_ERR_UNKNOWN; + return o->parse_opt (arg, state); + } +} + +void +argppp::parse (int argc, char **argv, unsigned flags, int *remaining) +{ + assert (!_m_inited); + argp_parse (&_m_argp, argc, argv, flags, remaining, &global_opts); +} + +void +argppp::help (FILE *stream, unsigned flags, char *name) +{ + argp_help (&_m_argp, stream, flags, name); +} int option_i::_m_last_opt = 300; diff --git a/dwarflint/option.hh b/dwarflint/option.hh index 1b5172c25..6bde308c3 100644 --- a/dwarflint/option.hh +++ b/dwarflint/option.hh @@ -39,11 +39,10 @@ class options : private std::map { - friend class option_common; + friend class argppp; mutable std::vector _m_opts; option_i *find_opt (int key) const; - static error_t parse_opt (int key, char *arg, argp_state *state); public: option_i const *getopt (int key) const; @@ -55,17 +54,31 @@ public: } }; -class argp_full +// 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: - argp_full (options const &global, - std::vector checkdescriptors); - argp const &get () const { return _m_argp; } + 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