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

// Begin prologue.
//
#include <options-parser.hxx>
//
// End prologue.

#include <options.hxx>

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

namespace cli
{
  // unknown_option
  //
  unknown_option::
  ~unknown_option () throw ()
  {
  }

  void unknown_option::
  print (::std::wostream& os) const
  {
    os << "unknown option '" << option ().c_str () << "'";
  }

  const char* unknown_option::
  what () const throw ()
  {
    return "unknown option";
  }

  // unknown_argument
  //
  unknown_argument::
  ~unknown_argument () throw ()
  {
  }

  void unknown_argument::
  print (::std::wostream& os) const
  {
    os << "unknown argument '" << argument ().c_str () << "'";
  }

  const char* unknown_argument::
  what () const throw ()
  {
    return "unknown argument";
  }

  // missing_value
  //
  missing_value::
  ~missing_value () throw ()
  {
  }

  void missing_value::
  print (::std::wostream& os) const
  {
    os << "missing value for option '" << option ().c_str () << "'";
  }

  const char* missing_value::
  what () const throw ()
  {
    return "missing option value";
  }

  // invalid_value
  //
  invalid_value::
  ~invalid_value () throw ()
  {
  }

  void invalid_value::
  print (::std::wostream& os) const
  {
    os << "invalid value '" << value ().c_str () << "' for option '"
       << option ().c_str () << "'";
  }

  const char* invalid_value::
  what () const throw ()
  {
    return "invalid option value";
  }

  // eos_reached
  //
  void eos_reached::
  print (::std::wostream& os) const
  {
    os << what ();
  }

  const char* eos_reached::
  what () const throw ()
  {
    return "end of argument stream reached";
  }

  // file_io_failure
  //
  file_io_failure::
  ~file_io_failure () throw ()
  {
  }

  void file_io_failure::
  print (::std::wostream& os) const
  {
    os << "unable to open file '" << file ().c_str () << "' or read failure";
  }

  const char* file_io_failure::
  what () const throw ()
  {
    return "unable to open file or read failure";
  }

  // unmatched_quote
  //
  unmatched_quote::
  ~unmatched_quote () throw ()
  {
  }

  void unmatched_quote::
  print (::std::wostream& os) const
  {
    os << "unmatched quote in argument '" << argument ().c_str () << "'";
  }

  const char* unmatched_quote::
  what () const throw ()
  {
    return "unmatched quote";
  }

  // scanner
  //
  scanner::
  ~scanner ()
  {
  }

  // argv_scanner
  //
  bool argv_scanner::
  more ()
  {
    return i_ < argc_;
  }

  const char* argv_scanner::
  peek ()
  {
    if (i_ < argc_)
      return argv_[i_];
    else
      throw eos_reached ();
  }

  const char* argv_scanner::
  next ()
  {
    if (i_ < argc_)
    {
      const char* r (argv_[i_]);

      if (erase_)
      {
        for (int i (i_ + 1); i < argc_; ++i)
          argv_[i - 1] = argv_[i];

        --argc_;
        argv_[argc_] = 0;
      }
      else
        ++i_;

      return r;
    }
    else
      throw eos_reached ();
  }

  void argv_scanner::
  skip ()
  {
    if (i_ < argc_)
      ++i_;
    else
      throw eos_reached ();
  }

  // argv_file_scanner
  //
  bool argv_file_scanner::
  more ()
  {
    if (!args_.empty ())
      return true;

    while (base::more ())
    {
      // See if the next argument is the file option.
      //
      const char* a (base::peek ());
      const option_info* oi;

      if (!skip_ && (oi = find (a)))
      {
        base::next ();

        if (!base::more ())
          throw missing_value (oi->option);

        if (oi->search_func != 0)
        {
          std::string f (oi->search_func (base::next (), oi->arg));

          if (!f.empty ())
            load (f);
        }
        else
          load (base::next ());

        if (!args_.empty ())
          return true;
      }
      else
      {
        if (!skip_)
          skip_ = (std::strcmp (a, "--") == 0);

        return true;
      }
    }

    return false;
  }

  const char* argv_file_scanner::
  peek ()
  {
    if (!more ())
      throw eos_reached ();

    return args_.empty () ? base::peek () : args_.front ().c_str ();
  }

