// -*- C++ -*-
//
// This file was generated by CLI, a command line interface
// compiler for C++.
//

// Begin prologue.
//
#include <bpkg/types-parsers.hxx>
//
// End prologue.

#include <bpkg/pkg-bindist-options.hxx>

#include <map>
#include <set>
#include <string>
#include <vector>
#include <utility>
#include <ostream>
#include <sstream>
#include <cstring>

namespace bpkg
{
  namespace cli
  {
    template <typename X>
    struct parser
    {
      static void
      parse (X& x, bool& xs, scanner& s)
      {
        using namespace std;

        const char* o (s.next ());
        if (s.more ())
        {
          string v (s.next ());
          istringstream is (v);
          if (!(is >> x && is.peek () == istringstream::traits_type::eof ()))
            throw invalid_value (o, v);
        }
        else
          throw missing_value (o);

        xs = true;
      }

      static void
      merge (X& b, const X& a)
      {
        b = a;
      }
    };

    template <>
    struct parser<bool>
    {
      static void
      parse (bool& x, bool& xs, scanner& s)
      {
        const char* o (s.next ());

        if (s.more ())
        {
          const char* v (s.next ());

          if (std::strcmp (v, "1")    == 0 ||
              std::strcmp (v, "true") == 0 ||
              std::strcmp (v, "TRUE") == 0 ||
              std::strcmp (v, "True") == 0)
            x = true;
          else if (std::strcmp (v, "0")     == 0 ||
                   std::strcmp (v, "false") == 0 ||
                   std::strcmp (v, "FALSE") == 0 ||
                   std::strcmp (v, "False") == 0)
            x = false;
          else
            throw invalid_value (o, v);
        }
        else
          throw missing_value (o);

        xs = true;
      }

      static void
      merge (bool& b, const bool&)
      {
        b = true;
      }
    };

    template <>
    struct parser<std::string>
    {
      static void
      parse (std::string& x, bool& xs, scanner& s)
      {
        const char* o (s.next ());

        if (s.more ())
          x = s.next ();
        else
          throw missing_value (o);

        xs = true;
      }

      static void
      merge (std::string& b, const std::string& a)
      {
        b = a;
      }
    };

    template <typename X>
    struct parser<std::pair<X, std::size_t> >
    {
      static void
      parse (std::pair<X, std::size_t>& x, bool& xs, scanner& s)
      {
        x.second = s.position ();
        parser<X>::parse (x.first, xs, s);
      }

      static void
      merge (std::pair<X, std::size_t>& b, const std::pair<X, std::size_t>& a)
      {
        b = a;
      }
    };

    template <typename X>
    struct parser<std::vector<X> >
    {
      static void
      parse (std::vector<X>& c, bool& xs, scanner& s)
      {
        X x;
        bool dummy;
        parser<X>::parse (x, dummy, s);
        c.push_back (x);
        xs = true;
      }

      static void
      merge (std::vector<X>& b, const std::vector<X>& a)
      {
        b.insert (b.end (), a.begin (), a.end ());
      }
    };

    template <typename X, typename C>
    struct parser<std::set<X, C> >
    {
      static void
      parse (std::set<X, C>& c, bool& xs, scanner& s)
      {
        X x;
        bool dummy;
        parser<X>::parse (x, dummy, s);
        c.insert (x);
        xs = true;
      }

      static void
      merge (std::set<X, C>& b, const std::set<X, C>& a)
      {
        b.insert (a.begin (), a.end ());
      }
    };

    template <typename K, typename V, typename C>
    struct parser<std::map<K, V, C> >
    {
      static void
      parse (std::map<K, V, C>& m, bool& xs, scanner& s)
      {
        const char* o (s.next ());

        if (s.more ())
        {
          std::size_t pos (s.position ());
          std::string ov (s.next ());
          std::string::size_type p = ov.find ('=');

          K k = K ();
          V v = V ();
          std::string kstr (ov, 0, p);
          std::string vstr (ov, (p != std::string::npos ? p + 1 : ov.size ()));

          int ac (2);
          char* av[] =
          {
            const_cast<char*> (o),
            0
          };

          bool dummy;
          if (!kstr.empty ())
          {
            av[1] = const_cast<char*> (kstr.c_str ());
            argv_scanner s (0, ac, av, false, pos);
            parser<K>::parse (k, dummy, s);
          }

          if (!vstr.empty ())
          {
            av[1] = const_cast<char*> (vstr.c_str ());
            argv_scanner s (0, ac, av, false, pos);
            parser<V>::parse (v, dummy, s);
          }

          m[k] = v;
        }
        else
          throw missing_value (o);

        xs = true;
      }

      static void
      merge (std::map<K, V, C>& b, const std::map<K, V, C>& a)
      {
        for (typename std::map<K, V, C>::const_iterator i (a.begin ()); 
             i != a.end (); 
             ++i)
          b[i->first] = i->second;
      }
    };

    template <typename K, typename V, typename C>
    struct parser<std::multimap<K, V, C> >
    {
      static void
      parse (std::multimap<K, V, C>& m, bool& xs, scanner& s)
      {
        const char* o (s.next ());

        if (s.more ())
        {
          std::size_t pos (s.position ());
          std::string ov (s.next ());
          std::string::size_type p = ov.find ('=');

          K k = K ();
          V v = V ();
          std::string kstr (ov, 0, p);
          std::string vstr (ov, (p != std::string::npos ? p + 1 : ov.size ()));

          int ac (2);
          char* av[] =
          {
            const_cast<char*> (o),
            0
          };

          bool dummy;
          if (!kstr.empty ())
          {
            av[1] = const_cast<char*> (kstr.c_str ());
            argv_scanner s (0, ac, av, false, pos);
            parser<K>::parse (k, dummy, s);
          }

          if (!vstr.empty ())
          {
            av[1] = const_cast<char*> (vstr.c_str ());
            argv_scanner s (0, ac, av, false, pos);
            parser<V>::parse (v, dummy, s);
          }

          m.insert (typename std::multimap<K, V, C>::value_type (k, v));
        }
        else
          throw missing_value (o);

        xs = true;
      }

      static void
      merge (std::multimap<K, V, C>& b, const std::multimap<K, V, C>& a)
      {
        for (typename std::multimap<K, V, C>::const_iterator i (a.begin ()); 
             i != a.end (); 
             ++i)
          b.insert (typename std::multimap<K, V, C>::value_type (i->first,
                                                                 i->second));
      }
    };

    template <typename X, typename T, T X::*M>
    void
    thunk (X& x, scanner& s)
    {
      parser<T>::parse (x.*M, s);
    }

    template <typename X, bool X::*M>
    void
    thunk (X& x, scanner& s)
    {
      s.next ();
      x.*M = true;
    }

    template <typename X, typename T, T X::*M, bool X::*S>
    void
    thunk (X& x, scanner& s)
    {
      parser<T>::parse (x.*M, x.*S, s);
    }
  }
}

#include <map>

namespace bpkg
{
  // pkg_bindist_common_options
  //

  pkg_bindist_common_options::
  pkg_bindist_common_options ()
  : distribution_ (),
    distribution_specified_ (false),
    architecture_ (),
    architecture_specified_ (false),
    recursive_ ("none"),
    recursive_specified_ (false),
    private__ (),
    output_root_ (),
    output_root_specified_ (false),
    wipe_output_ (),
    keep_output_ (),
    allow_dependent_config_ (),
    os_release_id_ (),
    os_release_id_specified_ (false),
    os_release_version_id_ (),
    os_release_version_id_specified_ (false),
    os_release_name_ (),
    os_release_name_specified_ (false)
  {
  }

  bool pkg_bindist_common_options::
  parse (int& argc,
         char** argv,
         bool erase,
         ::bpkg::cli::unknown_mode opt,
         ::bpkg::cli::unknown_mode arg)
  {
    ::bpkg::cli::argv_scanner s (argc, argv, erase);
    bool r = _parse (s, opt, arg);
    return r;
  }

  bool pkg_bindist_common_options::
  parse (int start,
         int& argc,
         char** argv,
         bool erase,
         ::bpkg::cli::unknown_mode opt,
         ::bpkg::cli::unknown_mode arg)
  {
    ::bpkg::cli::argv_scanner s (start, argc, argv, erase);
    bool r = _parse (s, opt, arg);
    return r;
  }

  bool pkg_bindist_common_options::
  parse (int& argc,
         char** argv,
         int& end,
         bool erase,
         ::bpkg::cli::unknown_mode opt,
         ::bpkg::cli::unknown_mode arg)
  {
    ::bpkg::cli::argv_scanner s (argc, argv, erase);
    bool r = _parse (s, opt, arg);
    end = s.end ();
    return r;
  }

  bool pkg_bindist_common_options::
  parse (int start,
         int& argc,
         char** argv,
         int& end,
         bool erase,
         ::bpkg::cli::unknown_mode opt,
         ::bpkg::cli::unknown_mode arg)
  {
    ::bpkg::cli::argv_scanner s (start, argc, argv, erase);
    bool r = _parse (s, opt, arg);
    end = s.end ();
    return r;
  }

  bool pkg_bindist_common_options::
  parse (::bpkg::cli::scanner& s,
         ::bpkg::cli::unknown_mode opt,
         ::bpkg::cli::unknown_mode arg)
  {
    bool r = _parse (s, opt, arg);
    return r;
  }

  void pkg_bindist_common_options::
  merge (const pkg_bindist_common_options& a)
  {
    CLI_POTENTIALLY_UNUSED (a);

    // configuration_options base
    //
    ::bpkg::configuration_options::merge (a);

    if (a.distribution_specified_)
    {
      ::bpkg::cli::parser< string>::merge (
        this->distribution_, a.distribution_);
      this->distribution_specified_ = true;
    }

    if (a.architecture_specified_)
    {
      ::bpkg::cli::parser< string>::merge (
        this->architecture_, a.architecture_);
      this->architecture_specified_ = true;
    }

    if (a.recursive_specified_)
    {
      ::bpkg::cli::parser< string>::merge (
        this->recursive_, a.recursive_);
      this->recursive_specified_ = true;
    }

    if (a.private__)
    {
      ::bpkg::cli::parser< bool>::merge (
        this->private__, a.private__);
    }

    if (a.output_root_specified_)
    {
      ::bpkg::cli::parser< dir_path>::merge (
        this->output_root_, a.output_root_);
      this->output_root_specified_ = true;
    }

    if (a.wipe_output_)
    {
      ::bpkg::cli::parser< bool>::merge (
        this->wipe_output_, a.wipe_output_);
    }

    if (a.keep_output_)
    {
      ::bpkg::cli::parser< bool>::merge (
        this->keep_output_, a.keep_output_);
    }

    if (a.allow_dependent_config_)
    {
      ::bpkg::cli::parser< bool>::merge (
        this->allow_dependent_config_, a.allow_dependent_config_);
    }

    if (a.os_release_id_specified_)
    {
      ::bpkg::cli::parser< string>::merge (
        this->os_release_id_, a.os_release_id_);
      this->os_release_id_specified_ = true;
    }

    if (a.os_release_version_id_specified_)
    {
      ::bpkg::cli::parser< string>::merge (
        this->os_release_version_id_, a.os_release_version_id_);
      this->os_release_version_id_specified_ = true;
    }

    if (a.os_release_name_specified_)
    {
      ::bpkg::cli::parser< string>::merge (
        this->os_release_name_, a.os_release_name_);
      this->os_release_name_specified_ = true;
    }
  }

  ::bpkg::cli::usage_para pkg_bindist_common_options::
  print_usage (::std::ostream& os, ::bpkg::cli::usage_para p)
  {
    CLI_POTENTIALLY_UNUSED (os);

    if (p != ::bpkg::cli::usage_para::none)
      os << ::std::endl;

    os << "\033[1mPKG-BINDIST OPTIONS\033[0m" << ::std::endl
       << ::std::endl
       << "See the following sections below for distribution-specific options:" << ::std::endl
       << ::std::endl
       << "PKG-BINDIST DEBIAN OPTIONS" << ::std::endl
       << ::std::endl
       << "PKG-BINDIST FEDORA OPTIONS" << ::std::endl
       << ::std::endl
       << "PKG-BINDIST ARCHIVE OPTIONS" << ::std::endl;

    os << std::endl
       << "\033[1m--distribution\033[0m \033[4mname\033[0m       Alternative system/distribution package manager to" << ::std::endl
       << "                          generate the binary package for. The valid \033[4mname\033[0m" << ::std::endl
       << "                          values are \033[1mdebian\033[0m (Debian and alike, such as Ubuntu," << ::std::endl
       << "                          etc), \033[1mfedora\033[0m (Fedora and alike, such as RHEL, CentOS," << ::std::endl
       << "                          etc), and \033[1marchive\033[0m (installation archive on any" << ::std::endl
       << "                          operating system). Note that some package managers" << ::std::endl
       << "                          may only be supported when running on certain host" << ::std::endl
       << "                          operating systems." << ::std::endl;

    os << std::endl
       << "\033[1m--architecture\033[0m \033[4mname\033[0m       Alternative architecture to generate the binary" << ::std::endl
       << "                          package for. The valid \033[4mname\033[0m values are" << ::std::endl
       << "                          system/distribution package manager-specific. If" << ::std::endl
       << "                          unspecified, the host architecture is used." << ::std::endl;

    os << std::endl
       << "\033[1m--recursive\033[0m \033[4mmode\033[0m          Bundle or generate dependencies of the specified" << ::std::endl
       << "                          packages. The \033[4mmode\033[0m value can be either \033[1mauto\033[0m, in which" << ::std::endl
       << "                          case only the required files from each dependency" << ::std::endl
       << "                          package are bundled, \033[1mfull\033[0m, in which case all the" << ::std::endl
       << "                          files are bundled, or \033[1mseparate\033[0m, in which case a" << ::std::endl
       << "                          separate binary package is generated for each" << ::std::endl
       << "                          non-system dependency. It can also be \033[1mnone\033[0m which is" << ::std::endl
       << "                          equivalent to not specifying this option (primarily" << ::std::endl
       << "                          useful for overriding a previously-specified value)." << ::std::endl
       << ::std::endl
       << "                          Specifically, in the \033[1mauto\033[0m mode any required files," << ::std::endl
       << "                          such as shared libraries, are pulled implicitly by" << ::std::endl
       << "                          the \033[1minstall\033[0m build system operation, for example, as" << ::std::endl
       << "                          part of installing an executable from one of the" << ::std::endl
       << "                          specified packages. In contrast, in the \033[1mfull\033[0m mode," << ::std::endl
       << "                          each dependency package is installed explicitly and" << ::std::endl
       << "                          completely, as if they were specified as additional" << ::std::endl
       << "                          package on the command line. The \033[1mseparate\033[0m mode is" << ::std::endl
       << "                          equivalent to invoking the \033[1mpkg-bindist\033[0m command on" << ::std::endl
       << "                          each dependency package. See also the \033[1m--private\033[0m" << ::std::endl
       << "                          option." << ::std::endl;

    os << std::endl
       << "\033[1m--private\033[0m                 Enable the private installation subdirectory" << ::std::endl
       << "                          functionality using the package name as the private" << ::std::endl
       << "                          subdirectory. This is primarily useful when bundling" << ::std::endl
       << "                          dependencies, such as shared libraries, of an" << ::std::endl
       << "                          executable that is being installed into a shared" << ::std::endl
       << "                          location, such as \033[1m/usr/\033[0m.  See the" << ::std::endl
       << "                          \033[1mconfig.install.private\033[0m configuration variable" << ::std::endl
       << "                          documentation in the build system manual for details." << ::std::endl
       << "                          This option only makes sense together with the" << ::std::endl
       << "                          \033[1m--recursive\033[0m option \033[1mauto\033[0m and \033[1mfull\033[0m modes." << ::std::endl;

    os << std::endl
       << "\033[1m--output-root\033[0m|\033[1m-o\033[0m \033[4mdir\033[0m      Directory for intermediate files and subdirectories" << ::std::endl
       << "                          as well as the resulting binary package. Note that" << ::std::endl
       << "                          this option may be required for some system package" << ::std::endl
       << "                          managers and may not be specified for others." << ::std::endl;

    os << std::endl
       << "\033[1m--wipe-output\033[0m             Wipe the output root directory (either specified with" << ::std::endl
       << "                          \033[4m--output-root\033[0m or system package manager-specific)" << ::std::endl
       << "                          clean before using it to generate the binary package." << ::std::endl;

    os << std::endl
       << "\033[1m--keep-output\033[0m             Keep intermediate files in the output root directory" << ::std::endl
       << "                          (either specified with \033[4m--output-root\033[0m or system" << ::std::endl
       << "                          package manager-specific) that were used to generate" << ::std::endl
       << "                          the binary package. This is primarily useful for" << ::std::endl
       << "                          troubleshooting." << ::std::endl;

    os << std::endl
       << "\033[1m--allow-dependent-config\033[0m  Allow configuration that is imposed by dependent" << ::std::endl
       << "                          packages. Normally this is undesirable because the" << ::std::endl
       << "                          resulting binary packages become configured" << ::std::endl
       << "                          specificaly for particular dependent packages." << ::std::endl;

    os << std::endl
       << "\033[1m--os-release-id\033[0m \033[4mv\033[0m         Override the \033[1mID\033[0m component in \033[1mos-release(5)\033[0m or" << ::std::endl
       << "                          equivalent. Note that unlike the rest of the" << ::std::endl
       << "                          \033[1m--os-release-*\033[0m options, this option suppresses" << ::std::endl
       << "                          automatic detection of the host operating system" << ::std::endl
       << "                          information." << ::std::endl;

    os << std::endl
       << "\033[1m--os-release-version-id\033[0m \033[4mv\033[0m Override the \033[1mVERSION_ID\033[0m component in \033[1mos-release(5)\033[0m or" << ::std::endl
       << "                          equivalent." << ::std::endl;

    os << std::endl
       << "\033[1m--os-release-name\033[0m \033[4mv\033[0m       Override the \033[1mNAME\033[0m component in \033[1mos-release(5)\033[0m or" << ::std::endl
       << "                          equivalent." << ::std::endl;

    p = ::bpkg::cli::usage_para::option;

    // configuration_options base
    //
    p = ::bpkg::configuration_options::print_usage (os, p);

    return p;
  }

