LCOV - code coverage report
Current view: top level - home/yyan7/compiler/rexompiler/src/util/Sawyer - CommandLineBoost.h (source / functions) Hit Total Coverage
Test: ROSE Lines: 0 3 0.0 %
Date: 2022-12-08 13:48:47 Functions: 0 0 -
Legend: Lines: hit not hit

          Line data    Source code
       1             : // WARNING: Changes to this file must be contributed back to Sawyer or else they will
       2             : //          be clobbered by the next update from Sawyer.  The Sawyer repository is at
       3             : //          https://github.com/matzke1/sawyer.
       4             : 
       5             : 
       6             : 
       7             : 
       8             : #ifndef Sawyer_CommandLine_Boost_H
       9             : #define Sawyer_CommandLine_Boost_H
      10             : 
      11             : #include <Sawyer/CommandLine.h>
      12             : #include <Sawyer/Sawyer.h>
      13             : 
      14             : namespace Sawyer {
      15             : namespace CommandLine {
      16             : 
      17             : /** Drop-in replacement to help boost users.
      18             :  *
      19             :  *  Some users use boost::program_options, but due to the complexity of the interface, they use only the most basic
      20             :  *  features. Essentially, they use boost to map switches like "--foo=bar" into a map containing the pair ("foo", "bar") both
      21             :  *  represented as <code>std::string</code>. Their source code then makes decisions and obtains switch values by querying them
      22             :  *  from this map and converting them to a non-string type that's stored in a C++ variable for later reference.
      23             :  *
      24             :  *  Sawyer::CommandLine can also operate in this "pull" mode although it's most often used in "push" mode, where the
      25             :  *  command-line parsing package is responsible for converting the string argument to a non-string type and storing it in a C++
      26             :  *  variable somewhere. */
      27             : namespace Boost {
      28             : 
      29             : /** Replacement for basic use of boost::program_options::value.
      30             :  *
      31             :  *  The equivalent mechanism in Sawyer is split between two class hierarchies: a class that represents parsing of strings into
      32             :  *  non-string types, and a class that represents storing of non-string values into C++ variables. This separation of concerns
      33             :  *  allows Sawyer to parse one type but store it in a variable of a different, compatible type.  However, most users of Sawyer
      34             :  *  see these classes as functions like @ref Sawyer::CommandLine::nonNegativeIntegerParser "nonNegativeIntegerParser" taking
      35             :  *  one argument: some integer reference in which to ultimately store the result. */
      36             : template<class T>
      37             : struct value {};
      38             : 
      39             : /**  Replacement for basic use of boost::program_options::options_description.
      40             :  *
      41             :  *   The equivalent mechanism in Sawyer is a @ref Sawyer::CommandLine::SwitchGroup "SwitchGroup" that can hold declarations for
      42             :  *   zero or more switches. */
      43             : struct options_description {
      44             :     /** The underlying Sawyer mechanism. */
      45             :     Sawyer::CommandLine::SwitchGroup sg;
      46             : 
      47             :     /** Construct an empty switch group without documentation. */
      48             :     options_description() {}
      49             : 
      50             :     /** Construct an empty switch group having a title. */
      51             :     explicit options_description(const std::string &title): sg(title) {}
      52             : 
      53             :     /** Declare a switch of specified type.
      54             :      *
      55             :      *  As with boost (but not Sawyer) the type of the switch value is wrapped up in a template class called @ref value.
      56             :      *
      57             :      *  There are often slightly different semantics possible depending on the declaration details, but all that is glossed
      58             :      *  over in this simple wrapper.
      59             :      *
      60             :      *  @{ */
      61             :     options_description& operator()(const std::string &switchName, const value<std::string>&, const std::string &doc);
      62             :     options_description& operator()(const std::string &switchName, const value<int>&, const std::string &doc);
      63             :     options_description& operator()(const std::string &switchName, const value<long int>&, const std::string &doc);
      64             :     options_description& operator()(const std::string &switchName, const value<std::vector<int> >&, const std::string &doc);
      65             :     options_description& operator()(const std::string &switchName, const value< std::vector<std::string> >&,
      66             :                                     const std::string &doc);
      67             :     options_description& operator()(const std::string &switchName, const std::string &doc);
      68             :     /** @} */
      69             : 
      70             :     /** Boost intermediate type for adding more switches.
      71             :      *
      72             :      *  Sawyer does not need an intermediate type for adding switches since it uses an "insert" method and has a dedicated
      73             :      *  @ref Sawyer::CommandLine::Switch "Switch" type to hold all the switch properties. */
      74             :     options_description& add_options() {
      75             :         return *this;
      76             :     }
      77             : 
      78             :     /** Insert other switches into this group.
      79             :      *
      80             :      *  Copies the @p other switches into this switch group without making any attempt to resolve conflicts when the @p other
      81             :      *  group has switches with the same name as this group.  If that happens, you might end up with one switch that parses a
      82             :      *  string and another that parses an integer, and depending on their order, the string declaration might hide the integer
      83             :      *  declarations since strings are a superset of integers. */
      84             :     options_description& add(const options_description &other);
      85             : 
      86             :     /** Print switch documentation.
      87             :      *
      88             :      *  Sawyer normally produces manpage-style documentation for an entire program rather than line-oriented documentation for
      89             :      *  just a set of switch declarations. So in order to achieve the desired limited affect, this wrapper instantiates a
      90             :      *  temporary parser that contains these switches and nothing else. */
      91             :     void print() const;
      92             : };
      93             : 
      94             : /** Print documentation for a few switches. */
      95             : std::ostream& operator<<(std::ostream &out, const options_description &x);
      96             : 
      97             : /** Wrapper around Sawyer's CommandLine class. */
      98             : struct command_line_parser {
      99             :     int argc;                                           /**< Argument count saved by c'tor to be available during parsing. */
     100             :     char **argv;                                        /**< Arguments saved by c'tor to be available during parsing. */
     101             :     Sawyer::CommandLine::Parser parser;                 /**< Wrapped parser. */
     102             : 
     103             :     /** Construct a parser.
     104             :      *
     105             :      *  The command-line is not actually parsed here -- its only saved by reference until @ref run is called. */
     106             :     command_line_parser(int argc, char *argv[]): argc(argc), argv(argv) {
     107             :         parser.errorStream(Sawyer::Message::mlog[Sawyer::Message::FATAL]); // use error messages instead of exceptions
     108             :     }
     109             : 
     110             :     /** Insert specified switch declarations.
     111             :      *
     112             :      *  @{ */
     113             :     command_line_parser& options(const options_description&);
     114             :     command_line_parser& options(const Sawyer::CommandLine::SwitchGroup&);
     115             :     /** @} */
     116             : 
     117             :     /** Add predefined switches.
     118             :      *
     119             :      *  The boost version of this method causes boost to capture values of switches that have not been declared. Although
     120             :      *  Sawyer is also capable of skipping over and accumulating arguments that look like switches but which have not been
     121             :      *  declared, doing so is fraught with danger.  Imagine the synchronization and missing code problems that would result if
     122             :      *  a source code compiler took this same approach! */
     123             :     command_line_parser& allow_unregistered() { return *this; }
     124             : 
     125             :     /** Parse command-line.
     126             :      *
     127             :      *  Parses the command line and return results. If the syntax is good, this also runs the "--help" switch if present. */
     128             :     Sawyer::CommandLine::ParserResult run() {
     129             :         return parser.parse(argc, argv).apply();
     130             :     }
     131             : };
     132             : 
     133             : /** Wrapper around parsed values.
     134             :  *
     135             :  *  Sawyer not only stores the parsed switch value, but also much information about where the value came from, it's original
     136             :  *  string form, etc. */
     137           0 : struct parsed_values {                                  // not a boost::program_options type
     138             :     Sawyer::CommandLine::ParsedValues pv;               /**< Wrapped ParsedValues. */
     139             : 
     140             :     /** Wrap nothing. */
     141           0 :     parsed_values() {}
     142             : 
     143             :     /** Wrap ParsedValues. */
     144           0 :     explicit parsed_values(const Sawyer::CommandLine::ParsedValues &pv): pv(pv) {}
     145             : 
     146             :     /** Convert parsed value to another type.
     147             :      *
     148             :      *  @{ */
     149             :     template<class T>
     150             :     T as() {
     151             :         return as_helper(T());
     152             :     }
     153             : 
     154             : private:
     155             :     template<class T>
     156             :     T as_helper(const T&) {
     157             :         ASSERT_forbid(pv.empty());
     158             :         return pv.back().as<T>();
     159             :     }
     160             : 
     161             :     template<class T>
     162             :     std::vector<T> as_helper(const std::vector<T>&) {
     163             :         std::vector<T> retval;
     164             :         BOOST_FOREACH (const Sawyer::CommandLine::ParsedValue &v, pv) {
     165             :             Sawyer::CommandLine::ListParser::ValueList elmts = v.as<Sawyer::CommandLine::ListParser::ValueList>();
     166             :             BOOST_FOREACH (const Sawyer::CommandLine::ParsedValue &elmt, elmts)
     167             :                 retval.push_back(elmt.as<T>());
     168             :         }
     169             :         return retval;
     170             :     }
     171             :     /** @} */
     172             :     
     173             : };
     174             : 
     175             : /** Wrapper around ParserResult. */
     176             : struct variables_map {
     177             :     Sawyer::CommandLine::ParserResult pr;               /**< Wrapped ParserResult. */
     178             : 
     179             :     /** Number of times a switch appeared. */
     180             :     size_t count(const std::string &swName) const;
     181             : 
     182             :     /** Saved values for a switch. */
     183             :     parsed_values operator[](const std::string &swName) const;
     184             : };
     185             : 
     186             : /** Transfer parser results to map. */
     187             : void store(const Sawyer::CommandLine::ParserResult &results, variables_map &output);
     188             : 
     189             : /** Transfer map to C++ variables.
     190             :  *
     191             :  *  This wrapper doesn't try to handle a "push" paradigm, but if you've gone around the wrapper to declare switches using
     192             :  *  Sawyer's interface and those switches were specified with storage locations, the data has already been moved before this
     193             :  *  function is called (it's part of command_line_parser::run). */
     194             : void notify(variables_map&);
     195             : 
     196             : } // namespace
     197             : 
     198             : } // namespace
     199             : } // namespace
     200             : 
     201             : #endif

Generated by: LCOV version 1.14