  const char* argv_file_scanner::
  next ()
  {
    if (!more ())
      throw eos_reached ();

    if (args_.empty ())
      return base::next ();
    else
    {
      hold_.swap (args_.front ());
      args_.pop_front ();
      return hold_.c_str ();
    }
  }

  void argv_file_scanner::
  skip ()
  {
    if (!more ())
      throw eos_reached ();

    if (args_.empty ())
      return base::skip ();
    else
      args_.pop_front ();
  }

  const argv_file_scanner::option_info* argv_file_scanner::
  find (const char* a) const
  {
    for (std::size_t i (0); i < options_count_; ++i)
      if (std::strcmp (a, options_[i].option) == 0)
        return &options_[i];

    return 0;
  }

  void argv_file_scanner::
  load (const std::string& file)
  {
    using namespace std;

    ifstream is (file.c_str ());

    if (!is.is_open ())
      throw file_io_failure (file);

    while (!is.eof ())
    {
      string line;
      getline (is, line);

      if (is.fail () && !is.eof ())
        throw file_io_failure (file);

      string::size_type n (line.size ());

      // Trim the line from leading and trailing whitespaces.
      //
      if (n != 0)
      {
        const char* f (line.c_str ());
        const char* l (f + n);

        const char* of (f);
        while (f < l && (*f == ' ' || *f == '\t' || *f == '\r'))
          ++f;

        --l;

        const char* ol (l);
        while (l > f && (*l == ' ' || *l == '\t' || *l == '\r'))
          --l;

        if (f != of || l != ol)
          line = f <= l ? string (f, l - f + 1) : string ();
      }

      // Ignore empty lines, those that start with #.
      //
      if (line.empty () || line[0] == '#')
        continue;

      string::size_type p (line.find (' '));

      if (p == string::npos)
      {
        if (!skip_)
          skip_ = (line == "--");

        args_.push_back (line);
      }
      else
      {
        string s1 (line, 0, p);

        // Skip leading whitespaces in the argument.
        //
        n = line.size ();
        for (++p; p < n; ++p)
        {
          char c (line[p]);

          if (c != ' ' && c != '\t' && c != '\r')
            break;
        }

        string s2 (line, p);

        // If the string is wrapped in quotes, remove them.
        //
        n = s2.size ();
        char cf (s2[0]), cl (s2[n - 1]);

        if (cf == '"' || cf == '\'' || cl == '"' || cl == '\'')
        {
          if (n == 1 || cf != cl)
            throw unmatched_quote (s2);

          s2 = string (s2, 1, n - 2);
        }

        const option_info* oi;
        if (!skip_ && (oi = find (s1.c_str ())))
        {
          if (s2.empty ())
            throw missing_value (oi->option);

          if (oi->search_func != 0)
          {
            std::string f (oi->search_func (s2.c_str (), oi->arg));

            if (!f.empty ())
              load (f);
          }
          else
            load (s2);
        }
        else
        {
          args_.push_back (s1);
          args_.push_back (s2);
        }
      }
    }
  }

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

      if (s.more ())
      {
        std::string v (s.next ());
        std::istringstream is (v);
        if (!(is >> x && is.eof ()))
          throw invalid_value (o, v);
      }
      else
        throw missing_value (o);