  typedef
  std::map<std::string, void (*) (pkg_bindist_common_options&, ::bpkg::cli::scanner&)>
  _cli_pkg_bindist_common_options_map;

  static _cli_pkg_bindist_common_options_map _cli_pkg_bindist_common_options_map_;

  struct _cli_pkg_bindist_common_options_map_init
  {
    _cli_pkg_bindist_common_options_map_init ()
    {
      _cli_pkg_bindist_common_options_map_["--distribution"] =
      &::bpkg::cli::thunk< pkg_bindist_common_options, string, &pkg_bindist_common_options::distribution_,
        &pkg_bindist_common_options::distribution_specified_ >;
      _cli_pkg_bindist_common_options_map_["--architecture"] =
      &::bpkg::cli::thunk< pkg_bindist_common_options, string, &pkg_bindist_common_options::architecture_,
        &pkg_bindist_common_options::architecture_specified_ >;
      _cli_pkg_bindist_common_options_map_["--recursive"] =
      &::bpkg::cli::thunk< pkg_bindist_common_options, string, &pkg_bindist_common_options::recursive_,
        &pkg_bindist_common_options::recursive_specified_ >;
      _cli_pkg_bindist_common_options_map_["--private"] =
      &::bpkg::cli::thunk< pkg_bindist_common_options, &pkg_bindist_common_options::private__ >;
      _cli_pkg_bindist_common_options_map_["--output-root"] =
      &::bpkg::cli::thunk< pkg_bindist_common_options, dir_path, &pkg_bindist_common_options::output_root_,
        &pkg_bindist_common_options::output_root_specified_ >;
      _cli_pkg_bindist_common_options_map_["-o"] =
      &::bpkg::cli::thunk< pkg_bindist_common_options, dir_path, &pkg_bindist_common_options::output_root_,
        &pkg_bindist_common_options::output_root_specified_ >;
      _cli_pkg_bindist_common_options_map_["--wipe-output"] =
      &::bpkg::cli::thunk< pkg_bindist_common_options, &pkg_bindist_common_options::wipe_output_ >;
      _cli_pkg_bindist_common_options_map_["--keep-output"] =
      &::bpkg::cli::thunk< pkg_bindist_common_options, &pkg_bindist_common_options::keep_output_ >;
      _cli_pkg_bindist_common_options_map_["--allow-dependent-config"] =
      &::bpkg::cli::thunk< pkg_bindist_common_options, &pkg_bindist_common_options::allow_dependent_config_ >;
      _cli_pkg_bindist_common_options_map_["--os-release-id"] =
      &::bpkg::cli::thunk< pkg_bindist_common_options, string, &pkg_bindist_common_options::os_release_id_,
        &pkg_bindist_common_options::os_release_id_specified_ >;
      _cli_pkg_bindist_common_options_map_["--os-release-version-id"] =
      &::bpkg::cli::thunk< pkg_bindist_common_options, string, &pkg_bindist_common_options::os_release_version_id_,
        &pkg_bindist_common_options::os_release_version_id_specified_ >;
      _cli_pkg_bindist_common_options_map_["--os-release-name"] =
      &::bpkg::cli::thunk< pkg_bindist_common_options, string, &pkg_bindist_common_options::os_release_name_,
        &pkg_bindist_common_options::os_release_name_specified_ >;
    }
  };

  static _cli_pkg_bindist_common_options_map_init _cli_pkg_bindist_common_options_map_init_;

  bool pkg_bindist_common_options::
  _parse (const char* o, ::bpkg::cli::scanner& s)
  {
    _cli_pkg_bindist_common_options_map::const_iterator i (_cli_pkg_bindist_common_options_map_.find (o));

    if (i != _cli_pkg_bindist_common_options_map_.end ())
    {
      (*(i->second)) (*this, s);
      return true;
    }

    // configuration_options base
    //
    if (::bpkg::configuration_options::_parse (o, s))
      return true;

    return false;
  }

  bool pkg_bindist_common_options::
  _parse (::bpkg::cli::scanner& s,
          ::bpkg::cli::unknown_mode opt_mode,
          ::bpkg::cli::unknown_mode arg_mode)
  {
    // Can't skip combined flags (--no-combined-flags).
    //
    assert (opt_mode != ::bpkg::cli::unknown_mode::skip);

    bool r = false;
    bool opt = true;

    while (s.more ())
    {
      const char* o = s.peek ();

      if (std::strcmp (o, "--") == 0)
      {
        opt = false;
      }

      if (opt)
      {
        if (_parse (o, s))
        {
          r = true;
          continue;
        }

        if (std::strncmp (o, "-", 1) == 0 && o[1] != '\0')
        {
          // Handle combined option values.
          //
          std::string co;
          if (const char* v = std::strchr (o, '='))
          {
            co.assign (o, 0, v - o);
            ++v;

            int ac (2);
            char* av[] =
            {
              const_cast<char*> (co.c_str ()),
              const_cast<char*> (v)
            };

            ::bpkg::cli::argv_scanner ns (0, ac, av);

            if (_parse (co.c_str (), ns))
            {
              // Parsed the option but not its value?
              //
              if (ns.end () != 2)
                throw ::bpkg::cli::invalid_value (co, v);

              s.next ();
              r = true;
              continue;
            }
            else
            {
              // Set the unknown option and fall through.
              //
              o = co.c_str ();
            }
          }

          // Handle combined flags.
          //
          char cf[3];
          {
            const char* p = o + 1;
            for (; *p != '\0'; ++p)
            {
              if (!((*p >= 'a' && *p <= 'z') ||
                    (*p >= 'A' && *p <= 'Z') ||
                    (*p >= '0' && *p <= '9')))
                break;
            }

            if (*p == '\0')
            {
              for (p = o + 1; *p != '\0'; ++p)
              {
                std::strcpy (cf, "-");
                cf[1] = *p;
                cf[2] = '\0';

                int ac (1);
                char* av[] =
                {
                  cf
                };

                ::bpkg::cli::argv_scanner ns (0, ac, av);

                if (!_parse (cf, ns))
                  break;
              }

              if (*p == '\0')
              {
                // All handled.
                //
                s.next ();
                r = true;
                continue;
              }
              else
              {
                // Set the unknown option and fall through.
                //
                o = cf;
              }
            }
          }

          switch (opt_mode)
          {
            case ::bpkg::cli::unknown_mode::skip:
            {
              s.skip ();
              r = true;
              continue;
            }
            case ::bpkg::cli::unknown_mode::stop:
            {
              break;
            }
            case ::bpkg::cli::unknown_mode::fail:
            {
              throw ::bpkg::cli::unknown_option (o);
            }
          }

          break;
        }
      }

      switch (arg_mode)
      {
        case ::bpkg::cli::unknown_mode::skip:
        {
          s.skip ();
          r = true;
          continue;
        }
        case ::bpkg::cli::unknown_mode::stop:
        {
          break;
        }
        case ::bpkg::cli::unknown_mode::fail:
        {
          throw ::bpkg::cli::unknown_argument (o);
        }
      }

      break;
    }

    return r;
  }

  // pkg_bindist_debian_options
  //

  pkg_bindist_debian_options::
  pkg_bindist_debian_options ()
  : debian_prepare_only_ (),
    debian_buildflags_ ("assign"),
    debian_buildflags_specified_ (false),
    debian_maint_option_ (),
    debian_maint_option_specified_ (false),
    debian_build_option_ (),
    debian_build_option_specified_ (false),
    debian_build_meta_ (),
    debian_build_meta_specified_ (false),
    debian_section_ (),
    debian_section_specified_ (false),
    debian_priority_ (),
    debian_priority_specified_ (false),
    debian_maintainer_ (),
    debian_maintainer_specified_ (false),
    debian_architecture_ (),
    debian_architecture_specified_ (false),
    debian_main_langdep_ (),
    debian_main_langdep_specified_ (false),
    debian_dev_langdep_ (),
    debian_dev_langdep_specified_ (false),
    debian_main_extradep_ (),
    debian_main_extradep_specified_ (false),
    debian_dev_extradep_ (),
    debian_dev_extradep_specified_ (false)
  {
  }

  bool pkg_bindist_debian_options::
  parse (int& argc,
         char** argv,
         bool erase,
         ::bpkg::cli::unknown_mode opt,
         ::bpkg::cli::unknown_mode arg)
  {
    ::bpkg::cli::argv_scanner s (argc, argv, erase);
    bool r = _parse (s, opt, arg);
    return r;
  }

  bool pkg_bindist_debian_options::
  parse (int start,
         int& argc,
         char** argv,
         bool erase,
         ::bpkg::cli::unknown_mode opt,
         ::bpkg::cli::unknown_mode arg)
  {
    ::bpkg::cli::argv_scanner s (start, argc, argv, erase);
    bool r = _parse (s, opt, arg);
    return r;
  }

  bool pkg_bindist_debian_options::
  parse (int& argc,
         char** argv,
         int& end,
         bool erase,
         ::bpkg::cli::unknown_mode opt,
         ::bpkg::cli::unknown_mode arg)
  {
    ::bpkg::cli::argv_scanner s (argc, argv, erase);
    bool r = _parse (s, opt, arg);
    end = s.end ();
    return r;
  }

  bool pkg_bindist_debian_options::
  parse (int start,
         int& argc,
         char** argv,
         int& end,
         bool erase,
         ::bpkg::cli::unknown_mode opt,
         ::bpkg::cli::unknown_mode arg)
  {
    ::bpkg::cli::argv_scanner s (start, argc, argv, erase);
    bool r = _parse (s, opt, arg);
    end = s.end ();
    return r;
  }

  bool pkg_bindist_debian_options::
  parse (::bpkg::cli::scanner& s,
         ::bpkg::cli::unknown_mode opt,
         ::bpkg::cli::unknown_mode arg)
  {
    bool r = _parse (s, opt, arg);
    return r;
  }

  void pkg_bindist_debian_options::
  merge (const pkg_bindist_debian_options& a)
  {
    CLI_POTENTIALLY_UNUSED (a);

    if (a.debian_prepare_only_)
    {
      ::bpkg::cli::parser< bool>::merge (
        this->debian_prepare_only_, a.debian_prepare_only_);
    }

    if (a.debian_buildflags_specified_)
    {
      ::bpkg::cli::parser< string>::merge (
        this->debian_buildflags_, a.debian_buildflags_);
      this->debian_buildflags_specified_ = true;
    }

    if (a.debian_maint_option_specified_)
    {
      ::bpkg::cli::parser< strings>::merge (
        this->debian_maint_option_, a.debian_maint_option_);
      this->debian_maint_option_specified_ = true;
    }

    if (a.debian_build_option_specified_)
    {
      ::bpkg::cli::parser< strings>::merge (
        this->debian_build_option_, a.debian_build_option_);
      this->debian_build_option_specified_ = true;
    }

    if (a.debian_build_meta_specified_)
    {
      ::bpkg::cli::parser< string>::merge (
        this->debian_build_meta_, a.debian_build_meta_);
      this->debian_build_meta_specified_ = true;
    }

    if (a.debian_section_specified_)
    {
      ::bpkg::cli::parser< string>::merge (
        this->debian_section_, a.debian_section_);
      this->debian_section_specified_ = true;
    }

    if (a.debian_priority_specified_)
    {
      ::bpkg::cli::parser< string>::merge (
        this->debian_priority_, a.debian_priority_);
      this->debian_priority_specified_ = true;
    }

    if (a.debian_maintainer_specified_)
    {
      ::bpkg::cli::parser< string>::merge (
        this->debian_maintainer_, a.debian_maintainer_);
      this->debian_maintainer_specified_ = true;
    }

    if (a.debian_architecture_specified_)
    {
      ::bpkg::cli::parser< string>::merge (
        this->debian_architecture_, a.debian_architecture_);
      this->debian_architecture_specified_ = true;
    }

    if (a.debian_main_langdep_specified_)
    {
      ::bpkg::cli::parser< string>::merge (
        this->debian_main_langdep_, a.debian_main_langdep_);
      this->debian_main_langdep_specified_ = true;
    }

    if (a.debian_dev_langdep_specified_)
    {
      ::bpkg::cli::parser< string>::merge (
        this->debian_dev_langdep_, a.debian_dev_langdep_);
      this->debian_dev_langdep_specified_ = true;
    }

    if (a.debian_main_extradep_specified_)
    {
      ::bpkg::cli::parser< string>::merge (
        this->debian_main_extradep_, a.debian_main_extradep_);
      this->debian_main_extradep_specified_ = true;
    }

    if (a.debian_dev_extradep_specified_)
    {
      ::bpkg::cli::parser< string>::merge (
        this->debian_dev_extradep_, a.debian_dev_extradep_);
      this->debian_dev_extradep_specified_ = true;
    }
  }

