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

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

#include <bbot/agent/agent-options.hxx>

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

namespace bbot
{
  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;
      }
    };

    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;
      }
    };

    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;
      }
    };

    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);
      }
    };

    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;
      }
    };

    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;
      }
    };

    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;
      }
    };

    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;
      }
    };

    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 bbot
{
  // agent_options
  //

  agent_options::
  agent_options ()
  : help_ (),
    version_ (),
    verbose_ (1),
    verbose_specified_ (false),
    systemd_daemon_ (),
    toolchain_name_ ("default"),
    toolchain_name_specified_ (false),
    toolchain_num_ (1),
    toolchain_num_specified_ (false),
    toolchain_lock_ (),
    toolchain_lock_specified_ (false),
    toolchain_ver_ (),
    toolchain_ver_specified_ (false),
    toolchain_id_ (),
    toolchain_id_specified_ (false),
    interactive_ (interactive_mode::false_),
    interactive_specified_ (false),
    instance_ (1),
    instance_specified_ (false),
    instance_max_ (0),
    instance_max_specified_ (false),
    cpu_ (1),
    cpu_specified_ (false),
    build_ram_ (4 * 1024 * 1024),
    build_ram_specified_ (false),
    auxiliary_ram_ (0),
    auxiliary_ram_specified_ (false),
    bridge_ ("br1"),
    bridge_specified_ (false),
    auth_key_ (),
    auth_key_specified_ (false),
    trust_ (),
    trust_specified_ (false),
    machines_ ("/build/machines/"),
    machines_specified_ (false),
    tftp_ ("/build/tftp/"),
    tftp_specified_ (false),
    tftp_port_ (23400),
    tftp_port_specified_ (false),
    bootstrap_startup_ (300),
    bootstrap_startup_specified_ (false),
    bootstrap_timeout_ (3600),
    bootstrap_timeout_specified_ (false),
    bootstrap_auxiliary_ (900),
    bootstrap_auxiliary_specified_ (false),
    bootstrap_retries_ (2),
    bootstrap_retries_specified_ (false),
    build_startup_ (240),
    build_startup_specified_ (false),
    build_timeout_ (5400),
    build_timeout_specified_ (false),
    build_retries_ (2),
    build_retries_specified_ (false),
    intactive_timeout_ (10800),
    intactive_timeout_specified_ (false),
    connect_timeout_ (60),
    connect_timeout_specified_ (false),
    request_timeout_ (300),
    request_timeout_specified_ (false),
    request_retries_ (4),
    request_retries_specified_ (false),
    openssl_ ("openssl"),
    openssl_specified_ (false),
    openssl_option_ (),
    openssl_option_specified_ (false),
    dump_machines_ (),
    dump_task_ (),
    dump_result_ (),
    fake_bootstrap_ (),
    fake_build_ (),
    fake_machine_ (),
    fake_machine_specified_ (false),
    fake_request_ (),
    fake_request_specified_ (false)
  {
  }

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

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

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

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

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

  ::bbot::cli::usage_para agent_options::
  print_usage (::std::ostream& os, ::bbot::cli::usage_para p)
  {
    CLI_POTENTIALLY_UNUSED (os);

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

    os << "\033[1mOPTIONS\033[0m" << ::std::endl;

    os << std::endl
       << "\033[1m--help\033[0m                    Print usage information and exit." << ::std::endl;

    os << std::endl
       << "\033[1m--version\033[0m                 Print version and exit." << ::std::endl;

    os << std::endl
       << "\033[1m--verbose\033[0m \033[4mlevel\033[0m           Set the diagnostics verbosity to \033[4mlevel\033[0m between 0 and" << ::std::endl
       << "                          6 with level 1 being the default." << ::std::endl;

    os << std::endl
       << "\033[1m--systemd-daemon\033[0m          Run as a simple systemd daemon." << ::std::endl;

    os << std::endl
       << "\033[1m--toolchain-name\033[0m \033[4mstr\033[0m      Toolchain name, \033[1mdefault\033[0m by default." << ::std::endl;

    os << std::endl
       << "\033[1m--toolchain-num\033[0m \033[4mnum\033[0m       Toolchain number, 1 by default. If agents are running" << ::std::endl
       << "                          for several toolchains, then each of them should have" << ::std::endl
       << "                          a unique toolchain number between 1 and 9. This" << ::std::endl
       << "                          number is used as an offset for network ports," << ::std::endl
       << "                          interfaces, etc." << ::std::endl;

    os << std::endl
       << "\033[1m--toolchain-lock\033[0m \033[4mpath\033[0m     Absolute path to the global toolchain lock file. If" << ::std::endl
       << "                          unspecified, then" << ::std::endl
       << "                          \033[1m/var/lock/bbot-agent-\033[0m\033[4mtoolchain-name\033[0m\033[1m.lock\033[0m\033[0m is used by" << ::std::endl
       << "                          default. If empty path is specified then no global" << ::std::endl
       << "                          locking is performed. If one of the \033[1m--fake-*\033[0m options" << ::std::endl
       << "                          is specified, then no locking is performed by" << ::std::endl
       << "                          default." << ::std::endl;

    os << std::endl
       << "\033[1m--toolchain-ver\033[0m \033[4mstdver\033[0m    Toolchain version. If unspecified, then the agent's" << ::std::endl
       << "                          version will be used (which will be imprecise for" << ::std::endl
       << "                          snapshot versions)." << ::std::endl;

    os << std::endl
       << "\033[1m--toolchain-id\033[0m \033[4mstr\033[0m        Toolchain id. If unspecified or empty, then no" << ::std::endl
       << "                          re-bootstrapping on toolchain changes will be" << ::std::endl
       << "                          performed (which is primarily useful for testing)." << ::std::endl;

    os << std::endl
       << "\033[1m--interactive\033[0m \033[4mmode\033[0m        Interactive build support. Valid values for this" << ::std::endl
       << "                          option are \033[1mfalse\033[0m (only non-interactive), \033[1mtrue\033[0m (only" << ::std::endl
       << "                          interactive), and \033[1mboth\033[0m. If this option is not" << ::std::endl
       << "                          specified, then only non-interactive builds are" << ::std::endl
       << "                          supported." << ::std::endl;

    os << std::endl
       << "\033[1m--instance\033[0m \033[4mnum\033[0m            Instance number, 1 by default. If several instances" << ::std::endl
       << "                          of an agent are running for the same toolchain, then" << ::std::endl
       << "                          each of them should have a unique instance number" << ::std::endl
       << "                          between 1 and 99. This number is used as an offset" << ::std::endl
       << "                          for network ports, interfaces, etc." << ::std::endl;

    os << std::endl
       << "\033[1m--instance-max\033[0m \033[4mnum\033[0m        Maximum number of instances that can perform tasks" << ::std::endl
       << "                          concurrently. If the number of instances that have" << ::std::endl
       << "                          been started is greater than this number (normally by" << ::std::endl
       << "                          just one), then when the maximum number of tasks is" << ::std::endl
       << "                          already being performed, the extra instances operate" << ::std::endl
       << "                          in the \033[4mpriority monitor\033[0m mode: they only query" << ::std::endl
       << "                          controller URLs with priorities higher than of the" << ::std::endl
       << "                          existing tasks and can only perform a task by" << ::std::endl
       << "                          interrupting one of them. If the maximum number of" << ::std::endl
       << "                          instances is \033[1m0\033[0m (default), then it is assumed the" << ::std::endl
       << "                          number of instances started is the maximum number," << ::std::endl
       << "                          essentially disabling the priority monitor" << ::std::endl
       << "                          functionality." << ::std::endl;

    os << std::endl
       << "\033[1m--cpu\033[0m \033[4mnum\033[0m                 Number of CPUs (threads) to use, 1 by default." << ::std::endl;

    os << std::endl
       << "\033[1m--build-ram\033[0m \033[4mnum\033[0m           Amount of RAM (in KiB) to use for the build machine," << ::std::endl
       << "                          4GiB by default." << ::std::endl;

    os << std::endl
       << "\033[1m--auxiliary-ram\033[0m \033[4mnum\033[0m       Amount of RAM (in KiB) to use for auxiliary machines." << ::std::endl
       << "                          To disable running auxiliary machines, specify \033[1m0\033[0m. If" << ::std::endl
       << "                          unspecified, then currently the behavior is the same" << ::std::endl
       << "                          as specifying \033[1m0\033[0m but this may change in the future" << ::std::endl
       << "                          (for example, to support a more dynamic allocation" << ::std::endl
       << "                          strategy)." << ::std::endl;

    os << std::endl
       << "\033[1m--bridge\033[0m \033[4miface\033[0m            Bridge interface to use for machine networking, \033[1mbr1\033[0m" << ::std::endl
       << "                          by default." << ::std::endl;

    os << std::endl
       << "\033[1m--auth-key\033[0m \033[4mfile\033[0m           Private key for the public key-based agent" << ::std::endl
       << "                          authentication. If not specified, then the agent will" << ::std::endl
       << "                          not be able to request tasks from controllers that" << ::std::endl
       << "                          require authentication." << ::std::endl
       << ::std::endl
       << "                          The file is expected to contain a single PEM-encoded" << ::std::endl
       << "                          private key without a password. A suitable key can be" << ::std::endl
       << "                          generated using the following command:" << ::std::endl
       << ::std::endl
       << "                          $ openssl genrsa 4096 >key.pem" << ::std::endl;

    os << std::endl
       << "\033[1m--trust\033[0m \033[4mfingerprint\033[0m       Trust repository certificate with a SHA256" << ::std::endl
       << "                          \033[4mfingerprint\033[0m." << ::std::endl;

    os << std::endl
       << "\033[1m--machines\033[0m \033[4mdir\033[0m            The location of the build machines, \033[1m/build/machines/\033[0m" << ::std::endl
       << "                          by default." << ::std::endl;

    os << std::endl
       << "\033[1m--tftp\033[0m \033[4mdir\033[0m                The location of the TFTP server root, \033[1m/build/tftp/\033[0m by" << ::std::endl
       << "                          default." << ::std::endl;

    os << std::endl
       << "\033[1m--tftp-port\033[0m \033[4mnum\033[0m           TFTP server port base, 23400 by default. The actual" << ::std::endl
       << "                          port is calculated by adding an offset calculated" << ::std::endl
       << "                          based on the toolchain, instance, and machine" << ::std::endl
       << "                          numbers." << ::std::endl;

    os << std::endl
       << "\033[1m--bootstrap-startup\033[0m \033[4msec\033[0m   Maximum number of seconds to wait for build machine" << ::std::endl
       << "                          bootstrap startup, 300 (5 minutes) by default." << ::std::endl;

    os << std::endl
       << "\033[1m--bootstrap-timeout\033[0m \033[4msec\033[0m   Maximum number of seconds to wait for build machine" << ::std::endl
       << "                          bootstrap completion, 3600 (60 minutes) by default." << ::std::endl;

    os << std::endl
       << "\033[1m--bootstrap-auxiliary\033[0m \033[4msec\033[0m Maximum number of seconds to wait for auxiliary" << ::std::endl
       << "                          machine bootstrap completion, 900 (15 minutes) by" << ::std::endl
       << "                          default." << ::std::endl;

    os << std::endl
       << "\033[1m--bootstrap-retries\033[0m \033[4mnum\033[0m   Number of times to retry a mis-booted bootstrap, 2 (3" << ::std::endl
       << "                          attempts total) by default." << ::std::endl;

    os << std::endl
       << "\033[1m--build-startup\033[0m \033[4msec\033[0m       Maximum number of seconds to wait for build startup," << ::std::endl
       << "                          240 (4 minutes) by default. This value is used for" << ::std::endl
       << "                          both build and auxiliary machines." << ::std::endl;

    os << std::endl
       << "\033[1m--build-timeout\033[0m \033[4msec\033[0m       Maximum number of seconds to wait for build" << ::std::endl
       << "                          completion, 5400 (90 minutes) by default." << ::std::endl;

    os << std::endl
       << "\033[1m--build-retries\033[0m \033[4mnum\033[0m       Number of times to retry a mis-booted build, 2 (3" << ::std::endl
       << "                          attempts total) by default." << ::std::endl;

    os << std::endl
       << "\033[1m--intactive-timeout\033[0m \033[4msec\033[0m   Maximum number of seconds to wait for interactive" << ::std::endl
       << "                          build completion, 10800 (3 hours) by default." << ::std::endl;

    os << std::endl
       << "\033[1m--connect-timeout\033[0m \033[4msec\033[0m     Maximum number of seconds to wait for controller" << ::std::endl
       << "                          request connection, 60 (1 minute) by default." << ::std::endl;

    os << std::endl
       << "\033[1m--request-timeout\033[0m \033[4msec\033[0m     Maximum number of seconds to wait for controller" << ::std::endl
       << "                          request completion, 300 (5 minutes) by default." << ::std::endl;

    os << std::endl
       << "\033[1m--request-retries\033[0m \033[4mnum\033[0m     Number of times to retry a controller request, 4 (5" << ::std::endl
       << "                          attempts total) by default. Note that both the total" << ::std::endl
       << "                          time for all retries as well as the time of each" << ::std::endl
       << "                          retry are limited by the same --request-timeout\033[0m" << ::std::endl
       << "                          value. This means that a successful request may take" << ::std::endl
       << "                          up to twice as long if a connection was established" << ::std::endl
       << "                          at the end of the retry window and took just as long" << ::std::endl
       << "                          to complete." << ::std::endl;

    os << std::endl
       << "\033[1m--openssl\033[0m \033[4mpath\033[0m            The openssl program to be used for crypto operations." << ::std::endl
       << "                          You can also specify additional options that should" << ::std::endl
       << "                          be passed to the openssl program with" << ::std::endl
       << "                          \033[1m--openssl-option\033[0m. If the openssl program is not" << ::std::endl
       << "                          explicitly specified, then \033[1mbbot-agent\033[0m will use" << ::std::endl
       << "                          \033[1mopenssl\033[0m by default." << ::std::endl;

    os << std::endl
       << "\033[1m--openssl-option\033[0m \033[4mopt\033[0m      Additional option to be passed to the openssl program" << ::std::endl
       << "                          (see \033[1m--openssl\033[0m for details). Repeat this option to" << ::std::endl
       << "                          specify multiple openssl options." << ::std::endl;

    os << std::endl
       << "\033[1m--dump-machines\033[0m           Dump the available machines to \033[1mstdout\033[0m," << ::std::endl
       << "                          (re)-bootstrapping any if necessary, and exit." << ::std::endl;

    os << std::endl
       << "\033[1m--dump-task\033[0m               Dump the received build task to \033[1mstdout\033[0m and exit." << ::std::endl;

    os << std::endl
       << "\033[1m--dump-result\033[0m             Dump the obtained build result to \033[1mstdout\033[0m and exit." << ::std::endl;

    os << std::endl
       << "\033[1m--fake-bootstrap\033[0m          Fake the machine bootstrap process by creating the" << ::std::endl
       << "                          expected bootstrapped machine manifest." << ::std::endl;

    os << std::endl
       << "\033[1m--fake-build\033[0m              Fake the package building process by creating the" << ::std::endl
       << "                          aborted build result." << ::std::endl;

    os << std::endl
       << "\033[1m--fake-machine\033[0m \033[4mfile\033[0m       Fake the machine enumeration process by reading the" << ::std::endl
       << "                          machine header manifest from \033[4mfile\033[0m (or \033[1mstdin\033[0m if \033[4mfile\033[0m" << ::std::endl
       << "                          is '\033[1m-\033[0m')." << ::std::endl;

    os << std::endl
       << "\033[1m--fake-request\033[0m \033[4mfile\033[0m       Fake the task request process by reading the task" << ::std::endl
       << "                          manifest from \033[4mfile\033[0m (or \033[1mstdin\033[0m if \033[4mfile\033[0m is '\033[1m-\033[0m')." << ::std::endl;

    p = ::bbot::cli::usage_para::option;

    return p;
  }

  typedef
  std::map<std::string, void (*) (agent_options&, ::bbot::cli::scanner&)>
  _cli_agent_options_map;

  static _cli_agent_options_map _cli_agent_options_map_;

  struct _cli_agent_options_map_init
  {
    _cli_agent_options_map_init ()
    {
      _cli_agent_options_map_["--help"] =
      &::bbot::cli::thunk< agent_options, &agent_options::help_ >;
      _cli_agent_options_map_["--version"] =
      &::bbot::cli::thunk< agent_options, &agent_options::version_ >;
      _cli_agent_options_map_["--verbose"] =
      &::bbot::cli::thunk< agent_options, uint16_t, &agent_options::verbose_,
        &agent_options::verbose_specified_ >;
      _cli_agent_options_map_["--systemd-daemon"] =
      &::bbot::cli::thunk< agent_options, &agent_options::systemd_daemon_ >;
      _cli_agent_options_map_["--toolchain-name"] =
      &::bbot::cli::thunk< agent_options, string, &agent_options::toolchain_name_,
        &agent_options::toolchain_name_specified_ >;
      _cli_agent_options_map_["--toolchain-num"] =
      &::bbot::cli::thunk< agent_options, uint16_t, &agent_options::toolchain_num_,
        &agent_options::toolchain_num_specified_ >;
      _cli_agent_options_map_["--toolchain-lock"] =
      &::bbot::cli::thunk< agent_options, string, &agent_options::toolchain_lock_,
        &agent_options::toolchain_lock_specified_ >;
      _cli_agent_options_map_["--toolchain-ver"] =
      &::bbot::cli::thunk< agent_options, standard_version, &agent_options::toolchain_ver_,
        &agent_options::toolchain_ver_specified_ >;
      _cli_agent_options_map_["--toolchain-id"] =
      &::bbot::cli::thunk< agent_options, string, &agent_options::toolchain_id_,
        &agent_options::toolchain_id_specified_ >;
      _cli_agent_options_map_["--interactive"] =
      &::bbot::cli::thunk< agent_options, interactive_mode, &agent_options::interactive_,
        &agent_options::interactive_specified_ >;
      _cli_agent_options_map_["--instance"] =
      &::bbot::cli::thunk< agent_options, uint16_t, &agent_options::instance_,
        &agent_options::instance_specified_ >;
      _cli_agent_options_map_["--instance-max"] =
      &::bbot::cli::thunk< agent_options, uint16_t, &agent_options::instance_max_,
        &agent_options::instance_max_specified_ >;
      _cli_agent_options_map_["--cpu"] =
      &::bbot::cli::thunk< agent_options, size_t, &agent_options::cpu_,
        &agent_options::cpu_specified_ >;
      _cli_agent_options_map_["--build-ram"] =
      &::bbot::cli::thunk< agent_options, size_t, &agent_options::build_ram_,
        &agent_options::build_ram_specified_ >;
      _cli_agent_options_map_["--auxiliary-ram"] =
      &::bbot::cli::thunk< agent_options, size_t, &agent_options::auxiliary_ram_,
        &agent_options::auxiliary_ram_specified_ >;
      _cli_agent_options_map_["--bridge"] =
      &::bbot::cli::thunk< agent_options, string, &agent_options::bridge_,
        &agent_options::bridge_specified_ >;
      _cli_agent_options_map_["--auth-key"] =
      &::bbot::cli::thunk< agent_options, path, &agent_options::auth_key_,
        &agent_options::auth_key_specified_ >;
      _cli_agent_options_map_["--trust"] =
      &::bbot::cli::thunk< agent_options, strings, &agent_options::trust_,
        &agent_options::trust_specified_ >;
      _cli_agent_options_map_["--machines"] =
      &::bbot::cli::thunk< agent_options, dir_path, &agent_options::machines_,
        &agent_options::machines_specified_ >;
      _cli_agent_options_map_["--tftp"] =
      &::bbot::cli::thunk< agent_options, dir_path, &agent_options::tftp_,
        &agent_options::tftp_specified_ >;
      _cli_agent_options_map_["--tftp-port"] =
      &::bbot::cli::thunk< agent_options, uint16_t, &agent_options::tftp_port_,
        &agent_options::tftp_port_specified_ >;
      _cli_agent_options_map_["--bootstrap-startup"] =
      &::bbot::cli::thunk< agent_options, size_t, &agent_options::bootstrap_startup_,
        &agent_options::bootstrap_startup_specified_ >;
      _cli_agent_options_map_["--bootstrap-timeout"] =
      &::bbot::cli::thunk< agent_options, size_t, &agent_options::bootstrap_timeout_,
        &agent_options::bootstrap_timeout_specified_ >;
      _cli_agent_options_map_["--bootstrap-auxiliary"] =
      &::bbot::cli::thunk< agent_options, size_t, &agent_options::bootstrap_auxiliary_,
        &agent_options::bootstrap_auxiliary_specified_ >;
      _cli_agent_options_map_["--bootstrap-retries"] =
      &::bbot::cli::thunk< agent_options, size_t, &agent_options::bootstrap_retries_,
        &agent_options::bootstrap_retries_specified_ >;
      _cli_agent_options_map_["--build-startup"] =
      &::bbot::cli::thunk< agent_options, size_t, &agent_options::build_startup_,
        &agent_options::build_startup_specified_ >;
      _cli_agent_options_map_["--build-timeout"] =
      &::bbot::cli::thunk< agent_options, size_t, &agent_options::build_timeout_,
        &agent_options::build_timeout_specified_ >;
      _cli_agent_options_map_["--build-retries"] =
      &::bbot::cli::thunk< agent_options, size_t, &agent_options::build_retries_,
        &agent_options::build_retries_specified_ >;
      _cli_agent_options_map_["--intactive-timeout"] =
      &::bbot::cli::thunk< agent_options, size_t, &agent_options::intactive_timeout_,
        &agent_options::intactive_timeout_specified_ >;
      _cli_agent_options_map_["--connect-timeout"] =
      &::bbot::cli::thunk< agent_options, size_t, &agent_options::connect_timeout_,
        &agent_options::connect_timeout_specified_ >;
      _cli_agent_options_map_["--request-timeout"] =
      &::bbot::cli::thunk< agent_options, size_t, &agent_options::request_timeout_,
        &agent_options::request_timeout_specified_ >;
      _cli_agent_options_map_["--request-retries"] =
      &::bbot::cli::thunk< agent_options, size_t, &agent_options::request_retries_,
        &agent_options::request_retries_specified_ >;
      _cli_agent_options_map_["--openssl"] =
      &::bbot::cli::thunk< agent_options, path, &agent_options::openssl_,
        &agent_options::openssl_specified_ >;
      _cli_agent_options_map_["--openssl-option"] =
      &::bbot::cli::thunk< agent_options, strings, &agent_options::openssl_option_,
        &agent_options::openssl_option_specified_ >;
      _cli_agent_options_map_["--dump-machines"] =
      &::bbot::cli::thunk< agent_options, &agent_options::dump_machines_ >;
      _cli_agent_options_map_["--dump-task"] =
      &::bbot::cli::thunk< agent_options, &agent_options::dump_task_ >;
      _cli_agent_options_map_["--dump-result"] =
      &::bbot::cli::thunk< agent_options, &agent_options::dump_result_ >;
      _cli_agent_options_map_["--fake-bootstrap"] =
      &::bbot::cli::thunk< agent_options, &agent_options::fake_bootstrap_ >;
      _cli_agent_options_map_["--fake-build"] =
      &::bbot::cli::thunk< agent_options, &agent_options::fake_build_ >;
      _cli_agent_options_map_["--fake-machine"] =
      &::bbot::cli::thunk< agent_options, path, &agent_options::fake_machine_,
        &agent_options::fake_machine_specified_ >;
      _cli_agent_options_map_["--fake-request"] =
      &::bbot::cli::thunk< agent_options, path, &agent_options::fake_request_,
        &agent_options::fake_request_specified_ >;
    }
  };

  static _cli_agent_options_map_init _cli_agent_options_map_init_;

  bool agent_options::
  _parse (const char* o, ::bbot::cli::scanner& s)
  {
    _cli_agent_options_map::const_iterator i (_cli_agent_options_map_.find (o));

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

    return false;
  }

  bool agent_options::
  _parse (::bbot::cli::scanner& s,
          ::bbot::cli::unknown_mode opt_mode,
          ::bbot::cli::unknown_mode arg_mode)
  {
    // Can't skip combined flags (--no-combined-flags).
    //
    assert (opt_mode != ::bbot::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;
        s.skip ();
        r = true;
        continue;
      }

      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)
            };

            ::bbot::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 ::bbot::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
                };

                ::bbot::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 ::bbot::cli::unknown_mode::skip:
            {
              s.skip ();
              r = true;
              continue;
            }
            case ::bbot::cli::unknown_mode::stop:
            {
              break;
            }
            case ::bbot::cli::unknown_mode::fail:
            {
              throw ::bbot::cli::unknown_option (o);
            }
          }

          break;
        }
      }

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

      break;
    }

    return r;
  }
}