      xs = true;
    }
  };

  template <>
  struct parser<bool>
  {
    static void
    parse (bool& x, scanner& s)
    {
      s.next ();
      x = 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::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>
  struct parser<std::set<X> >
  {
    static void
    parse (std::set<X>& 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>
  struct parser<std::map<K, V> >
  {
    static void
    parse (std::map<K, V>& m, bool& xs, scanner& s)
    {
      std::string o (s.next ());

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

        if (p == std::string::npos)
        {
          K k = K ();

          if (!ov.empty ())
          {
            std::istringstream ks (ov);

            if (!(ks >> k && ks.eof ()))
              throw invalid_value (o, ov);
          }

          m[k] = V ();
        }
        else
        {
          K k = K ();
          V v = V ();
          std::string kstr (ov, 0, p);
          std::string vstr (ov, p + 1);

          if (!kstr.empty ())
          {
            std::istringstream ks (kstr);

            if (!(ks >> k && ks.eof ()))
              throw invalid_value (o, ov);
          }

          if (!vstr.empty ())
          {
            std::istringstream vs (vstr);

            if (!(vs >> v && vs.eof ()))
              throw invalid_value (o, ov);
          }

          m[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, typename T, T X::*M, bool X::*S>
  void
  thunk (X& x, scanner& s)
  {
    parser<T>::parse (x.*M, x.*S, s);
  }
}

#include <map>
#include <cstring>

// help_options
//

help_options::
help_options ()
: help_ (),
  version_ (),
  proprietary_license_ ()
{
}

help_options::
help_options (int& argc,
              char** argv,
              bool erase,
              ::cli::unknown_mode opt,
              ::cli::unknown_mode arg)
: help_ (),
  version_ (),
  proprietary_license_ ()
{
  ::cli::argv_scanner s (argc, argv, erase);
  _parse (s, opt, arg);
}

help_options::
help_options (int start,
              int& argc,
              char** argv,
              bool erase,
              ::cli::unknown_mode opt,
              ::cli::unknown_mode arg)
: help_ (),
  version_ (),
  proprietary_license_ ()
{
  ::cli::argv_scanner s (start, argc, argv, erase);
  _parse (s, opt, arg);
}

help_options::
help_options (int& argc,
              char** argv,
              int& end,
              bool erase,
              ::cli::unknown_mode opt,
              ::cli::unknown_mode arg)
: help_ (),
  version_ (),
  proprietary_license_ ()
{
  ::cli::argv_scanner s (argc, argv, erase);
  _parse (s, opt, arg);
  end = s.end ();
}

help_options::
help_options (int start,
              int& argc,
              char** argv,
              int& end,
              bool erase,
              ::cli::unknown_mode opt,
              ::cli::unknown_mode arg)
: help_ (),
  version_ (),
  proprietary_license_ ()
{
  ::cli::argv_scanner s (start, argc, argv, erase);
  _parse (s, opt, arg);
  end = s.end ();
}

help_options::
help_options (::cli::scanner& s,
              ::cli::unknown_mode opt,
              ::cli::unknown_mode arg)
: help_ (),
  version_ (),
  proprietary_license_ ()
{
  _parse (s, opt, arg);
}

void help_options::
print_usage (::std::wostream&)
{
}

typedef
std::map<std::string, void (*) (help_options&, ::cli::scanner&)>
_cli_help_options_map;

static _cli_help_options_map _cli_help_options_map_;

struct _cli_help_options_map_init
{
  _cli_help_options_map_init ()
  {
    _cli_help_options_map_["--help"] = 
    &::cli::thunk< help_options, bool, &help_options::help_ >;
    _cli_help_options_map_["--version"] = 
    &::cli::thunk< help_options, bool, &help_options::version_ >;
    _cli_help_options_map_["--proprietary-license"] = 
    &::cli::thunk< help_options, bool, &help_options::proprietary_license_ >;
  }
};

static _cli_help_options_map_init _cli_help_options_map_init_;

bool help_options::
_parse (const char* o, ::cli::scanner& s)
{
  _cli_help_options_map::const_iterator i (_cli_help_options_map_.find (o));

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

  return false;
}

void help_options::
_parse (::cli::scanner& s,
        ::cli::unknown_mode opt_mode,
        ::cli::unknown_mode arg_mode)
{
  bool opt = true;

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

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

    if (opt && _parse (o, s));
    else if (opt && std::strncmp (o, "-", 1) == 0 && o[1] != '\0')
    {
      switch (opt_mode)
      {
        case ::cli::unknown_mode::skip:
        {
          s.skip ();
          continue;
        }
        case ::cli::unknown_mode::stop:
        {
          break;
        }
        case ::cli::unknown_mode::fail:
        {
          throw ::cli::unknown_option (o);
        }
      }

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

      break;
    }
  }
}

// options
//

options::
options ()
: disable_warning_ (),
  disable_warning_specified_ (false),
  options_file_ (),
  options_file_specified_ (false),
  show_sloc_ (),
  sloc_limit_ (),
  sloc_limit_specified_ (false),
  proprietary_license_ (),
  custom_literals_ (),
  custom_literals_specified_ (false),
  preserve_anonymous_ (),
  show_anonymous_ (),
  anonymous_regex_ (),
  anonymous_regex_specified_ (false),
  anonymous_regex_trace_ (),
  morph_anonymous_ (),
  location_map_ (),
  location_map_specified_ (false),
  location_regex_ (),
  location_regex_specified_ (false),
  location_regex_trace_ (),
  file_per_type_ (),
  type_file_regex_ (),
  type_file_regex_specified_ (false),
  type_file_regex_trace_ (),
  schema_file_regex_ (),
  schema_file_regex_specified_ (false),
  schema_file_regex_trace_ (),
  fat_type_file_ (),
  file_list_ (),
  file_list_specified_ (false),
  file_list_prologue_ (),
  file_list_prologue_specified_ (false),
  file_list_epilogue_ (),
  file_list_epilogue_specified_ (false),
  file_list_delim_ ("\n"),
  file_list_delim_specified_ (false),
  disable_multi_import_ (),
  disable_full_check_ ()
{
}

void options::
print_usage (::std::wostream& os)
{
  os << "--disable-warning <warn>     Disable printing warning with id <warn>." << ::std::endl;

  os << "--options-file <file>        Read additional options from <file>." << ::std::endl;

  os << "--show-sloc                  Show the number of generated physical source lines" << ::std::endl
     << "                             of code (SLOC)." << ::std::endl;

  os << "--sloc-limit <num>           Check that the number of generated physical source" << ::std::endl
     << "                             lines of code (SLOC) does not exceed <num>." << ::std::endl;

  os << "--proprietary-license        Indicate that the generated code is licensed under" << ::std::endl
     << "                             a proprietary license instead of the GPL." << ::std::endl;

  os << "--custom-literals <file>     Load custom XML string to C++ literal mappings" << ::std::endl
     << "                             from <file>." << ::std::endl;

  os << "--preserve-anonymous         Preserve anonymous types." << ::std::endl;

  os << "--show-anonymous             Show elements and attributes that are of anonymous" << ::std::endl
     << "                             types." << ::std::endl;

  os << "--anonymous-regex <regex>    Add <regex> to the list of regular expressions" << ::std::endl
     << "                             used to derive names for anonymous types from the" << ::std::endl
     << "                             enclosing attributes/elements." << ::std::endl;

  os << "--anonymous-regex-trace      Trace the process of applying regular expressions" << ::std::endl
     << "                             specified with the '--anonymous-regex' option." << ::std::endl;

  os << "--location-map <ol>=<nl>     Map the original schema location <ol> that is" << ::std::endl
     << "                             specified in the XML Schema include or import" << ::std::endl
     << "                             elements to new schema location <nl>." << ::std::endl;

  os << "--location-regex <regex>     Add <regex> to the list of regular expressions" << ::std::endl
     << "                             used to map schema locations that are specified in" << ::std::endl
     << "                             the XML Schema include or import elements." << ::std::endl;

  os << "--location-regex-trace       Trace the process of applying regular expressions" << ::std::endl
     << "                             specified with the '--location-regex' option." << ::std::endl;

  os << "--file-per-type              Generate a separate set of C++ files for each type" << ::std::endl
     << "                             defined in XML Schema." << ::std::endl;

  os << "--type-file-regex <regex>    Add <regex> to the list of regular expressions" << ::std::endl
     << "                             used to translate type names to file names when" << ::std::endl
     << "                             the '--file-per-type' option is specified." << ::std::endl;

  os << "--type-file-regex-trace      Trace the process of applying regular expressions" << ::std::endl
     << "                             specified with the '--type-file-regex' option." << ::std::endl;

  os << "--schema-file-regex <regex>  Add <regex> to the list of regular expressions" << ::std::endl
     << "                             used to translate schema file names when the" << ::std::endl
     << "                             '--file-per-type' option is specified." << ::std::endl;

  os << "--schema-file-regex-trace    Trace the process of applying regular expressions" << ::std::endl
     << "                             specified with the '--schema-file-regex' option." << ::std::endl;

  os << "--fat-type-file              Generate code corresponding to global elements" << ::std::endl
     << "                             into type files instead of schema files when the" << ::std::endl
     << "                             '--type-file-regex' option is specified." << ::std::endl;

  os << "--file-list <file>           Write a list of generated C++ files to <file>." << ::std::endl;

  os << "--file-list-prologue <text>  Insert <text> at the beginning of the file list." << ::std::endl;

  os << "--file-list-epilogue <text>  Insert <text> at the end of the file list." << ::std::endl;

  os << "--file-list-delim <text>     Delimit file names written to the file list with" << ::std::endl
     << "                             <text> instead of new lines." << ::std::endl;
}

typedef
std::map<std::string, void (*) (options&, ::cli::scanner&)>
_cli_options_map;

static _cli_options_map _cli_options_map_;

struct _cli_options_map_init
{
  _cli_options_map_init ()
  {
    _cli_options_map_["--disable-warning"] = 
    &::cli::thunk< options, NarrowStrings, &options::disable_warning_,
      &options::disable_warning_specified_ >;
    _cli_options_map_["--options-file"] = 
    &::cli::thunk< options, std::string, &options::options_file_,
      &options::options_file_specified_ >;
    _cli_options_map_["--show-sloc"] = 
    &::cli::thunk< options, bool, &options::show_sloc_ >;
    _cli_options_map_["--sloc-limit"] = 
    &::cli::thunk< options, std::size_t, &options::sloc_limit_,
      &options::sloc_limit_specified_ >;
    _cli_options_map_["--proprietary-license"] = 
    &::cli::thunk< options, bool, &options::proprietary_license_ >;
    _cli_options_map_["--custom-literals"] = 
    &::cli::thunk< options, NarrowString, &options::custom_literals_,
      &options::custom_literals_specified_ >;
    _cli_options_map_["--preserve-anonymous"] = 
    &::cli::thunk< options, bool, &options::preserve_anonymous_ >;
    _cli_options_map_["--show-anonymous"] = 
    &::cli::thunk< options, bool, &options::show_anonymous_ >;
    _cli_options_map_["--anonymous-regex"] = 
    &::cli::thunk< options, NarrowStrings, &options::anonymous_regex_,
      &options::anonymous_regex_specified_ >;
    _cli_options_map_["--anonymous-regex-trace"] = 
    &::cli::thunk< options, bool, &options::anonymous_regex_trace_ >;
    _cli_options_map_["--morph-anonymous"] = 
    &::cli::thunk< options, bool, &options::morph_anonymous_ >;
    _cli_options_map_["--location-map"] = 
    &::cli::thunk< options, NarrowStrings, &options::location_map_,
      &options::location_map_specified_ >;
    _cli_options_map_["--location-regex"] = 
    &::cli::thunk< options, NarrowStrings, &options::location_regex_,
      &options::location_regex_specified_ >;
    _cli_options_map_["--location-regex-trace"] = 
    &::cli::thunk< options, bool, &options::location_regex_trace_ >;
    _cli_options_map_["--file-per-type"] = 
    &::cli::thunk< options, bool, &options::file_per_type_ >;
    _cli_options_map_["--type-file-regex"] = 
    &::cli::thunk< options, NarrowStrings, &options::type_file_regex_,
      &options::type_file_regex_specified_ >;
    _cli_options_map_["--type-file-regex-trace"] = 
    &::cli::thunk< options, bool, &options::type_file_regex_trace_ >;
    _cli_options_map_["--schema-file-regex"] = 
    &::cli::thunk< options, NarrowStrings, &options::schema_file_regex_,
      &options::schema_file_regex_specified_ >;
    _cli_options_map_["--schema-file-regex-trace"] = 
    &::cli::thunk< options, bool, &options::schema_file_regex_trace_ >;
    _cli_options_map_["--fat-type-file"] = 
    &::cli::thunk< options, bool, &options::fat_type_file_ >;
    _cli_options_map_["--file-list"] = 
    &::cli::thunk< options, NarrowString, &options::file_list_,
      &options::file_list_specified_ >;
    _cli_options_map_["--file-list-prologue"] = 
    &::cli::thunk< options, NarrowString, &options::file_list_prologue_,
      &options::file_list_prologue_specified_ >;
    _cli_options_map_["--file-list-epilogue"] = 
    &::cli::thunk< options, NarrowString, &options::file_list_epilogue_,
      &options::file_list_epilogue_specified_ >;
    _cli_options_map_["--file-list-delim"] = 
    &::cli::thunk< options, NarrowString, &options::file_list_delim_,
      &options::file_list_delim_specified_ >;
    _cli_options_map_["--disable-multi-import"] = 
    &::cli::thunk< options, bool, &options::disable_multi_import_ >;
    _cli_options_map_["--disable-full-check"] = 
    &::cli::thunk< options, bool, &options::disable_full_check_ >;
  }
};

static _cli_options_map_init _cli_options_map_init_;

bool options::
_parse (const char* o, ::cli::scanner& s)
{
  _cli_options_map::const_iterator i (_cli_options_map_.find (o));

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

  return false;
}

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