  ::bpkg::cli::usage_para pkg_bindist_debian_options::
  print_usage (::std::ostream& os, ::bpkg::cli::usage_para p)
  {
    CLI_POTENTIALLY_UNUSED (os);

    if (p != ::bpkg::cli::usage_para::none)
      os << ::std::endl;

    os << "\033[1mDEBIAN DESCRIPTION\033[0m" << ::std::endl
       << ::std::endl
       << "The Debian binary packages are generated by producing the standard" << ::std::endl
       << "\033[1mdebian/control\033[0m, \033[1mdebian/rules\033[0m, and other package metadata files and then" << ::std::endl
       << "invoking \033[1mdpkg-buildpackage(1)\033[0m to build the binary package from that. In" << ::std::endl
       << "particular, the \033[1mdebian/rules\033[0m implemenation is based on the \033[1mdh(1)\033[0m command" << ::std::endl
       << "sequencer. While this approach is normally used to build packages from source," << ::std::endl
       << "this implementation \"pretends\" that this is what's happening by overriding a" << ::std::endl
       << "number of \033[1mdh\033[0m targets to invoke the \033[1mbuild2\033[0m build system on the required packages" << ::std::endl
       << "directly in their \033[1mbpkg\033[0m configuration locations." << ::std::endl
       << ::std::endl
       << "The \033[1mdpkg-dev\033[0m (or \033[1mbuild-essential\033[0m) and \033[1mdebhelper\033[0m Debian packages must be" << ::std::endl
       << "installed before invocation. Typical invocation:" << ::std::endl
       << ::std::endl
       << "bpkg build libhello" << ::std::endl
       << "bpkg test libhello" << ::std::endl
       << "bpkg bindist -o /tmp/output/ libhello" << ::std::endl
       << ::std::endl
       << "Unless the \033[1m--recursive\033[0m option \033[1mauto\033[0m or \033[1mfull\033[0m modes are specified, dependencies of" << ::std::endl
       << "the specified package are translated to dependencies in the resulting binary" << ::std::endl
       << "package using names and versions that refer to packages that would be generated" << ::std::endl
       << "by the \033[1mpkg-bindist\033[0m command (called \"non-native\" packages). If instead you would" << ::std::endl
       << "like certain dependencies to refer to binary packages provided by the" << ::std::endl
       << "distribution (called \"native\" packages), then you need to arrange for them to" << ::std::endl
       << "be built as system (see \033[1mbpkg-pkg-build(1)\033[0m for details). For example, if our" << ::std::endl
       << "\033[1mlibhello\033[0m has a dependency on \033[1mlibsqlite3\033[0m and we would like the binary package" << ::std::endl
       << "for \033[1mlibhello\033[0m to refer to \033[1mlibsqlite3\033[0m from Debian (or alike), then the \033[1mpkg-build\033[0m" << ::std::endl
       << "command would need to be (\033[1m--sys-install\033[0m is optional):" << ::std::endl
       << ::std::endl
       << "bpkg build --sys-install libhello ?sys:libsqlite3" << ::std::endl
       << ::std::endl
       << "Such a package with native dependencies can then be installed (including any" << ::std::endl
       << "missing native dependencies) using the \033[1mapt\033[0m or \033[1mapt-get\033[0m \033[1minstall\033[0m command. Note" << ::std::endl
       << "that the specified \033[1m.deb\033[0m file must include a directory separator (/\033[0m) in order to" << ::std::endl
       << "be recognized as a file rather than a package name. For example:" << ::std::endl
       << ::std::endl
       << "sudo apt-get install ./libhello_1.2.3-0~debian11_amd64.deb \\" << ::std::endl
       << "                     ./libhello-dev_1.2.3-0~debian11_amd64.deb" << ::std::endl
       << ::std::endl
       << "See Debian Package Mapping for Production (bpkg#bindist-mapping-debian-produce)" << ::std::endl
       << "for details on \033[1mbpkg\033[0m to Debian package name and version mapping." << ::std::endl;

    os << std::endl
       << "\033[1mPKG-BINDIST DEBIAN OPTIONS\033[0m" << ::std::endl;

    os << std::endl
       << "\033[1m--debian-prepare-only\033[0m     Prepare all the package metadata files (\033[1mcontrol\033[0m," << ::std::endl
       << "                          \033[1mrules\033[0m, etc) but do not invoke \033[1mdpkg-buildpackage\033[0m to" << ::std::endl
       << "                          generate the binary package, printing its command" << ::std::endl
       << "                          line instead unless requested to be quiet. Implies" << ::std::endl
       << "                          \033[1m--keep-output\033[0m." << ::std::endl;

    os << std::endl
       << "\033[1m--debian-buildflags\033[0m \033[4mmode\033[0m  Package build flags (\033[1mdpkg-buildflags\033[0m) usage mode." << ::std::endl
       << "                          Valid \033[4mmode\033[0m values are \033[1massign\033[0m (use the build flags" << ::std::endl
       << "                          instead of configured), \033[1mappend\033[0m (use the build flags" << ::std::endl
       << "                          in addition to configured, putting them last)," << ::std::endl
       << "                          \033[1mprepend\033[0m (use the build flags in addition to" << ::std::endl
       << "                          configured, putting them first), and \033[1mignore\033[0m (ignore" << ::std::endl
       << "                          build flags). The default mode is \033[1massign\033[0m. Note that" << ::std::endl
       << "                          compiler mode options, if any, are used as" << ::std::endl
       << "                          configured." << ::std::endl;

    os << std::endl
       << "\033[1m--debian-maint-option\033[0m \033[4mo\033[0m   Alternative options to specify in the" << ::std::endl
       << "                          \033[1mDEB_BUILD_MAINT_OPTIONS\033[0m variable of the \033[1mrules\033[0m file." << ::std::endl
       << "                          To specify multiple maintainer options repeat this" << ::std::endl
       << "                          option and/or specify them as a single value" << ::std::endl
       << "                          separated with spaces." << ::std::endl;

    os << std::endl
       << "\033[1m--debian-build-option\033[0m \033[4mo\033[0m   Additional option to pass to the \033[1mdpkg-buildpackage\033[0m" << ::std::endl
       << "                          program. Repeat this option to specify multiple build" << ::std::endl
       << "                          options." << ::std::endl;

    os << std::endl
       << "\033[1m--debian-build-meta\033[0m \033[4mdata\033[0m  Alternative or additional build metadata to include" << ::std::endl
       << "                          in the binary package version. If the specified value" << ::std::endl
       << "                          starts/ends with \033[1m+\033[0m then the value (with \033[1m+\033[0m removed) is" << ::std::endl
       << "                          added after/before the default metadata. Otherwise it" << ::std::endl
       << "                          is used as is instead of the default metadata. If" << ::std::endl
       << "                          empty value is specified, then no build metadata is" << ::std::endl
       << "                          included. By default, the build metadata is the \033[1mID\033[0m" << ::std::endl
       << "                          and \033[1mVERSION_ID\033[0m components from \033[1mos-release(5)\033[0m, for" << ::std::endl
       << "                          example, \033[1mdebian10\033[0m in version \033[1m1.2.3-0~debian10\033[0m. See" << ::std::endl
       << "                          also \033[1m--os-release-*\033[0m." << ::std::endl;

    os << std::endl
       << "\033[1m--debian-section\033[0m \033[4mv\033[0m        Alternative \033[1mSection\033[0m \033[1mcontrol\033[0m file field value for the" << ::std::endl
       << "                          main binary package. The default is either \033[1mlibs\033[0m or" << ::std::endl
       << "                          \033[1mdevel\033[0m, depending on the package type." << ::std::endl;

    os << std::endl
       << "\033[1m--debian-priority\033[0m \033[4mv\033[0m       Alternative \033[1mPriority\033[0m \033[1mcontrol\033[0m file field value. The" << ::std::endl
       << "                          default is \033[1moptional\033[0m." << ::std::endl;

    os << std::endl
       << "\033[1m--debian-maintainer\033[0m \033[4mv\033[0m     Alternative \033[1mMaintainer\033[0m \033[1mcontrol\033[0m file field value. The" << ::std::endl
       << "                          default is the \033[1mpackage-email\033[0m value from package" << ::std::endl
       << "                          \033[1mmanifest\033[0m." << ::std::endl;

    os << std::endl
       << "\033[1m--debian-architecture\033[0m \033[4mv\033[0m   Alternative \033[1mArchitecture\033[0m \033[1mcontrol\033[0m file field value for" << ::std::endl
       << "                          the main binary package, normally \033[1mall\033[0m" << ::std::endl
       << "                          (architecture-independent). The default is \033[1many\033[0m" << ::std::endl
       << "                          (architecture-dependent)." << ::std::endl;

    os << std::endl
       << "\033[1m--debian-main-langdep\033[0m \033[4mv\033[0m   Override the language runtime dependencies (such as" << ::std::endl
       << "                          \033[1mlibc6\033[0m, \033[1mlibstdc++6\033[0m, etc) in the \033[1mDepends\033[0m \033[1mcontrol\033[0m file" << ::std::endl
       << "                          field value of the main binary package." << ::std::endl;

    os << std::endl
       << "\033[1m--debian-dev-langdep\033[0m \033[4mv\033[0m    Override the language runtime dependencies (such as" << ::std::endl
       << "                          \033[1mlibc-dev\033[0m, \033[1mlibstdc++-dev\033[0m, etc) in the \033[1mDepends\033[0m \033[1mcontrol\033[0m" << ::std::endl
       << "                          file field value of the development (\033[1m-dev\033[0m) binary" << ::std::endl
       << "                          package." << ::std::endl;

    os << std::endl
       << "\033[1m--debian-main-extradep\033[0m \033[4mv\033[0m  Extra dependencies to add to the \033[1mDepends\033[0m \033[1mcontrol\033[0m file" << ::std::endl
       << "                          field value of the main binary package." << ::std::endl;

    os << std::endl
       << "\033[1m--debian-dev-extradep\033[0m \033[4mv\033[0m   Extra dependencies to add to the \033[1mDepends\033[0m \033[1mcontrol\033[0m file" << ::std::endl
       << "                          field value of the development (\033[1m-dev\033[0m) binary package." << ::std::endl;

    p = ::bpkg::cli::usage_para::option;

    return p;
  }

  typedef
  std::map<std::string, void (*) (pkg_bindist_debian_options&, ::bpkg::cli::scanner&)>
  _cli_pkg_bindist_debian_options_map;

  static _cli_pkg_bindist_debian_options_map _cli_pkg_bindist_debian_options_map_;

  struct _cli_pkg_bindist_debian_options_map_init
  {
    _cli_pkg_bindist_debian_options_map_init ()
    {
      _cli_pkg_bindist_debian_options_map_["--debian-prepare-only"] =
      &::bpkg::cli::thunk< pkg_bindist_debian_options, &pkg_bindist_debian_options::debian_prepare_only_ >;
      _cli_pkg_bindist_debian_options_map_["--debian-buildflags"] =
      &::bpkg::cli::thunk< pkg_bindist_debian_options, string, &pkg_bindist_debian_options::debian_buildflags_,
        &pkg_bindist_debian_options::debian_buildflags_specified_ >;
      _cli_pkg_bindist_debian_options_map_["--debian-maint-option"] =
      &::bpkg::cli::thunk< pkg_bindist_debian_options, strings, &pkg_bindist_debian_options::debian_maint_option_,
        &pkg_bindist_debian_options::debian_maint_option_specified_ >;
      _cli_pkg_bindist_debian_options_map_["--debian-build-option"] =
      &::bpkg::cli::thunk< pkg_bindist_debian_options, strings, &pkg_bindist_debian_options::debian_build_option_,
        &pkg_bindist_debian_options::debian_build_option_specified_ >;
      _cli_pkg_bindist_debian_options_map_["--debian-build-meta"] =
      &::bpkg::cli::thunk< pkg_bindist_debian_options, string, &pkg_bindist_debian_options::debian_build_meta_,
        &pkg_bindist_debian_options::debian_build_meta_specified_ >;
      _cli_pkg_bindist_debian_options_map_["--debian-section"] =
      &::bpkg::cli::thunk< pkg_bindist_debian_options, string, &pkg_bindist_debian_options::debian_section_,
        &pkg_bindist_debian_options::debian_section_specified_ >;
      _cli_pkg_bindist_debian_options_map_["--debian-priority"] =
      &::bpkg::cli::thunk< pkg_bindist_debian_options, string, &pkg_bindist_debian_options::debian_priority_,
        &pkg_bindist_debian_options::debian_priority_specified_ >;
      _cli_pkg_bindist_debian_options_map_["--debian-maintainer"] =
      &::bpkg::cli::thunk< pkg_bindist_debian_options, string, &pkg_bindist_debian_options::debian_maintainer_,
        &pkg_bindist_debian_options::debian_maintainer_specified_ >;
      _cli_pkg_bindist_debian_options_map_["--debian-architecture"] =
      &::bpkg::cli::thunk< pkg_bindist_debian_options, string, &pkg_bindist_debian_options::debian_architecture_,
        &pkg_bindist_debian_options::debian_architecture_specified_ >;
      _cli_pkg_bindist_debian_options_map_["--debian-main-langdep"] =
      &::bpkg::cli::thunk< pkg_bindist_debian_options, string, &pkg_bindist_debian_options::debian_main_langdep_,
        &pkg_bindist_debian_options::debian_main_langdep_specified_ >;
      _cli_pkg_bindist_debian_options_map_["--debian-dev-langdep"] =
      &::bpkg::cli::thunk< pkg_bindist_debian_options, string, &pkg_bindist_debian_options::debian_dev_langdep_,
        &pkg_bindist_debian_options::debian_dev_langdep_specified_ >;
      _cli_pkg_bindist_debian_options_map_["--debian-main-extradep"] =
      &::bpkg::cli::thunk< pkg_bindist_debian_options, string, &pkg_bindist_debian_options::debian_main_extradep_,
        &pkg_bindist_debian_options::debian_main_extradep_specified_ >;
      _cli_pkg_bindist_debian_options_map_["--debian-dev-extradep"] =
      &::bpkg::cli::thunk< pkg_bindist_debian_options, string, &pkg_bindist_debian_options::debian_dev_extradep_,
        &pkg_bindist_debian_options::debian_dev_extradep_specified_ >;
    }
  };