namespace bbot
{
  ::bbot::cli::usage_para
  print_bbot_agent_usage (::std::ostream& os, ::bbot::cli::usage_para p)
  {
    CLI_POTENTIALLY_UNUSED (os);

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

    os << "\033[1mSYNOPSIS\033[0m" << ::std::endl
       << ::std::endl
       << "\033[1mbbot-agent --help\033[0m" << ::std::endl
       << "\033[1mbbot-agent --version\033[0m" << ::std::endl
       << "\033[1mbbot-agent\033[0m [\033[4moptions\033[0m] [\033[4mpriority\033[0m=]\033[4murl\033[0m...\033[0m" << ::std::endl
       << ::std::endl
       << "\033[1mDESCRIPTION\033[0m" << ::std::endl
       << ::std::endl
       << "\033[1mbbot-agent\033[0m @@ TODO." << ::std::endl
       << ::std::endl
       << "The controller URL \033[4mpriority\033[0m is a four or five-digit decimal value. If it is" << ::std::endl
       << "absent, then \033[1m0\033[0m (lowest priority) is assumed. URLs with equal priority are" << ::std::endl
       << "queried at random." << ::std::endl
       << ::std::endl
       << "The \033[4mpriority\033[0m value has the [\033[4mF\033[0m]\033[4mDCBA\033[0m\033[0m form which encodes four priority levels" << ::std::endl
       << "(\033[4mDCBA\033[0m) each occupying one decimal digit (so there are 10 distinct priorities in" << ::std::endl
       << "each level) plus the optional boost flag (\033[4mF\033[0m). These levels offer different" << ::std::endl
       << "trade-offs between the speed of completing a higher priority task and" << ::std::endl
       << "potentially discarding work that has already been done." << ::std::endl
       << ::std::endl
       << "The first priority level (\033[4mA\033[0m) is a simple preference: among the URLs with equal" << ::std::endl
       << "values for other levels (\033[4mDCB\033[0m), those with higher first level priorities are" << ::std::endl
       << "queried first." << ::std::endl
       << ::std::endl
       << "The second priority level (\033[4mB\033[0m) has the semantics of the first level plus it" << ::std::endl
       << "prevents URLs with lower second priority level from being queried until the" << ::std::endl
       << "task with a higher second priority level has completed, effectively conserving" << ::std::endl
       << "the resources for the higher priority task." << ::std::endl
       << ::std::endl
       << "The third priority level (\033[4mC\033[0m) has the semantics of the second level plus it may" << ::std::endl
       << "interrupt one lower third priority level task in order to perform the higher" << ::std::endl
       << "third priority task (the interrupt is necessary if the desired machine is used" << ::std::endl
       << "by the lower priority task or the number of tasks already being performed is" << ::std::endl
       << "the maximum allowed to be performed concurrently; see \033[1m--instance-max\033[0m)." << ::std::endl
       << ::std::endl
       << "Finally, the fourth priority level (\033[4mD\033[0m) has the semantics of the third level" << ::std::endl
       << "except that not one but all the lower fourth priority level tasks are" << ::std::endl
       << "interrupting, effectively dedicating all the available resources to the higher" << ::std::endl
       << "priority task. This level can also be combined with the boost flag \033[4mF\033[0m. If this" << ::std::endl
       << "flag is \033[1m1\033[0m then the higher priority task's CPU number (\033[1m--cpu\033[0m) is boosted to the" << ::std::endl
       << "full number of available hardware threads (or, to view it another way, the" << ::std::endl
       << "fourth priority level has 20 possible values, not 10, with the first 0-9 being" << ::std::endl
       << "without the boost while the last 10-19 being with the boost). Note that this" << ::std::endl
       << "boosting semantics may not be accurate if the agent is executed with CPU" << ::std::endl
       << "affinity. Also note that there is no corresponding RAM boosting and it's" << ::std::endl
       << "possible that in some configurations the amount of RAM will be insufficient for" << ::std::endl
       << "the boosted CPU count." << ::std::endl
       << ::std::endl
       << "Note that the priority levels are hierarchical in a sense that within a given" << ::std::endl
       << "higher level URLs can be further prioritized using the lower levels. As an" << ::std::endl
       << "example, consider a deployment with three controller URLs: background package" << ::std::endl
       << "rebuilds (\033[1mpkg.example.org\033[0m), user-initiated CI (\033[1mci.example.org\033[0m), and" << ::std::endl
       << "user-initiated interactive CI (\033[1mici.example.org\033[0m). Given the following" << ::std::endl
       << "priorities:" << ::std::endl
       << ::std::endl
       << "0000=https://pkg.example.org" << ::std::endl
       << "0100=https://ci.example.org" << ::std::endl
       << "0101=https://ici.example.org" << ::std::endl
       << ::std::endl
       << "Both types of CI tasks will interrupt one background rebuild task if necessary" << ::std::endl
       << "while the interactive CI tasks will be merely preferred over non-interactive." << ::std::endl
       << ::std::endl
       << "Note that on termination \033[1mbbot-agent\033[0m may leave behind a machine lock and working" << ::std::endl
       << "machine snapshot. It is expected that the caller (normally Build OS monitor)" << ::std::endl
       << "cleans them up before restarting the agent." << ::std::endl;

    p = ::bbot::agent_options::print_usage (os, ::bbot::cli::usage_para::text);

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

    os << "\033[1mEXIT STATUS\033[0m" << ::std::endl
       << ::std::endl
       << "Non-zero exit status is returned in case of an error." << ::std::endl;

    p = ::bbot::cli::usage_para::text;

    return p;
  }
}

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