  static _cli_pkg_bindist_debian_options_map_init _cli_pkg_bindist_debian_options_map_init_;

  bool pkg_bindist_debian_options::
  _parse (const char* o, ::bpkg::cli::scanner& s)
  {
    _cli_pkg_bindist_debian_options_map::const_iterator i (_cli_pkg_bindist_debian_options_map_.find (o));

    if (i != _cli_pkg_bindist_debian_options_map_.end ())
    {
      (*(i->second)) (*this, s);
      return true;
    }

    return false;
  }

  bool pkg_bindist_debian_options::
  _parse (::bpkg::cli::scanner& s,
          ::bpkg::cli::unknown_mode opt_mode,
          ::bpkg::cli::unknown_mode arg_mode)
  {
    // Can't skip combined flags (--no-combined-flags).
    //
    assert (opt_mode != ::bpkg::cli::unknown_mode::skip);

    bool r = false;
    bool opt = true;

    while (s.more ())
    {
      const char* o = s.peek ();

      if (std::strcmp (o, "--") == 0)
      {
        opt = false;
      }

      if (opt)
      {
        if (_parse (o, s))
        {
          r = true;
          continue;
        }

        if (std::strncmp (o, "-", 1) == 0 && o[1] != '\0')
        {
          // Handle combined option values.
          //
          std::string co;
          if (const char* v = std::strchr (o, '='))
          {
            co.assign (o, 0, v - o);
            ++v;

            int ac (2);
            char* av[] =
            {
              const_cast<char*> (co.c_str ()),
              const_cast<char*> (v)
            };

            ::bpkg::cli::argv_scanner ns (0, ac, av);

            if (_parse (co.c_str (), ns))
            {
              // Parsed the option but not its value?
              //
              if (ns.end () != 2)
                throw ::bpkg::cli::invalid_value (co, v);

              s.next ();
              r = true;
              continue;
            }
            else
            {
              // Set the unknown option and fall through.
              //
              o = co.c_str ();
            }
          }

          // Handle combined flags.
          //
          char cf[3];
          {
            const char* p = o + 1;
            for (; *p != '\0'; ++p)
            {
              if (!((*p >= 'a' && *p <= 'z') ||
                    (*p >= 'A' && *p <= 'Z') ||
                    (*p >= '0' && *p <= '9')))
                break;
            }

            if (*p == '\0')
            {
              for (p = o + 1; *p != '\0'; ++p)
              {
                std::strcpy (cf, "-");
                cf[1] = *p;
                cf[2] = '\0';

                int ac (1);
                char* av[] =
                {
                  cf
                };

                ::bpkg::cli::argv_scanner ns (0, ac, av);

                if (!_parse (cf, ns))
                  break;
              }

              if (*p == '\0')
              {
                // All handled.
                //
                s.next ();
                r = true;
                continue;
              }
              else
              {
                // Set the unknown option and fall through.
                //
                o = cf;
              }
            }
          }

          switch (opt_mode)
          {
            case ::bpkg::cli::unknown_mode::skip:
            {
              s.skip ();
              r = true;
              continue;
            }
            case ::bpkg::cli::unknown_mode::stop:
            {
              break;
            }
            case ::bpkg::cli::unknown_mode::fail:
            {
              throw ::bpkg::cli::unknown_option (o);
            }
          }

          break;
        }
      }

      switch (arg_mode)
      {
        case ::bpkg::cli::unknown_mode::skip:
        {
          s.skip ();
          r = true;
          continue;
        }
        case ::bpkg::cli::unknown_mode::stop:
        {
          break;
        }
        case ::bpkg::cli::unknown_mode::fail:
        {
          throw ::bpkg::cli::unknown_argument (o);
        }
      }

      break;
    }

    return r;
  }

  // pkg_bindist_fedora_options
  //

  pkg_bindist_fedora_options::
  pkg_bindist_fedora_options ()
  : fedora_prepare_only_ (),
    fedora_buildflags_ ("assign"),
    fedora_buildflags_specified_ (false),
    fedora_build_option_ (),
    fedora_build_option_specified_ (false),
    fedora_query_option_ (),
    fedora_query_option_specified_ (false),
    fedora_dist_tag_ (),
    fedora_dist_tag_specified_ (false),
    fedora_packager_ (),
    fedora_packager_specified_ (false),
    fedora_build_arch_ (),
    fedora_build_arch_specified_ (false),
    fedora_main_langreq_ (),
    fedora_main_langreq_specified_ (false),
    fedora_devel_langreq_ (),
    fedora_devel_langreq_specified_ (false),
    fedora_stat_langreq_ (),
    fedora_stat_langreq_specified_ (false),
    fedora_main_extrareq_ (),
    fedora_main_extrareq_specified_ (false),
    fedora_devel_extrareq_ (),
    fedora_devel_extrareq_specified_ (false),
    fedora_stat_extrareq_ (),
    fedora_stat_extrareq_specified_ (false)
  {
  }

  bool pkg_bindist_fedora_options::
  parse (int& argc,
         char** argv,
         bool erase,
         ::bpkg::cli::unknown_mode opt,
         ::bpkg::cli::unknown_mode arg)
  {
    ::bpkg::cli::argv_scanner s (argc, argv, erase);
    bool r = _parse (s, opt, arg);
    return r;
  }

  bool pkg_bindist_fedora_options::
  parse (int start,
         int& argc,
         char** argv,
         bool erase,
         ::bpkg::cli::unknown_mode opt,
         ::bpkg::cli::unknown_mode arg)
  {
    ::bpkg::cli::argv_scanner s (start, argc, argv, erase);
    bool r = _parse (s, opt, arg);
    return r;
  }

  bool pkg_bindist_fedora_options::
  parse (int& argc,
         char** argv,
         int& end,
         bool erase,
         ::bpkg::cli::unknown_mode opt,
         ::bpkg::cli::unknown_mode arg)
  {
    ::bpkg::cli::argv_scanner s (argc, argv, erase);
    bool r = _parse (s, opt, arg);
    end = s.end ();
    return r;
  }

  bool pkg_bindist_fedora_options::
  parse (int start,
         int& argc,
         char** argv,
         int& end,
         bool erase,
         ::bpkg::cli::unknown_mode opt,
         ::bpkg::cli::unknown_mode arg)
  {
    ::bpkg::cli::argv_scanner s (start, argc, argv, erase);
    bool r = _parse (s, opt, arg);
    end = s.end ();
    return r;
  }

  bool pkg_bindist_fedora_options::
  parse (::bpkg::cli::scanner& s,
         ::bpkg::cli::unknown_mode opt,
         ::bpkg::cli::unknown_mode arg)
  {
    bool r = _parse (s, opt, arg);
    return r;
  }

  void pkg_bindist_fedora_options::
  merge (const pkg_bindist_fedora_options& a)
  {
    CLI_POTENTIALLY_UNUSED (a);

    if (a.fedora_prepare_only_)
    {
      ::bpkg::cli::parser< bool>::merge (
        this->fedora_prepare_only_, a.fedora_prepare_only_);
    }

    if (a.fedora_buildflags_specified_)
    {
      ::bpkg::cli::parser< string>::merge (
        this->fedora_buildflags_, a.fedora_buildflags_);
      this->fedora_buildflags_specified_ = true;
    }

    if (a.fedora_build_option_specified_)
    {
      ::bpkg::cli::parser< strings>::merge (
        this->fedora_build_option_, a.fedora_build_option_);
      this->fedora_build_option_specified_ = true;
    }

    if (a.fedora_query_option_specified_)
    {
      ::bpkg::cli::parser< strings>::merge (
        this->fedora_query_option_, a.fedora_query_option_);
      this->fedora_query_option_specified_ = true;
    }

    if (a.fedora_dist_tag_specified_)
    {
      ::bpkg::cli::parser< string>::merge (
        this->fedora_dist_tag_, a.fedora_dist_tag_);
      this->fedora_dist_tag_specified_ = true;
    }

    if (a.fedora_packager_specified_)
    {
      ::bpkg::cli::parser< string>::merge (
        this->fedora_packager_, a.fedora_packager_);
      this->fedora_packager_specified_ = true;
    }

    if (a.fedora_build_arch_specified_)
    {
      ::bpkg::cli::parser< string>::merge (
        this->fedora_build_arch_, a.fedora_build_arch_);
      this->fedora_build_arch_specified_ = true;
    }

    if (a.fedora_main_langreq_specified_)
    {
      ::bpkg::cli::parser< strings>::merge (
        this->fedora_main_langreq_, a.fedora_main_langreq_);
      this->fedora_main_langreq_specified_ = true;
    }

    if (a.fedora_devel_langreq_specified_)
    {
      ::bpkg::cli::parser< strings>::merge (
        this->fedora_devel_langreq_, a.fedora_devel_langreq_);
      this->fedora_devel_langreq_specified_ = true;
    }

    if (a.fedora_stat_langreq_specified_)
    {
      ::bpkg::cli::parser< strings>::merge (
        this->fedora_stat_langreq_, a.fedora_stat_langreq_);
      this->fedora_stat_langreq_specified_ = true;
    }

    if (a.fedora_main_extrareq_specified_)
    {
      ::bpkg::cli::parser< strings>::merge (
        this->fedora_main_extrareq_, a.fedora_main_extrareq_);
      this->fedora_main_extrareq_specified_ = true;
    }

    if (a.fedora_devel_extrareq_specified_)
    {
      ::bpkg::cli::parser< strings>::merge (
        this->fedora_devel_extrareq_, a.fedora_devel_extrareq_);
      this->fedora_devel_extrareq_specified_ = true;
    }

    if (a.fedora_stat_extrareq_specified_)
    {
      ::bpkg::cli::parser< strings>::merge (
        this->fedora_stat_extrareq_, a.fedora_stat_extrareq_);
      this->fedora_stat_extrareq_specified_ = true;
    }
  }

  ::bpkg::cli::usage_para pkg_bindist_fedora_options::
  print_usage (::std::ostream& os, ::bpkg::cli::usage_para p)
  {
    CLI_POTENTIALLY_UNUSED (os);

    if (p != ::bpkg::cli::usage_para::none)
      os << ::std::endl;

    os << "\033[1mFEDORA DESCRIPTION\033[0m" << ::std::endl
       << ::std::endl
       << "The Fedora binary packages are generated by producing the standard RPM spec" << ::std::endl
       << "file and then invoking \033[1mrpmbuild(8)\033[0m to build the binary package from that. While" << ::std::endl
       << "this approach is normally used to build packages from source, this" << ::std::endl
       << "implementation \"pretends\" that this is what's happening by overriding a number" << ::std::endl
       << "of RPM spec file sections to invoke the \033[1mbuild2\033[0m build system on the required" << ::std::endl
       << "packages directly in their \033[1mbpkg\033[0m configuration locations." << ::std::endl
       << ::std::endl
       << "The \033[1mrpmdevtools\033[0m Fedora package must be installed before invocation. Typical" << ::std::endl
       << "invocation:" << ::std::endl
       << ::std::endl
       << "bpkg build libhello" << ::std::endl
       << "bpkg test libhello" << ::std::endl
       << "bpkg bindist libhello" << ::std::endl
       << ::std::endl
       << "The resulting binary packages are placed into the standard \033[1mrpmbuild\033[0m output" << ::std::endl
       << "directory (normally \033[1m~/rpmbuild/RPMS/\033[0m\033[4march\033[0m\033[1m/\033[0m\033[0m)." << ::std::endl
       << ::std::endl
       << "Unless the \033[1m--recursive\033[0m option \033[1mauto\033[0m or \033[1mfull\033[0m modes are specified, dependencies of" << ::std::endl
       << "the specified package are translated to dependencies in the resulting binary" << ::std::endl
       << "package using names and versions that refer to packages that would be generated" << ::std::endl
       << "by the \033[1mpkg-bindist\033[0m command (called \"non-native\" packages). If instead you would" << ::std::endl
       << "like certain dependencies to refer to binary packages provided by the" << ::std::endl
       << "distribution (called \"native\" packages), then you need to arrange for them to" << ::std::endl
       << "be built as system (see \033[1mbpkg-pkg-build(1)\033[0m for details). For example, if our" << ::std::endl
       << "\033[1mlibhello\033[0m has a dependency on \033[1mlibsqlite3\033[0m and we would like the binary package" << ::std::endl
       << "for \033[1mlibhello\033[0m to refer to \033[1msqlite-libs\033[0m from Fedora (or alike), then the" << ::std::endl
       << "\033[1mpkg-build\033[0m command would need to be (\033[1m--sys-install\033[0m is optional):" << ::std::endl
       << ::std::endl
       << "bpkg build --sys-install libhello ?sys:libsqlite3" << ::std::endl
       << ::std::endl
       << "Such a package with native dependencies can then be installed (including any" << ::std::endl
       << "missing native dependencies) using the \033[1mdnf install\033[0m command. For example:" << ::std::endl
       << ::std::endl
       << "sudo dnf install libhello-1.2.3-1.fc35.x86_64.rpm \\" << ::std::endl
       << "                 libhello-devel-1.2.3-1.fc35.x86_64.rpm" << ::std::endl
       << ::std::endl
       << "See Fedora Package Mapping for Production (bpkg#bindist-mapping-fedora-produce)" << ::std::endl
       << "for details on \033[1mbpkg\033[0m to Fedora package name and version mapping." << ::std::endl;

    os << std::endl
       << "\033[1mPKG-BINDIST FEDORA OPTIONS\033[0m" << ::std::endl;

    os << std::endl
       << "\033[1m--fedora-prepare-only\033[0m     Prepare the RPM spec file but do not invoke \033[1mrpmbuild\033[0m" << ::std::endl
       << "                          to generate the binary package, printing its command" << ::std::endl
       << "                          line instead unless requested to be quiet." << ::std::endl;

    os << std::endl
       << "\033[1m--fedora-buildflags\033[0m \033[4mmode\033[0m  Package build flags (\033[1m%{build_*flags}\033[0m macros) usage" << ::std::endl
       << "                          mode. Valid \033[4mmode\033[0m values are \033[1massign\033[0m (use the build" << ::std::endl
       << "                          flags instead of configured), \033[1mappend\033[0m (use the build" << ::std::endl
       << "                          flags in addition to configured, putting them last)," << ::std::endl
       << "                          \033[1mprepend\033[0m (use the build flags in addition to" << ::std::endl
       << "                          configured, putting them first), and \033[1mignore\033[0m (ignore" << ::std::endl
       << "                          build flags). The default mode is \033[1massign\033[0m. Note that" << ::std::endl
       << "                          compiler mode options, if any, are used as" << ::std::endl
       << "                          configured." << ::std::endl;

    os << std::endl
       << "\033[1m--fedora-build-option\033[0m \033[4mo\033[0m   Additional option to pass to the \033[1mrpmbuild\033[0m program. If" << ::std::endl
       << "                          specified, these options must be consistent with the" << ::std::endl
       << "                          query options (\033[1m--fedora-query-option\033[0m) to result in" << ::std::endl
       << "                          identical macro expansions. Repeat this option to" << ::std::endl
       << "                          specify multiple build options." << ::std::endl;

    os << std::endl
       << "\033[1m--fedora-query-option\033[0m \033[4mo\033[0m   Additional option to pass to the \033[1mrpm\033[0m program. This" << ::std::endl
       << "                          program is used to query RPM macro values which" << ::std::endl
       << "                          affect the binary package. If specified, these" << ::std::endl
       << "                          options must be consistent with the build options" << ::std::endl
       << "                          (\033[1m--fedora-build-option\033[0m) to result in identical macro" << ::std::endl
       << "                          expansions. Repeat this option to specify multiple" << ::std::endl
       << "                          query options." << ::std::endl;

    os << std::endl
       << "\033[1m--fedora-dist-tag\033[0m \033[4mtag\033[0m     Alternative or additional distribution tag to use in" << ::std::endl
       << "                          the binary package release. If the specified value" << ::std::endl
       << "                          starts/ends with \033[1m+\033[0m then the value (with \033[1m+\033[0m removed) is" << ::std::endl
       << "                          added after/before the default distribution tag." << ::std::endl
       << "                          Otherwise it is used as is instead of the default" << ::std::endl
       << "                          tag. If empty value is specified, then no" << ::std::endl
       << "                          distribution tag is included. The default is a value" << ::std::endl
       << "                          that identifies the distribution being used to build" << ::std::endl
       << "                          the package, for example, \033[1mfc35\033[0m for Fedora 35 or \033[1mel8\033[0m" << ::std::endl
       << "                          for RHEL 8." << ::std::endl;

    os << std::endl
       << "\033[1m--fedora-packager\033[0m \033[4mv\033[0m       Alternative \033[1mPackager\033[0m RPM spec file directive value." << ::std::endl
       << "                          The default is the \033[1mpackage-email\033[0m value from package" << ::std::endl
       << "                          \033[1mmanifest\033[0m. If empty value is specified, then the" << ::std::endl
       << "                          \033[1mPackager\033[0m directive is omitted from the spec file." << ::std::endl;

    os << std::endl
       << "\033[1m--fedora-build-arch\033[0m \033[4mv\033[0m     \033[1mBuildArch\033[0m RPM spec file directive value for the main" << ::std::endl
       << "                          binary package, normally \033[1mnoarch\033[0m" << ::std::endl
       << "                          (architecture-independent). By default the directive" << ::std::endl
       << "                          is omitted, assuming that the package is" << ::std::endl
       << "                          architecture-dependent." << ::std::endl;

    os << std::endl
       << "\033[1m--fedora-main-langreq\033[0m \033[4mv\033[0m   Override the language runtime dependencies (such as" << ::std::endl
       << "                          \033[1mglibc\033[0m, \033[1mlibstdc++\033[0m, etc) of the main binary package by" << ::std::endl
       << "                          replacing the corresponding \033[1mRequires\033[0m RPM spec file" << ::std::endl
       << "                          directives. If empty value is specified then no" << ::std::endl
       << "                          language runtime dependencies are specified. Repeat" << ::std::endl
       << "                          this option to specify multiple language runtime" << ::std::endl
       << "                          dependencies." << ::std::endl;

    os << std::endl
       << "\033[1m--fedora-devel-langreq\033[0m \033[4mv\033[0m  Override the language runtime dependencies (such as" << ::std::endl
       << "                          \033[1mglibc-devel\033[0m, \033[1mlibstdc++-devel\033[0m, etc) of the development" << ::std::endl
       << "                          (\033[1m-devel\033[0m) binary package by replacing the" << ::std::endl
       << "                          corresponding \033[1mRequires\033[0m RPM spec file directives. If" << ::std::endl
       << "                          empty value is specified then no language runtime" << ::std::endl
       << "                          dependencies are specified. Repeat this option to" << ::std::endl
       << "                          specify multiple language runtime dependencies." << ::std::endl;

    os << std::endl
       << "\033[1m--fedora-stat-langreq\033[0m \033[4mv\033[0m   Override the language runtime dependencies (such as" << ::std::endl
       << "                          \033[1mglibc-static\033[0m, \033[1mlibstdc++-static\033[0m, etc) of the static" << ::std::endl
       << "                          libraries (\033[1m-static\033[0m) binary package by replacing the" << ::std::endl
       << "                          corresponding \033[1mRequires\033[0m RPM spec file directives. If" << ::std::endl
       << "                          empty value is specified then no language runtime" << ::std::endl
       << "                          dependencies are specified. Repeat this option to" << ::std::endl
       << "                          specify multiple language runtime dependencies." << ::std::endl;

    os << std::endl
       << "\033[1m--fedora-main-extrareq\033[0m \033[4mv\033[0m  Extra dependency to add to the main binary package as" << ::std::endl
       << "                          an additional \033[1mRequires\033[0m RPM spec file directive." << ::std::endl
       << "                          Repeat this option to specify multiple extra" << ::std::endl
       << "                          dependencies." << ::std::endl;

    os << std::endl
       << "\033[1m--fedora-devel-extrareq\033[0m \033[4mv\033[0m Extra dependency to add to the development (\033[1m-devel\033[0m)" << ::std::endl
       << "                          binary package as an additional \033[1mRequires\033[0m RPM spec" << ::std::endl
       << "                          file directive. Repeat this option to specify" << ::std::endl
       << "                          multiple extra dependencies." << ::std::endl;

    os << std::endl
       << "\033[1m--fedora-stat-extrareq\033[0m \033[4mv\033[0m  Extra dependency to add to the static libraries" << ::std::endl
       << "                          (\033[1m-static\033[0m) binary package as an additional \033[1mRequires\033[0m" << ::std::endl
       << "                          RPM spec file directive. Repeat this option to" << ::std::endl
       << "                          specify multiple extra dependencies." << ::std::endl;

    p = ::bpkg::cli::usage_para::option;

    return p;
  }

  typedef
  std::map<std::string, void (*) (pkg_bindist_fedora_options&, ::bpkg::cli::scanner&)>
  _cli_pkg_bindist_fedora_options_map;

  static _cli_pkg_bindist_fedora_options_map _cli_pkg_bindist_fedora_options_map_;

  struct _cli_pkg_bindist_fedora_options_map_init
  {
    _cli_pkg_bindist_fedora_options_map_init ()
    {
      _cli_pkg_bindist_fedora_options_map_["--fedora-prepare-only"] =
      &::bpkg::cli::thunk< pkg_bindist_fedora_options, &pkg_bindist_fedora_options::fedora_prepare_only_ >;
      _cli_pkg_bindist_fedora_options_map_["--fedora-buildflags"] =
      &::bpkg::cli::thunk< pkg_bindist_fedora_options, string, &pkg_bindist_fedora_options::fedora_buildflags_,
        &pkg_bindist_fedora_options::fedora_buildflags_specified_ >;
      _cli_pkg_bindist_fedora_options_map_["--fedora-build-option"] =
      &::bpkg::cli::thunk< pkg_bindist_fedora_options, strings, &pkg_bindist_fedora_options::fedora_build_option_,
        &pkg_bindist_fedora_options::fedora_build_option_specified_ >;
      _cli_pkg_bindist_fedora_options_map_["--fedora-query-option"] =
      &::bpkg::cli::thunk< pkg_bindist_fedora_options, strings, &pkg_bindist_fedora_options::fedora_query_option_,
        &pkg_bindist_fedora_options::fedora_query_option_specified_ >;
      _cli_pkg_bindist_fedora_options_map_["--fedora-dist-tag"] =
      &::bpkg::cli::thunk< pkg_bindist_fedora_options, string, &pkg_bindist_fedora_options::fedora_dist_tag_,
        &pkg_bindist_fedora_options::fedora_dist_tag_specified_ >;
      _cli_pkg_bindist_fedora_options_map_["--fedora-packager"] =
      &::bpkg::cli::thunk< pkg_bindist_fedora_options, string, &pkg_bindist_fedora_options::fedora_packager_,
        &pkg_bindist_fedora_options::fedora_packager_specified_ >;
      _cli_pkg_bindist_fedora_options_map_["--fedora-build-arch"] =
      &::bpkg::cli::thunk< pkg_bindist_fedora_options, string, &pkg_bindist_fedora_options::fedora_build_arch_,
        &pkg_bindist_fedora_options::fedora_build_arch_specified_ >;
      _cli_pkg_bindist_fedora_options_map_["--fedora-main-langreq"] =
      &::bpkg::cli::thunk< pkg_bindist_fedora_options, strings, &pkg_bindist_fedora_options::fedora_main_langreq_,
        &pkg_bindist_fedora_options::fedora_main_langreq_specified_ >;
      _cli_pkg_bindist_fedora_options_map_["--fedora-devel-langreq"] =
      &::bpkg::cli::thunk< pkg_bindist_fedora_options, strings, &pkg_bindist_fedora_options::fedora_devel_langreq_,
        &pkg_bindist_fedora_options::fedora_devel_langreq_specified_ >;
      _cli_pkg_bindist_fedora_options_map_["--fedora-stat-langreq"] =
      &::bpkg::cli::thunk< pkg_bindist_fedora_options, strings, &pkg_bindist_fedora_options::fedora_stat_langreq_,
        &pkg_bindist_fedora_options::fedora_stat_langreq_specified_ >;
      _cli_pkg_bindist_fedora_options_map_["--fedora-main-extrareq"] =
      &::bpkg::cli::thunk< pkg_bindist_fedora_options, strings, &pkg_bindist_fedora_options::fedora_main_extrareq_,
        &pkg_bindist_fedora_options::fedora_main_extrareq_specified_ >;
      _cli_pkg_bindist_fedora_options_map_["--fedora-devel-extrareq"] =
      &::bpkg::cli::thunk< pkg_bindist_fedora_options, strings, &pkg_bindist_fedora_options::fedora_devel_extrareq_,
        &pkg_bindist_fedora_options::fedora_devel_extrareq_specified_ >;
      _cli_pkg_bindist_fedora_options_map_["--fedora-stat-extrareq"] =
      &::bpkg::cli::thunk< pkg_bindist_fedora_options, strings, &pkg_bindist_fedora_options::fedora_stat_extrareq_,
        &pkg_bindist_fedora_options::fedora_stat_extrareq_specified_ >;
    }
  };

  static _cli_pkg_bindist_fedora_options_map_init _cli_pkg_bindist_fedora_options_map_init_;

  bool pkg_bindist_fedora_options::
  _parse (const char* o, ::bpkg::cli::scanner& s)
  {
    _cli_pkg_bindist_fedora_options_map::const_iterator i (_cli_pkg_bindist_fedora_options_map_.find (o));

    if (i != _cli_pkg_bindist_fedora_options_map_.end ())
    {
      (*(i->second)) (*this, s);
      return true;
    }

    return false;
  }

  bool pkg_bindist_fedora_options::
  _parse (::bpkg::cli::scanner& s,
          ::bpkg::cli::unknown_mode opt_mode,
          ::bpkg::cli::unknown_mode arg_mode)
  {
    // Can't skip combined flags (--no-combined-flags).
    //
    assert (opt_mode != ::bpkg::cli::unknown_mode::skip);

    bool r = false;
    bool opt = true;

    while (s.more ())
    {
      const char* o = s.peek ();

      if (std::strcmp (o, "--") == 0)
      {
        opt = false;
      }

      if (opt)
      {
        if (_parse (o, s))
        {
          r = true;
          continue;
        }

        if (std::strncmp (o, "-", 1) == 0 && o[1] != '\0')
        {
          // Handle combined option values.
          //
          std::string co;
          if (const char* v = std::strchr (o, '='))
          {
            co.assign (o, 0, v - o);
            ++v;

            int ac (2);
            char* av[] =
            {
              const_cast<char*> (co.c_str ()),
              const_cast<char*> (v)
            };

            ::bpkg::cli::argv_scanner ns (0, ac, av);

            if (_parse (co.c_str (), ns))
            {
              // Parsed the option but not its value?
              //
              if (ns.end () != 2)
                throw ::bpkg::cli::invalid_value (co, v);

              s.next ();
              r = true;
              continue;
            }
            else
            {
              // Set the unknown option and fall through.
              //
              o = co.c_str ();
            }
          }

          // Handle combined flags.
          //
          char cf[3];
          {
            const char* p = o + 1;
            for (; *p != '\0'; ++p)
            {
              if (!((*p >= 'a' && *p <= 'z') ||
                    (*p >= 'A' && *p <= 'Z') ||
                    (*p >= '0' && *p <= '9')))
                break;
            }

            if (*p == '\0')
            {
              for (p = o + 1; *p != '\0'; ++p)
              {
                std::strcpy (cf, "-");
                cf[1] = *p;
                cf[2] = '\0';

                int ac (1);
                char* av[] =
                {
                  cf
                };

                ::bpkg::cli::argv_scanner ns (0, ac, av);

                if (!_parse (cf, ns))
                  break;
              }

              if (*p == '\0')
              {
                // All handled.
                //
                s.next ();
                r = true;
                continue;
              }
              else
              {
                // Set the unknown option and fall through.
                //
                o = cf;
              }
            }
          }

          switch (opt_mode)
          {
            case ::bpkg::cli::unknown_mode::skip:
            {
              s.skip ();
              r = true;
              continue;
            }
            case ::bpkg::cli::unknown_mode::stop:
            {
              break;
            }
            case ::bpkg::cli::unknown_mode::fail:
            {
              throw ::bpkg::cli::unknown_option (o);
            }
          }

          break;
        }
      }

      switch (arg_mode)
      {
        case ::bpkg::cli::unknown_mode::skip:
        {
          s.skip ();
          r = true;
          continue;
        }
        case ::bpkg::cli::unknown_mode::stop:
        {
          break;
        }
        case ::bpkg::cli::unknown_mode::fail:
        {
          throw ::bpkg::cli::unknown_argument (o);
        }
      }

      break;
    }

    return r;
  }

  // pkg_bindist_archive_options
  //

  pkg_bindist_archive_options::
  pkg_bindist_archive_options ()
  : archive_prepare_only_ (),
    archive_type_ (),
    archive_type_specified_ (false),
    archive_lang_ (),
    archive_lang_specified_ (false),
    archive_lang_impl_ (),
    archive_lang_impl_specified_ (false),
    archive_no_cpu_ (),
    archive_no_os_ (),
    archive_build_meta_ (),
    archive_build_meta_specified_ (false),
    archive_install_root_ (),
    archive_install_root_specified_ (false),
    archive_install_config_ (),
    archive_split_ (),
    archive_split_specified_ (false)
  {
  }

  bool pkg_bindist_archive_options::
  parse (int& argc,
         char** argv,
         bool erase,
         ::bpkg::cli::unknown_mode opt,
         ::bpkg::cli::unknown_mode arg)
  {
    ::bpkg::cli::argv_scanner s (argc, argv, erase);
    bool r = _parse (s, opt, arg);
    return r;
  }

  bool pkg_bindist_archive_options::
  parse (int start,
         int& argc,
         char** argv,
         bool erase,
         ::bpkg::cli::unknown_mode opt,
         ::bpkg::cli::unknown_mode arg)
  {
    ::bpkg::cli::argv_scanner s (start, argc, argv, erase);
    bool r = _parse (s, opt, arg);
    return r;
  }

  bool pkg_bindist_archive_options::
  parse (int& argc,
         char** argv,
         int& end,
         bool erase,
         ::bpkg::cli::unknown_mode opt,
         ::bpkg::cli::unknown_mode arg)
  {
    ::bpkg::cli::argv_scanner s (argc, argv, erase);
    bool r = _parse (s, opt, arg);
    end = s.end ();
    return r;
  }

  bool pkg_bindist_archive_options::
  parse (int start,
         int& argc,
         char** argv,
         int& end,
         bool erase,
         ::bpkg::cli::unknown_mode opt,
         ::bpkg::cli::unknown_mode arg)
  {
    ::bpkg::cli::argv_scanner s (start, argc, argv, erase);
    bool r = _parse (s, opt, arg);
    end = s.end ();
    return r;
  }

  bool pkg_bindist_archive_options::
  parse (::bpkg::cli::scanner& s,
         ::bpkg::cli::unknown_mode opt,
         ::bpkg::cli::unknown_mode arg)
  {
    bool r = _parse (s, opt, arg);
    return r;
  }

  void pkg_bindist_archive_options::
  merge (const pkg_bindist_archive_options& a)
  {
    CLI_POTENTIALLY_UNUSED (a);

    if (a.archive_prepare_only_)
    {
      ::bpkg::cli::parser< bool>::merge (
        this->archive_prepare_only_, a.archive_prepare_only_);
    }

    if (a.archive_type_specified_)
    {
      ::bpkg::cli::parser< strings>::merge (
        this->archive_type_, a.archive_type_);
      this->archive_type_specified_ = true;
    }

    if (a.archive_lang_specified_)
    {
      ::bpkg::cli::parser< std::multimap<string, string>>::merge (
        this->archive_lang_, a.archive_lang_);
      this->archive_lang_specified_ = true;
    }

    if (a.archive_lang_impl_specified_)
    {
      ::bpkg::cli::parser< std::multimap<string, string>>::merge (
        this->archive_lang_impl_, a.archive_lang_impl_);
      this->archive_lang_impl_specified_ = true;
    }

    if (a.archive_no_cpu_)
    {
      ::bpkg::cli::parser< bool>::merge (
        this->archive_no_cpu_, a.archive_no_cpu_);
    }

    if (a.archive_no_os_)
    {
      ::bpkg::cli::parser< bool>::merge (
        this->archive_no_os_, a.archive_no_os_);
    }

    if (a.archive_build_meta_specified_)
    {
      ::bpkg::cli::parser< string>::merge (
        this->archive_build_meta_, a.archive_build_meta_);
      this->archive_build_meta_specified_ = true;
    }

    if (a.archive_install_root_specified_)
    {
      ::bpkg::cli::parser< dir_path>::merge (
        this->archive_install_root_, a.archive_install_root_);
      this->archive_install_root_specified_ = true;
    }

    if (a.archive_install_config_)
    {
      ::bpkg::cli::parser< bool>::merge (
        this->archive_install_config_, a.archive_install_config_);
    }

    if (a.archive_split_specified_)
    {
      ::bpkg::cli::parser< std::map<string, string>>::merge (
        this->archive_split_, a.archive_split_);
      this->archive_split_specified_ = true;
    }
  }

  ::bpkg::cli::usage_para pkg_bindist_archive_options::
  print_usage (::std::ostream& os, ::bpkg::cli::usage_para p)
  {
    CLI_POTENTIALLY_UNUSED (os);

    if (p != ::bpkg::cli::usage_para::none)
      os << ::std::endl;

    os << "\033[1mARCHIVE DESCRIPTION\033[0m" << ::std::endl
       << ::std::endl
       << "The installation archive binary packages are generated by invoking the \033[1mbuild2\033[0m" << ::std::endl
       << "build system on the required packages directly in their \033[1mbpkg\033[0m configuration" << ::std::endl
       << "locations and installing them into the binary package directory using the" << ::std::endl
       << "\033[1mconfig.install.chroot\033[0m mechanism. Then this directory is packaged with \033[1mtar\033[0m or" << ::std::endl
       << "\033[1mzip\033[0m to produce one or more binary package archives." << ::std::endl
       << ::std::endl
       << "The generation of installation archive packages is never the default and should" << ::std::endl
       << "be requested explicitly with the \033[1m--distribution=archive\033[0m option. The" << ::std::endl
       << "installation directory layout and the package archives to generate can be" << ::std::endl
       << "specified with the \033[1m--archive-install-*\033[0m and \033[1m--archive-type\033[0m options (refer to" << ::std::endl
       << "their documentation for defaults)." << ::std::endl
       << ::std::endl
       << "The binary package directory (the top-level directory inside the archive) as" << ::std::endl
       << "well as the archive file base (the file name without the extension) are the" << ::std::endl
       << "same and have the following form:" << ::std::endl
       << ::std::endl
       << "\033[4mpackage\033[0m-\033[4mversion\033[0m-\033[4mbuild_metadata\033[0m\033[0m" << ::std::endl
       << ::std::endl
       << "Where \033[4mpackage\033[0m is the package name and \033[4mversion\033[0m is the \033[1mbpkg\033[0m package version." << ::std::endl
       << "Unless overridden with the \033[1m--archive-build-meta\033[0m option, \033[4mbuild_metadata\033[0m has the" << ::std::endl
       << "following form:" << ::std::endl
       << ::std::endl
       << "\033[4mcpu\033[0m-\033[4mos\033[0m[-\033[4mlangrt\033[0m...]\033[0m" << ::std::endl
       << ::std::endl
       << "Where \033[4mcpu\033[0m is the target CPU (for example, \033[1mx86_64\033[0m or \033[1maarch64\033[0m; omitted if" << ::std::endl
       << "\033[1m--archive-no-cpu\033[0m is specified), \033[4mos\033[0m is the \033[1mID\033[0m and \033[1mVERSION_ID\033[0m components from" << ::std::endl
       << "\033[1mos-release(5)\033[0m (or equivalent, for example, \033[1mdebian11\033[0m or \033[1mwindows10\033[0m; omitted if" << ::std::endl
       << "\033[1m--archive-no-os\033[0m is specified), and \033[4mlangrt\033[0m are the language runtimes as mapped" << ::std::endl
       << "by the \033[1m--archive-lang*\033[0m options (for example, \033[1mgcc12\033[0m or \033[1mmsvc17.4\033[0m)." << ::std::endl
       << ::std::endl
       << "For example, given the following invocation on Debian 11 running on \033[1mx86_64\033[0m:" << ::std::endl
       << ::std::endl
       << "bpkg build libhello" << ::std::endl
       << "bpkg test libhello" << ::std::endl
       << "bpkg bindist              \\" << ::std::endl
       << "  -o /tmp/output/         \\" << ::std::endl
       << "  --distribution=archive  \\" << ::std::endl
       << "  --archive-lang cc=gcc12 \\" << ::std::endl
       << "  libhello" << ::std::endl
       << ::std::endl
       << "We will end up with the package archive in the following form:" << ::std::endl
       << ::std::endl
       << "libhello-1.2.3-x86_64-debian11-gcc12.tar.xz" << ::std::endl
       << ::std::endl
       << "The recommended language runtime id format is the runtime name followed by the" << ::std::endl
       << "version, for example, \033[1mgcc12\033[0m or \033[1mmsvc17.4\033[0m. Note that its purpose is not to" << ::std::endl
       << "provide a precise specification of requirements but rather to help the user of" << ::std::endl
       << "a binary package to pick the appropriate variant. Refer to the \033[1m--archive-lang*\033[0m" << ::std::endl
       << "options documentation for details on the mapping semantics." << ::std::endl
       << ::std::endl
       << "Instead of mapping languages individually you can specify entire build metadata" << ::std::endl
       << "as a single value with the \033[1m--archive-build-meta\033[0m (it is also possible to add" << ::std::endl
       << "additional metadata; see the option documentation for details). For example:" << ::std::endl
       << ::std::endl
       << "bpkg bindist                              \\" << ::std::endl
       << "  -o /tmp/output/                         \\" << ::std::endl
       << "  --distribution=archive                  \\" << ::std::endl
       << "  --archive-build-meta=x86_64-linux-glibc" << ::std::endl
       << "  libhello" << ::std::endl
       << ::std::endl
       << "This will produce the package archive in the following form:" << ::std::endl
       << ::std::endl
       << "libhello-1.2.3-x86_64-linux-glibc.tar.xz" << ::std::endl
       << ::std::endl
       << "To install the binary package from archive simply unpack it using \033[1mtar\033[0m or \033[1mzip\033[0m." << ::std::endl
       << "You can use the \033[1m--strip-components\033[0m \033[1mtar\033[0m option to remove the top-level package" << ::std::endl
       << "directory (the same can be achieved for \033[1mzip\033[0m archives by using \033[1mbsdtar\033[0m on" << ::std::endl
       << "Windows). For example, to unpack the package contents so that they end up in" << ::std::endl
       << "\033[1m/usr/local/\033[0m:" << ::std::endl
       << ::std::endl
       << "sudo tar -xf libhello-1.2.3-x86_64-debian11-gcc12.tar.xz \\" << ::std::endl
       << "  -C / --strip-components=1" << ::std::endl
       << ::std::endl
       << "If you expect the binary package to be unpacked into a directory other than its" << ::std::endl
       << "original installation directory (\033[1m--archive-install-root\033[0m), then it's recommended" << ::std::endl
       << "to make it relocatable by specifying the \033[1mconfig.install.relocatable=true\033[0m" << ::std::endl
       << "configuration variable. For example:" << ::std::endl
       << ::std::endl
       << "bpkg bindist                      \\" << ::std::endl
       << "  ...                             \\" << ::std::endl
       << "  config.install.relocatable=true \\" << ::std::endl
       << "  libhello" << ::std::endl
       << ::std::endl
       << "Note that not all source packages support relocatable installation (see" << ::std::endl
       << "Rolocatable Installation (b#install-reloc) for details)." << ::std::endl
       << ::std::endl
       << "Another mechanism that can useful when generating archive packages is the" << ::std::endl
       << "ability to filter the files being installed. This, for example, can be used to" << ::std::endl
       << "create binary packages that don't contain any development-related files. See" << ::std::endl
       << "Installation Filtering (b#install-filter) for details. See also the" << ::std::endl
       << "\033[1m--archive-split\033[0m option." << ::std::endl
       << ::std::endl
       << "The installation archive package can be generated for a target other than the" << ::std::endl
       << "host by specifying the target triplet with the \033[1m--architecture\033[0m option. In this" << ::std::endl
       << "case the \033[1mbpkg\033[0m configuration is assumed to be appropriately configured for" << ::std::endl
       << "cross-compiling to the specified target. You will also need to explicitly" << ::std::endl
       << "specify the \033[1m--archive-install-root\033[0m option (or \033[1m--archive-install-config\033[0m) as well" << ::std::endl
       << "as the \033[1m--os-release-id\033[0m option (and likely want to specify other \033[1m--os-release-*\033[0m" << ::std::endl
       << "options). For example, for cross-compiling from Linux to Windows using the" << ::std::endl
       << "MinGW GCC toolchain:" << ::std::endl
       << ::std::endl
       << "bpkg bindist                        \\" << ::std::endl
       << "  --distribution=archive            \\" << ::std::endl
       << "  --architecture=x86_64-w64-mingw32 \\" << ::std::endl
       << "  --os-release-id=windows           \\" << ::std::endl
       << "  --os-release-name=Windows         \\" << ::std::endl
       << "  --os-release-version-id=10        \\" << ::std::endl
       << "  --archive-install-root /          \\" << ::std::endl
       << "  --archive-lang cc=mingw_w64_gcc12 \\" << ::std::endl
       << "  ..." << ::std::endl;

    os << std::endl
       << "\033[1mPKG-BINDIST ARCHIVE OPTIONS\033[0m" << ::std::endl;

    os << std::endl
       << "\033[1m--archive-prepare-only\033[0m    Prepare all the package contents but do not create" << ::std::endl
       << "                          the binary package archive, printing its directory" << ::std::endl
       << "                          instead unless requested to be quiet. Implies" << ::std::endl
       << "                          \033[1m--keep-output\033[0m." << ::std::endl;

    os << std::endl
       << "\033[1m--archive-type\033[0m \033[4mext\033[0m        Archive type to create specified as a file extension," << ::std::endl
       << "                          for example, \033[1mtar.xz\033[0m, \033[1mtar.gz\033[0m, \033[1mtar\033[0m, \033[1mzip\033[0m. Repeat this" << ::std::endl
       << "                          option to generate multiple archive types. If" << ::std::endl
       << "                          unspecified, then a default type appropriate for the" << ::std::endl
       << "                          target operating system is used, currently \033[1mzip\033[0m for" << ::std::endl
       << "                          Windows and \033[1mtar.xz\033[0m for POSIX. Note, however, that" << ::std::endl
       << "                          these defaults may change in the future." << ::std::endl;

    os << std::endl
       << "\033[1m--archive-lang\033[0m \033[4mln\033[0m=\033[4mrt\033[0m      Map interface language name \033[4mln\033[0m to runtime id \033[4mrt\033[0m. If" << ::std::endl
       << "                          no mapping is found for an interface language in this" << ::std::endl
       << "                          map, then fallback to the \033[1m--archive-lang-impl\033[0m map. If" << ::std::endl
       << "                          still no mapping is found, then fail. If the" << ::std::endl
       << "                          information about an interface language is" << ::std::endl
       << "                          unimportant and should be ignored, then empty runtime" << ::std::endl
       << "                          id can be specified. Note that the mapping specified" << ::std::endl
       << "                          with this option is only considered if the package" << ::std::endl
       << "                          type is a library (for other package types all" << ::std::endl
       << "                          languages used are implementation). Note also that" << ::std::endl
       << "                          multiple runtime ids specified for the same language" << ::std::endl
       << "                          are combined except for an empty id, which is treated" << ::std::endl
       << "                          as a request to clear previous entries." << ::std::endl;

    os << std::endl
       << "\033[1m--archive-lang-impl\033[0m \033[4mln\033[0m=\033[4mrt\033[0m Map implementation language name \033[4mln\033[0m to runtime id \033[4mrt\033[0m." << ::std::endl
       << "                          If no mapping is found for an implementation language" << ::std::endl
       << "                          in this map, then assume the information about this" << ::std::endl
       << "                          implementation language is unimportant and ignore it" << ::std::endl
       << "                          (examples of such cases include static linking as" << ::std::endl
       << "                          well as a language runtime that is always present)." << ::std::endl
       << "                          See \033[1m--archive-lang\033[0m for background." << ::std::endl;

    os << std::endl
       << "\033[1m--archive-no-cpu\033[0m          Assume the package is CPU architecture-independent" << ::std::endl
       << "                          and omit it from the binary package directory name" << ::std::endl
       << "                          and archive file base." << ::std::endl;

    os << std::endl
       << "\033[1m--archive-no-os\033[0m           Assume the package is operating system-independent" << ::std::endl
       << "                          and omit it from the binary package directory name" << ::std::endl
       << "                          and archive file base." << ::std::endl;

    os << std::endl
       << "\033[1m--archive-build-meta\033[0m \033[4mdata\033[0m Alternative or additional build metadata to include" << ::std::endl
       << "                          after the version in the binary package directory and" << ::std::endl
       << "                          file names. If the specified value starts/ends with" << ::std::endl
       << "                          \033[1m+\033[0m then the value (with \033[1m+\033[0m removed) is added" << ::std::endl
       << "                          after/before the default metadata. Otherwise it is" << ::std::endl
       << "                          used as is instead of the default metadata. If empty" << ::std::endl
       << "                          value is specified, then no build metadata is" << ::std::endl
       << "                          included." << ::std::endl;

    os << std::endl
       << "\033[1m--archive-install-root\033[0m \033[4md\033[0m  Alternative installation root directory. The default" << ::std::endl
       << "                          is \033[1m/usr/local/\033[0m on POSIX and \033[1mC:\\\033[0m\033[4mproject\033[0m\033[1m\\\033[0m\033[0m on Windows," << ::std::endl
       << "                          where \033[4mproject\033[0m is the \033[1mproject\033[0m" << ::std::endl
       << "                          (bpkg#manifest-package-project) package manifest" << ::std::endl
       << "                          value." << ::std::endl;

    os << std::endl
       << "\033[1m--archive-install-config\033[0m  Use the installation directory layout" << ::std::endl
       << "                          (\033[1mconfig.install.*\033[0m variables) as configured instead of" << ::std::endl
       << "                          overriding them with defaults appropriate for the" << ::std::endl
       << "                          target operating system. Note that this includes" << ::std::endl
       << "                          \033[1mconfig.install.private\033[0m and \033[1mconfig.bin.rpath\033[0m if needed" << ::std::endl
       << "                          for a private installation. Note also that the" << ::std::endl
       << "                          \033[1mconfig.install.root\033[0m value is still overridden with" << ::std::endl
       << "                          the \033[1m--archive-install-root\033[0m option value if specified." << ::std::endl;

    os << std::endl
       << "\033[1m--archive-split\033[0m \033[4mkey\033[0m=\033[4mfilt\033[0m  Split the installation into multiple binary packages." << ::std::endl
       << "                          Specifically, for each \033[4mkey\033[0m=\033[4mfilt\033[0m pair, perform the" << ::std::endl
       << "                          \033[1minstall\033[0m operation with \033[1mconfig.install.filter=\033[0m\033[4mfilt\033[0m\033[0m and" << ::std::endl
       << "                          package the resulting files as" << ::std::endl
       << "                          \033[4mpackage-key-version-build_metadata\033[0m omitting the \033[4m-key\033[0m" << ::std::endl
       << "                          part if \033[4mkey\033[0m is empty. Note that wildcard patterns in" << ::std::endl
       << "                          \033[4mfilt\033[0m must be quoted. See Installation Filtering" << ::std::endl
       << "                          (b#install-filter) for background." << ::std::endl;

    p = ::bpkg::cli::usage_para::option;

    return p;
  }

  typedef
  std::map<std::string, void (*) (pkg_bindist_archive_options&, ::bpkg::cli::scanner&)>
  _cli_pkg_bindist_archive_options_map;

  static _cli_pkg_bindist_archive_options_map _cli_pkg_bindist_archive_options_map_;

  struct _cli_pkg_bindist_archive_options_map_init
  {
    _cli_pkg_bindist_archive_options_map_init ()
    {
      _cli_pkg_bindist_archive_options_map_["--archive-prepare-only"] =
      &::bpkg::cli::thunk< pkg_bindist_archive_options, &pkg_bindist_archive_options::archive_prepare_only_ >;
      _cli_pkg_bindist_archive_options_map_["--archive-type"] =
      &::bpkg::cli::thunk< pkg_bindist_archive_options, strings, &pkg_bindist_archive_options::archive_type_,
        &pkg_bindist_archive_options::archive_type_specified_ >;
      _cli_pkg_bindist_archive_options_map_["--archive-lang"] =
      &::bpkg::cli::thunk< pkg_bindist_archive_options, std::multimap<string, string>, &pkg_bindist_archive_options::archive_lang_,
        &pkg_bindist_archive_options::archive_lang_specified_ >;
      _cli_pkg_bindist_archive_options_map_["--archive-lang-impl"] =
      &::bpkg::cli::thunk< pkg_bindist_archive_options, std::multimap<string, string>, &pkg_bindist_archive_options::archive_lang_impl_,
        &pkg_bindist_archive_options::archive_lang_impl_specified_ >;
      _cli_pkg_bindist_archive_options_map_["--archive-no-cpu"] =
      &::bpkg::cli::thunk< pkg_bindist_archive_options, &pkg_bindist_archive_options::archive_no_cpu_ >;
      _cli_pkg_bindist_archive_options_map_["--archive-no-os"] =
      &::bpkg::cli::thunk< pkg_bindist_archive_options, &pkg_bindist_archive_options::archive_no_os_ >;
      _cli_pkg_bindist_archive_options_map_["--archive-build-meta"] =
      &::bpkg::cli::thunk< pkg_bindist_archive_options, string, &pkg_bindist_archive_options::archive_build_meta_,
        &pkg_bindist_archive_options::archive_build_meta_specified_ >;
      _cli_pkg_bindist_archive_options_map_["--archive-install-root"] =
      &::bpkg::cli::thunk< pkg_bindist_archive_options, dir_path, &pkg_bindist_archive_options::archive_install_root_,
        &pkg_bindist_archive_options::archive_install_root_specified_ >;
      _cli_pkg_bindist_archive_options_map_["--archive-install-config"] =
      &::bpkg::cli::thunk< pkg_bindist_archive_options, &pkg_bindist_archive_options::archive_install_config_ >;
      _cli_pkg_bindist_archive_options_map_["--archive-split"] =
      &::bpkg::cli::thunk< pkg_bindist_archive_options, std::map<string, string>, &pkg_bindist_archive_options::archive_split_,
        &pkg_bindist_archive_options::archive_split_specified_ >;
    }
  };

  static _cli_pkg_bindist_archive_options_map_init _cli_pkg_bindist_archive_options_map_init_;

  bool pkg_bindist_archive_options::
  _parse (const char* o, ::bpkg::cli::scanner& s)
  {
    _cli_pkg_bindist_archive_options_map::const_iterator i (_cli_pkg_bindist_archive_options_map_.find (o));

    if (i != _cli_pkg_bindist_archive_options_map_.end ())
    {
      (*(i->second)) (*this, s);
      return true;
    }

    return false;
  }

  bool pkg_bindist_archive_options::
  _parse (::bpkg::cli::scanner& s,
          ::bpkg::cli::unknown_mode opt_mode,
          ::bpkg::cli::unknown_mode arg_mode)
  {
    // Can't skip combined flags (--no-combined-flags).
    //
    assert (opt_mode != ::bpkg::cli::unknown_mode::skip);

    bool r = false;
    bool opt = true;

    while (s.more ())
    {
      const char* o = s.peek ();

      if (std::strcmp (o, "--") == 0)
      {
        opt = false;
      }

      if (opt)
      {
        if (_parse (o, s))
        {
          r = true;
          continue;
        }

        if (std::strncmp (o, "-", 1) == 0 && o[1] != '\0')
        {
          // Handle combined option values.
          //
          std::string co;
          if (const char* v = std::strchr (o, '='))
          {
            co.assign (o, 0, v - o);
            ++v;

            int ac (2);
            char* av[] =
            {
              const_cast<char*> (co.c_str ()),
              const_cast<char*> (v)
            };

            ::bpkg::cli::argv_scanner ns (0, ac, av);

            if (_parse (co.c_str (), ns))
            {
              // Parsed the option but not its value?
              //
              if (ns.end () != 2)
                throw ::bpkg::cli::invalid_value (co, v);

              s.next ();
              r = true;
              continue;
            }
            else
            {
              // Set the unknown option and fall through.
              //
              o = co.c_str ();
            }
          }

          // Handle combined flags.
          //
          char cf[3];
          {
            const char* p = o + 1;
            for (; *p != '\0'; ++p)
            {
              if (!((*p >= 'a' && *p <= 'z') ||
                    (*p >= 'A' && *p <= 'Z') ||
                    (*p >= '0' && *p <= '9')))
                break;
            }

            if (*p == '\0')
            {
              for (p = o + 1; *p != '\0'; ++p)
              {
                std::strcpy (cf, "-");
                cf[1] = *p;
                cf[2] = '\0';

                int ac (1);
                char* av[] =
                {
                  cf
                };

                ::bpkg::cli::argv_scanner ns (0, ac, av);

                if (!_parse (cf, ns))
                  break;
              }

              if (*p == '\0')
              {
                // All handled.
                //
                s.next ();
                r = true;
                continue;
              }
              else
              {
                // Set the unknown option and fall through.
                //
                o = cf;
              }
            }
          }

          switch (opt_mode)
          {
            case ::bpkg::cli::unknown_mode::skip:
            {
              s.skip ();
              r = true;
              continue;
            }
            case ::bpkg::cli::unknown_mode::stop:
            {
              break;
            }
            case ::bpkg::cli::unknown_mode::fail:
            {
              throw ::bpkg::cli::unknown_option (o);
            }
          }

          break;
        }
      }

      switch (arg_mode)
      {
        case ::bpkg::cli::unknown_mode::skip:
        {
          s.skip ();
          r = true;
          continue;
        }
        case ::bpkg::cli::unknown_mode::stop:
        {
          break;
        }
        case ::bpkg::cli::unknown_mode::fail:
        {
          throw ::bpkg::cli::unknown_argument (o);
        }
      }

      break;
    }

    return r;
  }

  // pkg_bindist_options
  //

  pkg_bindist_options::
  pkg_bindist_options ()
  {
  }

  bool pkg_bindist_options::
  parse (int& argc,
         char** argv,
         bool erase,
         ::bpkg::cli::unknown_mode opt,
         ::bpkg::cli::unknown_mode arg)
  {
    ::bpkg::cli::argv_scanner s (argc, argv, erase);
    bool r = _parse (s, opt, arg);
    return r;
  }

  bool pkg_bindist_options::
  parse (int start,
         int& argc,
         char** argv,
         bool erase,
         ::bpkg::cli::unknown_mode opt,
         ::bpkg::cli::unknown_mode arg)
  {
    ::bpkg::cli::argv_scanner s (start, argc, argv, erase);
    bool r = _parse (s, opt, arg);
    return r;
  }

  bool pkg_bindist_options::
  parse (int& argc,
         char** argv,
         int& end,
         bool erase,
         ::bpkg::cli::unknown_mode opt,
         ::bpkg::cli::unknown_mode arg)
  {
    ::bpkg::cli::argv_scanner s (argc, argv, erase);
    bool r = _parse (s, opt, arg);
    end = s.end ();
    return r;
  }

  bool pkg_bindist_options::
  parse (int start,
         int& argc,
         char** argv,
         int& end,
         bool erase,
         ::bpkg::cli::unknown_mode opt,
         ::bpkg::cli::unknown_mode arg)
  {
    ::bpkg::cli::argv_scanner s (start, argc, argv, erase);
    bool r = _parse (s, opt, arg);
    end = s.end ();
    return r;
  }

  bool pkg_bindist_options::
  parse (::bpkg::cli::scanner& s,
         ::bpkg::cli::unknown_mode opt,
         ::bpkg::cli::unknown_mode arg)
  {
    bool r = _parse (s, opt, arg);
    return r;
  }

  void pkg_bindist_options::
  merge (const pkg_bindist_options& a)
  {
    CLI_POTENTIALLY_UNUSED (a);

    // pkg_bindist_common_options base
    //
    ::bpkg::pkg_bindist_common_options::merge (a);

    // pkg_bindist_debian_options base
    //
    ::bpkg::pkg_bindist_debian_options::merge (a);

    // pkg_bindist_fedora_options base
    //
    ::bpkg::pkg_bindist_fedora_options::merge (a);

    // pkg_bindist_archive_options base
    //
    ::bpkg::pkg_bindist_archive_options::merge (a);
  }

  ::bpkg::cli::usage_para pkg_bindist_options::
  print_usage (::std::ostream& os, ::bpkg::cli::usage_para p)
  {
    CLI_POTENTIALLY_UNUSED (os);

    return p;
  }

  typedef
  std::map<std::string, void (*) (pkg_bindist_options&, ::bpkg::cli::scanner&)>
  _cli_pkg_bindist_options_map;

  static _cli_pkg_bindist_options_map _cli_pkg_bindist_options_map_;

  struct _cli_pkg_bindist_options_map_init
  {
    _cli_pkg_bindist_options_map_init ()
    {
    }
  };

  static _cli_pkg_bindist_options_map_init _cli_pkg_bindist_options_map_init_;

  bool pkg_bindist_options::
  _parse (const char* o, ::bpkg::cli::scanner& s)
  {
    _cli_pkg_bindist_options_map::const_iterator i (_cli_pkg_bindist_options_map_.find (o));

    if (i != _cli_pkg_bindist_options_map_.end ())
    {
      (*(i->second)) (*this, s);
      return true;
    }

    // pkg_bindist_common_options base
    //
    if (::bpkg::pkg_bindist_common_options::_parse (o, s))
      return true;

    // pkg_bindist_debian_options base
    //
    if (::bpkg::pkg_bindist_debian_options::_parse (o, s))
      return true;

    // pkg_bindist_fedora_options base
    //
    if (::bpkg::pkg_bindist_fedora_options::_parse (o, s))
      return true;

    // pkg_bindist_archive_options base
    //
    if (::bpkg::pkg_bindist_archive_options::_parse (o, s))
      return true;

    return false;
  }

  bool pkg_bindist_options::
  _parse (::bpkg::cli::scanner& s,
          ::bpkg::cli::unknown_mode opt_mode,
          ::bpkg::cli::unknown_mode arg_mode)
  {
    // Can't skip combined flags (--no-combined-flags).
    //
    assert (opt_mode != ::bpkg::cli::unknown_mode::skip);

    bool r = false;
    bool opt = true;

    while (s.more ())
    {
      const char* o = s.peek ();

      if (std::strcmp (o, "--") == 0)
      {
        opt = false;
      }

      if (opt)
      {
        if (_parse (o, s))
        {
          r = true;
          continue;
        }

        if (std::strncmp (o, "-", 1) == 0 && o[1] != '\0')
        {
          // Handle combined option values.
          //
          std::string co;
          if (const char* v = std::strchr (o, '='))
          {
            co.assign (o, 0, v - o);
            ++v;

            int ac (2);
            char* av[] =
            {
              const_cast<char*> (co.c_str ()),
              const_cast<char*> (v)
            };

            ::bpkg::cli::argv_scanner ns (0, ac, av);

            if (_parse (co.c_str (), ns))
            {
              // Parsed the option but not its value?
              //
              if (ns.end () != 2)
                throw ::bpkg::cli::invalid_value (co, v);

              s.next ();
              r = true;
              continue;
            }
            else
            {
              // Set the unknown option and fall through.
              //
              o = co.c_str ();
            }
          }

          // Handle combined flags.
          //
          char cf[3];
          {
            const char* p = o + 1;
            for (; *p != '\0'; ++p)
            {
              if (!((*p >= 'a' && *p <= 'z') ||
                    (*p >= 'A' && *p <= 'Z') ||
                    (*p >= '0' && *p <= '9')))
                break;
            }

            if (*p == '\0')
            {
              for (p = o + 1; *p != '\0'; ++p)
              {
                std::strcpy (cf, "-");
                cf[1] = *p;
                cf[2] = '\0';

                int ac (1);
                char* av[] =
                {
                  cf
                };

                ::bpkg::cli::argv_scanner ns (0, ac, av);

                if (!_parse (cf, ns))
                  break;
              }

              if (*p == '\0')
              {
                // All handled.
                //
                s.next ();
                r = true;
                continue;
              }
              else
              {
                // Set the unknown option and fall through.
                //
                o = cf;
              }
            }
          }

          switch (opt_mode)
          {
            case ::bpkg::cli::unknown_mode::skip:
            {
              s.skip ();
              r = true;
              continue;
            }
            case ::bpkg::cli::unknown_mode::stop:
            {
              break;
            }
            case ::bpkg::cli::unknown_mode::fail:
            {
              throw ::bpkg::cli::unknown_option (o);
            }
          }

          break;
        }
      }

      switch (arg_mode)
      {
        case ::bpkg::cli::unknown_mode::skip:
        {
          s.skip ();
          r = true;
          continue;
        }
        case ::bpkg::cli::unknown_mode::stop:
        {
          break;
        }
        case ::bpkg::cli::unknown_mode::fail:
        {
          throw ::bpkg::cli::unknown_argument (o);
        }
      }

      break;
    }

    return r;
  }
}

namespace bpkg
{
  ::bpkg::cli::usage_para
  print_bpkg_pkg_bindist_usage (::std::ostream& os, ::bpkg::cli::usage_para p)
  {
    CLI_POTENTIALLY_UNUSED (os);

    if (p != ::bpkg::cli::usage_para::none)
      os << ::std::endl;

    os << "\033[1mSYNOPSIS\033[0m" << ::std::endl
       << ::std::endl
       << "\033[1mbpkg pkg-bindist\033[0m|\033[1mbindist\033[0m [\033[1m--output-root\033[0m|\033[1m-o\033[0m \033[4mdir\033[0m] [\033[4moptions\033[0m] [\033[4mvars\033[0m] \033[4mpkg\033[0m...\033[0m" << ::std::endl
       << ::std::endl
       << "\033[1mDESCRIPTION\033[0m" << ::std::endl
       << ::std::endl
       << "The \033[1mpkg-bindist\033[0m command generates a binary distribution package for the" << ::std::endl
       << "specified package. If additional packages are specified, then they are bundled" << ::std::endl
       << "in the same distribution package. All the specified packages must have been" << ::std::endl
       << "previously configured with \033[1mbpkg-pkg-build(1)\033[0m or \033[1mbpkg-pkg-configure(1)\033[0m. For some" << ::std::endl
       << "system package managers a directory for intermediate files and subdirectories" << ::std::endl
       << "as well as the resulting binary package may have to be specified explicitly" << ::std::endl
       << "with the \033[1m--output-root\033[0m|\033[1m-o\033[0m\033[0m option." << ::std::endl
       << ::std::endl
       << "Underneath, this command roughly performs the following steps: First it" << ::std::endl
       << "installs the specified packages similar to the \033[1mbpkg-pkg-install(1)\033[0m command" << ::std::endl
       << "except that it may override the installation locations (via the" << ::std::endl
       << "\033[1mconfig.install.*\033[0m variables) to match the distribution's layout. Then it" << ::std::endl
       << "generates any necessary distribution package metadata files based on the" << ::std::endl
       << "information from the package \033[1mmanifest\033[0m files. Finally, it invokes the" << ::std::endl
       << "distribution-specific command to produce the binary package. Unless overridden" << ::std::endl
       << "with the \033[1m--architecture\033[0m and \033[1m--distribution\033[0m options, the binary package is" << ::std::endl
       << "generated for the host architecture using the host's standard system package" << ::std::endl
       << "manager. Additional command line variables (\033[4mvars\033[0m, normally \033[1mconfig.*\033[0m) can be" << ::std::endl
       << "passed to the build system during the installation step. See the following" << ::std::endl
       << "distribution-specific description sections below for details and invocation" << ::std::endl
       << "examples:" << ::std::endl
       << ::std::endl
       << "DEBIAN DESCRIPTION" << ::std::endl
       << ::std::endl
       << "FEDORA DESCRIPTION" << ::std::endl
       << ::std::endl
       << "ARCHIVE DESCRIPTION" << ::std::endl
       << ::std::endl
       << "The specified packages may have dependencies and the default behavior is to not" << ::std::endl
       << "bundle them but rather to specify them as dependencies in the corresponding" << ::std::endl
       << "distribution package metadata, if applicable. This default behavior can be" << ::std::endl
       << "overridden with the \033[1m--recursive\033[0m option (see the option description for the" << ::std::endl
       << "available modes). Note, however, that dependencies that are satisfied by system" << ::std::endl
       << "packages are always specified as dependencies in the distribution package" << ::std::endl
       << "metadata (if applicable)." << ::std::endl;

    p = ::bpkg::pkg_bindist_common_options::print_usage (os, ::bpkg::cli::usage_para::text);

    p = ::bpkg::pkg_bindist_debian_options::print_usage (os, p);

    p = ::bpkg::pkg_bindist_fedora_options::print_usage (os, p);

    p = ::bpkg::pkg_bindist_archive_options::print_usage (os, p);

    if (p != ::bpkg::cli::usage_para::none)
      os << ::std::endl;

    os << "\033[1mSTRUCTURED RESULT\033[0m" << ::std::endl
       << ::std::endl
       << "Instead of printing to \033[1mstderr\033[0m the list of generated binary packages in a format" << ::std::endl
       << "more suitable for human consumption, the \033[1mpkg-bindist\033[0m command can be instructed" << ::std::endl
       << "to write it to \033[1mstdout\033[0m in a machine-readable form by specifying the" << ::std::endl
       << "\033[1m--structured-result\033[0m option. Currently, the only recognized format value for" << ::std::endl
       << "this option is \033[1mjson\033[0m with the output being a JSON object that is a serialized" << ::std::endl
       << "representation of the following C++ struct \033[1mbindist_result\033[0m:" << ::std::endl
       << ::std::endl
       << "struct os_release" << ::std::endl
       << "{" << ::std::endl
       << "  string           name_id;     // ID" << ::std::endl
       << "  vector<string>   like_ids;    // ID_LIKE" << ::std::endl
       << "  optional<string> version_id;  // VERSION_ID" << ::std::endl
       << "  optional<string> variant_id;  // VARIANT_ID" << ::std::endl
       << ::std::endl
       << "  optional<string> name;              // NAME" << ::std::endl
       << "  optional<string> version_codename;  // VERSION_CODENAME" << ::std::endl
       << "  optional<string> variant;           // VARIANT" << ::std::endl
       << "};" << ::std::endl
       << ::std::endl
       << "struct file" << ::std::endl
       << "{" << ::std::endl
       << "  string type;" << ::std::endl
       << "  string path;" << ::std::endl
       << "  optional<string> system_name;" << ::std::endl
       << "};" << ::std::endl
       << ::std::endl
       << "struct package" << ::std::endl
       << "{" << ::std::endl
       << "  string           name;" << ::std::endl
       << "  string           version;" << ::std::endl
       << "  optional<string> system_version;" << ::std::endl
       << "  vector<file>     files;" << ::std::endl
       << "};" << ::std::endl
       << ::std::endl
       << "struct bindist_result" << ::std::endl
       << "{" << ::std::endl
       << "  string           distribution;     // --distribution or auto-detected" << ::std::endl
       << "  string           architecture;     // --architecture or auto-detected" << ::std::endl
       << "  os_release       os_release;       // --os-release-* or auto-detected" << ::std::endl
       << "  optional<string> recursive;        // --recursive" << ::std::endl
       << "  bool             private;          // --private" << ::std::endl
       << "  bool             dependent_config; // See --allow-dependent-config" << ::std::endl
       << ::std::endl
       << "  package          package;" << ::std::endl
       << "  vector<package>  dependencies;     // Only in --recursive=separate" << ::std::endl
       << "};" << ::std::endl
       << ::std::endl
       << "For example:" << ::std::endl
       << ::std::endl
       << "{" << ::std::endl
       << "  \"distribution\": \"debian\"," << ::std::endl
       << "  \"architecture\": \"amd64\"," << ::std::endl
       << "  \"os_release\": {" << ::std::endl
       << "    \"name_id\": \"debian\"," << ::std::endl
       << "    \"version_id\": \"11\"," << ::std::endl
       << "    \"name\": \"Debian GNU/Linux\"" << ::std::endl
       << "  }," << ::std::endl
       << "  \"package\": {" << ::std::endl
       << "    \"name\": \"libfoo\"," << ::std::endl
       << "    \"version\": \"2.5.0-b.23\"," << ::std::endl
       << "    \"system_version\": \"2.5.0~b.23-0~debian11\"," << ::std::endl
       << "    \"files\": [" << ::std::endl
       << "      {" << ::std::endl
       << "        \"type\": \"main.deb\"," << ::std::endl
       << "        \"path\": \"/tmp/libfoo_2.5.0~b.23-0~debian11_amd64.deb\"," << ::std::endl
       << "        \"system_name\": \"libfoo\"" << ::std::endl
       << "      }," << ::std::endl
       << "      {" << ::std::endl
       << "        \"type\": \"dev.deb\"," << ::std::endl
       << "        \"path\": \"/tmp/libfoo-dev_2.5.0~b.23-0~debian11_amd64.deb\"," << ::std::endl
       << "        \"system_name\": \"libfoo-dev\"" << ::std::endl
       << "      }," << ::std::endl
       << "      ..." << ::std::endl
       << "    ]" << ::std::endl
       << "  }" << ::std::endl
       << "}" << ::std::endl
       << ::std::endl
       << "See the JSON OUTPUT section in \033[1mbpkg-common-options(1)\033[0m for details on the" << ::std::endl
       << "overall properties of this format and the semantics of the \033[1mstruct\033[0m" << ::std::endl
       << "serialization." << ::std::endl
       << ::std::endl
       << "The \033[1mfile::type\033[0m member is a distribution-specific value that classifies the" << ::std::endl
       << "file. For the \033[1mdebian\033[0m distribution the possible values are \033[1mmain.deb\033[0m, \033[1mdev.deb\033[0m," << ::std::endl
       << "\033[1mdoc.deb\033[0m, \033[1mcommon.deb\033[0m, \033[1mdbgsym.deb\033[0m, \033[1mchanges\033[0m (\033[1m.changes\033[0m file), and \033[1mbuildid\033[0m" << ::std::endl
       << "(\033[1m.buildid\033[0m file); see Debian Package Mapping for Production" << ::std::endl
       << "(bpkg#bindist-mapping-debian-produce) for background. For the \033[1mfedora\033[0m" << ::std::endl
       << "distribution the possible values are \033[1mmain.rpm\033[0m, \033[1mdevel.rpm\033[0m, \033[1mstatic.rpm\033[0m, \033[1mdoc.rpm\033[0m," << ::std::endl
       << "\033[1mcommon.rpm\033[0m, and \033[1mdebuginfo.rpm\033[0m; see Fedora Package Mapping for Production" << ::std::endl
       << "(bpkg#bindist-mapping-fedora-produce) for background. For the \033[1marchive\033[0m" << ::std::endl
       << "distribution this is the archive type (\033[1m--archive-type\033[0m), for example, \033[1mtar.xz\033[0m or" << ::std::endl
       << "\033[1mzip\033[0m, potentially prefixed with \033[4mkey\033[0m if the \033[1m--archive-split\033[0m functionality is" << ::std::endl
       << "used, for example, \033[1mdev.tar.xz\033[0m." << ::std::endl
       << ::std::endl
       << "The \033[1mpackage::system_version\033[0m and/or \033[1mfile::system_name\033[0m members are absent if not" << ::std::endl
       << "applicable to the distribution. The \033[1mfile::system_name\033[0m member is also absent if" << ::std::endl
       << "the file is not a binary package (for example, \033[1m.changes\033[0m and \033[1m.buildid\033[0m files in" << ::std::endl
       << "the \033[1mdebian\033[0m distribution)." << ::std::endl;

    p = ::bpkg::pkg_bindist_options::print_usage (os, ::bpkg::cli::usage_para::text);

    if (p != ::bpkg::cli::usage_para::none)
      os << ::std::endl;

    os << "\033[1mDEFAULT OPTIONS FILES\033[0m" << ::std::endl
       << ::std::endl
       << "See \033[1mbpkg-default-options-files(1)\033[0m for an overview of the default options files." << ::std::endl
       << "For the \033[1mpkg-bindist\033[0m command the search start directory is the configuration" << ::std::endl
       << "directory. The following options files are searched for in each directory and," << ::std::endl
       << "if found, loaded in the order listed:" << ::std::endl
       << ::std::endl
       << "bpkg.options" << ::std::endl
       << "bpkg-pkg-bindist.options" << ::std::endl
       << ::std::endl
       << "The following \033[1mpkg-bindist\033[0m command options cannot be specified in the default" << ::std::endl
       << "options files:" << ::std::endl
       << ::std::endl
       << "--directory|-d" << ::std::endl;

    p = ::bpkg::cli::usage_para::text;

    return p;
  }
}

// Begin epilogue.
//
//
// End epilogue.

