aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorKaren Arutyunov <karen@codesynthesis.com>2022-02-17 16:33:27 +0300
committerKaren Arutyunov <karen@codesynthesis.com>2022-02-18 17:15:18 +0300
commit2835794b28d482b1e391dc85f79dfa91f9e63d3e (patch)
tree9d6378809644329c62df5caef536337566b9a86f
parent68da2afcaa84479142e80e23712793f6ed3e2beb (diff)
Move parse_cmdline() to libbuild2
-rw-r--r--build2/b-options.hxx722
-rw-r--r--build2/b-options.ixx582
-rw-r--r--build2/b.cxx407
-rw-r--r--build2/buildfile35
-rw-r--r--build2/types-parsers.cxx50
-rw-r--r--build2/types-parsers.hxx43
-rwxr-xr-xdoc/cli.sh4
-rw-r--r--libbuild2/b-options.cxx (renamed from build2/b-options.cxx)1317
-rw-r--r--libbuild2/b-options.hxx726
-rw-r--r--libbuild2/b-options.ixx585
-rw-r--r--libbuild2/b.cli (renamed from build2/b.cli)0
-rw-r--r--libbuild2/buildfile46
-rw-r--r--libbuild2/cmdline.cxx408
-rw-r--r--libbuild2/cmdline.hxx29
-rw-r--r--libbuild2/types-parsers.cxx53
-rw-r--r--libbuild2/types-parsers.hxx48
16 files changed, 2553 insertions, 2502 deletions
diff --git a/build2/b-options.hxx b/build2/b-options.hxx
deleted file mode 100644
index a2f99f4..0000000
--- a/build2/b-options.hxx
+++ /dev/null
@@ -1,722 +0,0 @@
-// -*- C++ -*-
-//
-// This file was generated by CLI, a command line interface
-// compiler for C++.
-//
-
-#ifndef BUILD2_B_OPTIONS_HXX
-#define BUILD2_B_OPTIONS_HXX
-
-// Begin prologue.
-//
-//
-// End prologue.
-
-#include <list>
-#include <deque>
-#include <iosfwd>
-#include <string>
-#include <cstddef>
-#include <exception>
-
-#ifndef CLI_POTENTIALLY_UNUSED
-# if defined(_MSC_VER) || defined(__xlC__)
-# define CLI_POTENTIALLY_UNUSED(x) (void*)&x
-# else
-# define CLI_POTENTIALLY_UNUSED(x) (void)x
-# endif
-#endif
-
-namespace build2
-{
- namespace cl
- {
- class usage_para
- {
- public:
- enum value
- {
- none,
- text,
- option
- };
-
- usage_para (value);
-
- operator value () const
- {
- return v_;
- }
-
- private:
- value v_;
- };
-
- class unknown_mode
- {
- public:
- enum value
- {
- skip,
- stop,
- fail
- };
-
- unknown_mode (value);
-
- operator value () const
- {
- return v_;
- }
-
- private:
- value v_;
- };
-
- // Exceptions.
- //
-
- class exception: public std::exception
- {
- public:
- virtual void
- print (::std::ostream&) const = 0;
- };
-
- ::std::ostream&
- operator<< (::std::ostream&, const exception&);
-
- class unknown_option: public exception
- {
- public:
- virtual
- ~unknown_option () throw ();
-
- unknown_option (const std::string& option);
-
- const std::string&
- option () const;
-
- virtual void
- print (::std::ostream&) const;
-
- virtual const char*
- what () const throw ();
-
- private:
- std::string option_;
- };
-
- class unknown_argument: public exception
- {
- public:
- virtual
- ~unknown_argument () throw ();
-
- unknown_argument (const std::string& argument);
-
- const std::string&
- argument () const;
-
- virtual void
- print (::std::ostream&) const;
-
- virtual const char*
- what () const throw ();
-
- private:
- std::string argument_;
- };
-
- class missing_value: public exception
- {
- public:
- virtual
- ~missing_value () throw ();
-
- missing_value (const std::string& option);
-
- const std::string&
- option () const;
-
- virtual void
- print (::std::ostream&) const;
-
- virtual const char*
- what () const throw ();
-
- private:
- std::string option_;
- };
-
- class invalid_value: public exception
- {
- public:
- virtual
- ~invalid_value () throw ();
-
- invalid_value (const std::string& option,
- const std::string& value,
- const std::string& message = std::string ());
-
- const std::string&
- option () const;
-
- const std::string&
- value () const;
-
- const std::string&
- message () const;
-
- virtual void
- print (::std::ostream&) const;
-
- virtual const char*
- what () const throw ();
-
- private:
- std::string option_;
- std::string value_;
- std::string message_;
- };
-
- class eos_reached: public exception
- {
- public:
- virtual void
- print (::std::ostream&) const;
-
- virtual const char*
- what () const throw ();
- };
-
- class file_io_failure: public exception
- {
- public:
- virtual
- ~file_io_failure () throw ();
-
- file_io_failure (const std::string& file);
-
- const std::string&
- file () const;
-
- virtual void
- print (::std::ostream&) const;
-
- virtual const char*
- what () const throw ();
-
- private:
- std::string file_;
- };
-
- class unmatched_quote: public exception
- {
- public:
- virtual
- ~unmatched_quote () throw ();
-
- unmatched_quote (const std::string& argument);
-
- const std::string&
- argument () const;
-
- virtual void
- print (::std::ostream&) const;
-
- virtual const char*
- what () const throw ();
-
- private:
- std::string argument_;
- };
-
- // Command line argument scanner interface.
- //
- // The values returned by next() are guaranteed to be valid
- // for the two previous arguments up until a call to a third
- // peek() or next().
- //
- // The position() function returns a monotonically-increasing
- // number which, if stored, can later be used to determine the
- // relative position of the argument returned by the following
- // call to next(). Note that if multiple scanners are used to
- // extract arguments from multiple sources, then the end
- // position of the previous scanner should be used as the
- // start position of the next.
- //
- class scanner
- {
- public:
- virtual
- ~scanner ();
-
- virtual bool
- more () = 0;
-
- virtual const char*
- peek () = 0;
-
- virtual const char*
- next () = 0;
-
- virtual void
- skip () = 0;
-
- virtual std::size_t
- position () = 0;
- };
-
- class argv_scanner: public scanner
- {
- public:
- argv_scanner (int& argc,
- char** argv,
- bool erase = false,
- std::size_t start_position = 0);
-
- argv_scanner (int start,
- int& argc,
- char** argv,
- bool erase = false,
- std::size_t start_position = 0);
-
- int
- end () const;
-
- virtual bool
- more ();
-
- virtual const char*
- peek ();
-
- virtual const char*
- next ();
-
- virtual void
- skip ();
-
- virtual std::size_t
- position ();
-
- protected:
- std::size_t start_position_;
- int i_;
- int& argc_;
- char** argv_;
- bool erase_;
- };
-
- class argv_file_scanner: public argv_scanner
- {
- public:
- argv_file_scanner (int& argc,
- char** argv,
- const std::string& option,
- bool erase = false,
- std::size_t start_position = 0);
-
- argv_file_scanner (int start,
- int& argc,
- char** argv,
- const std::string& option,
- bool erase = false,
- std::size_t start_position = 0);
-
- argv_file_scanner (const std::string& file,
- const std::string& option,
- std::size_t start_position = 0);
-
- struct option_info
- {
- // If search_func is not NULL, it is called, with the arg
- // value as the second argument, to locate the options file.
- // If it returns an empty string, then the file is ignored.
- //
- const char* option;
- std::string (*search_func) (const char*, void* arg);
- void* arg;
- };
-
- argv_file_scanner (int& argc,
- char** argv,
- const option_info* options,
- std::size_t options_count,
- bool erase = false,
- std::size_t start_position = 0);
-
- argv_file_scanner (int start,
- int& argc,
- char** argv,
- const option_info* options,
- std::size_t options_count,
- bool erase = false,
- std::size_t start_position = 0);
-
- argv_file_scanner (const std::string& file,
- const option_info* options = 0,
- std::size_t options_count = 0,
- std::size_t start_position = 0);
-
- virtual bool
- more ();
-
- virtual const char*
- peek ();
-
- virtual const char*
- next ();
-
- virtual void
- skip ();
-
- virtual std::size_t
- position ();
-
- // Return the file path if the peeked at argument came from a file and
- // the empty string otherwise. The reference is guaranteed to be valid
- // till the end of the scanner lifetime.
- //
- const std::string&
- peek_file ();
-
- // Return the 1-based line number if the peeked at argument came from
- // a file and zero otherwise.
- //
- std::size_t
- peek_line ();
-
- private:
- const option_info*
- find (const char*) const;
-
- void
- load (const std::string& file);
-
- typedef argv_scanner base;
-
- const std::string option_;
- option_info option_info_;
- const option_info* options_;
- std::size_t options_count_;
-
- struct arg
- {
- std::string value;
- const std::string* file;
- std::size_t line;
- };
-
- std::deque<arg> args_;
- std::list<std::string> files_;
-
- // Circular buffer of two arguments.
- //
- std::string hold_[2];
- std::size_t i_;
-
- bool skip_;
-
- static int zero_argc_;
- static std::string empty_string_;
- };
-
- template <typename X>
- struct parser;
- }
-}
-
-#include <set>
-
-#include <libbuild2/types.hxx>
-
-namespace build2
-{
- class options
- {
- public:
- options ();
-
- // Return true if anything has been parsed.
- //
- bool
- parse (int& argc,
- char** argv,
- bool erase = false,
- ::build2::cl::unknown_mode option = ::build2::cl::unknown_mode::fail,
- ::build2::cl::unknown_mode argument = ::build2::cl::unknown_mode::stop);
-
- bool
- parse (int start,
- int& argc,
- char** argv,
- bool erase = false,
- ::build2::cl::unknown_mode option = ::build2::cl::unknown_mode::fail,
- ::build2::cl::unknown_mode argument = ::build2::cl::unknown_mode::stop);
-
- bool
- parse (int& argc,
- char** argv,
- int& end,
- bool erase = false,
- ::build2::cl::unknown_mode option = ::build2::cl::unknown_mode::fail,
- ::build2::cl::unknown_mode argument = ::build2::cl::unknown_mode::stop);
-
- bool
- parse (int start,
- int& argc,
- char** argv,
- int& end,
- bool erase = false,
- ::build2::cl::unknown_mode option = ::build2::cl::unknown_mode::fail,
- ::build2::cl::unknown_mode argument = ::build2::cl::unknown_mode::stop);
-
- bool
- parse (::build2::cl::scanner&,
- ::build2::cl::unknown_mode option = ::build2::cl::unknown_mode::fail,
- ::build2::cl::unknown_mode argument = ::build2::cl::unknown_mode::stop);
-
- // Merge options from the specified instance appending/overriding
- // them as if they appeared after options in this instance.
- //
- void
- merge (const options&);
-
- // Option accessors.
- //
- const uint64_t&
- build2_metadata () const;
-
- bool
- build2_metadata_specified () const;
-
- const bool&
- v () const;
-
- const bool&
- V () const;
-
- const bool&
- quiet () const;
-
- const bool&
- silent () const;
-
- const uint16_t&
- verbose () const;
-
- bool
- verbose_specified () const;
-
- const bool&
- stat () const;
-
- const std::set<string>&
- dump () const;
-
- bool
- dump_specified () const;
-
- const bool&
- progress () const;
-
- const bool&
- no_progress () const;
-
- const size_t&
- jobs () const;
-
- bool
- jobs_specified () const;
-
- const size_t&
- max_jobs () const;
-
- bool
- max_jobs_specified () const;
-
- const size_t&
- queue_depth () const;
-
- bool
- queue_depth_specified () const;
-
- const string&
- file_cache () const;
-
- bool
- file_cache_specified () const;
-
- const size_t&
- max_stack () const;
-
- bool
- max_stack_specified () const;
-
- const bool&
- serial_stop () const;
-
- const bool&
- dry_run () const;
-
- const bool&
- match_only () const;
-
- const bool&
- no_external_modules () const;
-
- const bool&
- structured_result () const;
-
- const bool&
- mtime_check () const;
-
- const bool&
- no_mtime_check () const;
-
- const bool&
- no_column () const;
-
- const bool&
- no_line () const;
-
- const path&
- buildfile () const;
-
- bool
- buildfile_specified () const;
-
- const path&
- config_guess () const;
-
- bool
- config_guess_specified () const;
-
- const path&
- config_sub () const;
-
- bool
- config_sub_specified () const;
-
- const string&
- pager () const;
-
- bool
- pager_specified () const;
-
- const strings&
- pager_option () const;
-
- bool
- pager_option_specified () const;
-
- const string&
- options_file () const;
-
- bool
- options_file_specified () const;
-
- const dir_path&
- default_options () const;
-
- bool
- default_options_specified () const;
-
- const bool&
- no_default_options () const;
-
- const bool&
- help () const;
-
- const bool&
- version () const;
-
- // Print usage information.
- //
- static ::build2::cl::usage_para
- print_usage (::std::ostream&,
- ::build2::cl::usage_para = ::build2::cl::usage_para::none);
-
- // Implementation details.
- //
- protected:
- bool
- _parse (const char*, ::build2::cl::scanner&);
-
- private:
- bool
- _parse (::build2::cl::scanner&,
- ::build2::cl::unknown_mode option,
- ::build2::cl::unknown_mode argument);
-
- public:
- uint64_t build2_metadata_;
- bool build2_metadata_specified_;
- bool v_;
- bool V_;
- bool quiet_;
- bool silent_;
- uint16_t verbose_;
- bool verbose_specified_;
- bool stat_;
- std::set<string> dump_;
- bool dump_specified_;
- bool progress_;
- bool no_progress_;
- size_t jobs_;
- bool jobs_specified_;
- size_t max_jobs_;
- bool max_jobs_specified_;
- size_t queue_depth_;
- bool queue_depth_specified_;
- string file_cache_;
- bool file_cache_specified_;
- size_t max_stack_;
- bool max_stack_specified_;
- bool serial_stop_;
- bool dry_run_;
- bool match_only_;
- bool no_external_modules_;
- bool structured_result_;
- bool mtime_check_;
- bool no_mtime_check_;
- bool no_column_;
- bool no_line_;
- path buildfile_;
- bool buildfile_specified_;
- path config_guess_;
- bool config_guess_specified_;
- path config_sub_;
- bool config_sub_specified_;
- string pager_;
- bool pager_specified_;
- strings pager_option_;
- bool pager_option_specified_;
- string options_file_;
- bool options_file_specified_;
- dir_path default_options_;
- bool default_options_specified_;
- bool no_default_options_;
- bool help_;
- bool version_;
- };
-}
-
-// Print page usage information.
-//
-namespace build2
-{
- ::build2::cl::usage_para
- print_b_usage (::std::ostream&,
- ::build2::cl::usage_para = ::build2::cl::usage_para::none);
-}
-
-#include <build2/b-options.ixx>
-
-// Begin epilogue.
-//
-//
-// End epilogue.
-
-#endif // BUILD2_B_OPTIONS_HXX
diff --git a/build2/b-options.ixx b/build2/b-options.ixx
deleted file mode 100644
index 104d4da..0000000
--- a/build2/b-options.ixx
+++ /dev/null
@@ -1,582 +0,0 @@
-// -*- C++ -*-
-//
-// This file was generated by CLI, a command line interface
-// compiler for C++.
-//
-
-// Begin prologue.
-//
-//
-// End prologue.
-
-#include <cassert>
-
-namespace build2
-{
- namespace cl
- {
- // usage_para
- //
- inline usage_para::
- usage_para (value v)
- : v_ (v)
- {
- }
-
- // unknown_mode
- //
- inline unknown_mode::
- unknown_mode (value v)
- : v_ (v)
- {
- }
-
- // exception
- //
- inline ::std::ostream&
- operator<< (::std::ostream& os, const exception& e)
- {
- e.print (os);
- return os;
- }
-
- // unknown_option
- //
- inline unknown_option::
- unknown_option (const std::string& option)
- : option_ (option)
- {
- }
-
- inline const std::string& unknown_option::
- option () const
- {
- return option_;
- }
-
- // unknown_argument
- //
- inline unknown_argument::
- unknown_argument (const std::string& argument)
- : argument_ (argument)
- {
- }
-
- inline const std::string& unknown_argument::
- argument () const
- {
- return argument_;
- }
-
- // missing_value
- //
- inline missing_value::
- missing_value (const std::string& option)
- : option_ (option)
- {
- }
-
- inline const std::string& missing_value::
- option () const
- {
- return option_;
- }
-
- // invalid_value
- //
- inline invalid_value::
- invalid_value (const std::string& option,
- const std::string& value,
- const std::string& message)
- : option_ (option),
- value_ (value),
- message_ (message)
- {
- }
-
- inline const std::string& invalid_value::
- option () const
- {
- return option_;
- }
-
- inline const std::string& invalid_value::
- value () const
- {
- return value_;
- }
-
- inline const std::string& invalid_value::
- message () const
- {
- return message_;
- }
-
- // file_io_failure
- //
- inline file_io_failure::
- file_io_failure (const std::string& file)
- : file_ (file)
- {
- }
-
- inline const std::string& file_io_failure::
- file () const
- {
- return file_;
- }
-
- // unmatched_quote
- //
- inline unmatched_quote::
- unmatched_quote (const std::string& argument)
- : argument_ (argument)
- {
- }
-
- inline const std::string& unmatched_quote::
- argument () const
- {
- return argument_;
- }
-
- // argv_scanner
- //
- inline argv_scanner::
- argv_scanner (int& argc,
- char** argv,
- bool erase,
- std::size_t sp)
- : start_position_ (sp + 1),
- i_ (1),
- argc_ (argc),
- argv_ (argv),
- erase_ (erase)
- {
- }
-
- inline argv_scanner::
- argv_scanner (int start,
- int& argc,
- char** argv,
- bool erase,
- std::size_t sp)
- : start_position_ (sp + static_cast<std::size_t> (start)),
- i_ (start),
- argc_ (argc),
- argv_ (argv),
- erase_ (erase)
- {
- }
-
- inline int argv_scanner::
- end () const
- {
- return i_;
- }
-
- // argv_file_scanner
- //
- inline argv_file_scanner::
- argv_file_scanner (int& argc,
- char** argv,
- const std::string& option,
- bool erase,
- std::size_t sp)
- : argv_scanner (argc, argv, erase, sp),
- option_ (option),
- options_ (&option_info_),
- options_count_ (1),
- i_ (1),
- skip_ (false)
- {
- option_info_.option = option_.c_str ();
- option_info_.search_func = 0;
- }
-
- inline argv_file_scanner::
- argv_file_scanner (int start,
- int& argc,
- char** argv,
- const std::string& option,
- bool erase,
- std::size_t sp)
- : argv_scanner (start, argc, argv, erase, sp),
- option_ (option),
- options_ (&option_info_),
- options_count_ (1),
- i_ (1),
- skip_ (false)
- {
- option_info_.option = option_.c_str ();
- option_info_.search_func = 0;
- }
-
- inline argv_file_scanner::
- argv_file_scanner (const std::string& file,
- const std::string& option,
- std::size_t sp)
- : argv_scanner (0, zero_argc_, 0, sp),
- option_ (option),
- options_ (&option_info_),
- options_count_ (1),
- i_ (1),
- skip_ (false)
- {
- option_info_.option = option_.c_str ();
- option_info_.search_func = 0;
-
- load (file);
- }
-
- inline argv_file_scanner::
- argv_file_scanner (int& argc,
- char** argv,
- const option_info* options,
- std::size_t options_count,
- bool erase,
- std::size_t sp)
- : argv_scanner (argc, argv, erase, sp),
- options_ (options),
- options_count_ (options_count),
- i_ (1),
- skip_ (false)
- {
- }
-
- inline argv_file_scanner::
- argv_file_scanner (int start,
- int& argc,
- char** argv,
- const option_info* options,
- std::size_t options_count,
- bool erase,
- std::size_t sp)
- : argv_scanner (start, argc, argv, erase, sp),
- options_ (options),
- options_count_ (options_count),
- i_ (1),
- skip_ (false)
- {
- }
-
- inline argv_file_scanner::
- argv_file_scanner (const std::string& file,
- const option_info* options,
- std::size_t options_count,
- std::size_t sp)
- : argv_scanner (0, zero_argc_, 0, sp),
- options_ (options),
- options_count_ (options_count),
- i_ (1),
- skip_ (false)
- {
- load (file);
- }
- }
-}
-
-namespace build2
-{
- // options
- //
-
- inline const uint64_t& options::
- build2_metadata () const
- {
- return this->build2_metadata_;
- }
-
- inline bool options::
- build2_metadata_specified () const
- {
- return this->build2_metadata_specified_;
- }
-
- inline const bool& options::
- v () const
- {
- return this->v_;
- }
-
- inline const bool& options::
- V () const
- {
- return this->V_;
- }
-
- inline const bool& options::
- quiet () const
- {
- return this->quiet_;
- }
-
- inline const bool& options::
- silent () const
- {
- return this->silent_;
- }
-
- inline const uint16_t& options::
- verbose () const
- {
- return this->verbose_;
- }
-
- inline bool options::
- verbose_specified () const
- {
- return this->verbose_specified_;
- }
-
- inline const bool& options::
- stat () const
- {
- return this->stat_;
- }
-
- inline const std::set<string>& options::
- dump () const
- {
- return this->dump_;
- }
-
- inline bool options::
- dump_specified () const
- {
- return this->dump_specified_;
- }
-
- inline const bool& options::
- progress () const
- {
- return this->progress_;
- }
-
- inline const bool& options::
- no_progress () const
- {
- return this->no_progress_;
- }
-
- inline const size_t& options::
- jobs () const
- {
- return this->jobs_;
- }
-
- inline bool options::
- jobs_specified () const
- {
- return this->jobs_specified_;
- }
-
- inline const size_t& options::
- max_jobs () const
- {
- return this->max_jobs_;
- }
-
- inline bool options::
- max_jobs_specified () const
- {
- return this->max_jobs_specified_;
- }
-
- inline const size_t& options::
- queue_depth () const
- {
- return this->queue_depth_;
- }
-
- inline bool options::
- queue_depth_specified () const
- {
- return this->queue_depth_specified_;
- }
-
- inline const string& options::
- file_cache () const
- {
- return this->file_cache_;
- }
-
- inline bool options::
- file_cache_specified () const
- {
- return this->file_cache_specified_;
- }
-
- inline const size_t& options::
- max_stack () const
- {
- return this->max_stack_;
- }
-
- inline bool options::
- max_stack_specified () const
- {
- return this->max_stack_specified_;
- }
-
- inline const bool& options::
- serial_stop () const
- {
- return this->serial_stop_;
- }
-
- inline const bool& options::
- dry_run () const
- {
- return this->dry_run_;
- }
-
- inline const bool& options::
- match_only () const
- {
- return this->match_only_;
- }
-
- inline const bool& options::
- no_external_modules () const
- {
- return this->no_external_modules_;
- }
-
- inline const bool& options::
- structured_result () const
- {
- return this->structured_result_;
- }
-
- inline const bool& options::
- mtime_check () const
- {
- return this->mtime_check_;
- }
-
- inline const bool& options::
- no_mtime_check () const
- {
- return this->no_mtime_check_;
- }
-
- inline const bool& options::
- no_column () const
- {
- return this->no_column_;
- }
-
- inline const bool& options::
- no_line () const
- {
- return this->no_line_;
- }
-
- inline const path& options::
- buildfile () const
- {
- return this->buildfile_;
- }
-
- inline bool options::
- buildfile_specified () const
- {
- return this->buildfile_specified_;
- }
-
- inline const path& options::
- config_guess () const
- {
- return this->config_guess_;
- }
-
- inline bool options::
- config_guess_specified () const
- {
- return this->config_guess_specified_;
- }
-
- inline const path& options::
- config_sub () const
- {
- return this->config_sub_;
- }
-
- inline bool options::
- config_sub_specified () const
- {
- return this->config_sub_specified_;
- }
-
- inline const string& options::
- pager () const
- {
- return this->pager_;
- }
-
- inline bool options::
- pager_specified () const
- {
- return this->pager_specified_;
- }
-
- inline const strings& options::
- pager_option () const
- {
- return this->pager_option_;
- }
-
- inline bool options::
- pager_option_specified () const
- {
- return this->pager_option_specified_;
- }
-
- inline const string& options::
- options_file () const
- {
- return this->options_file_;
- }
-
- inline bool options::
- options_file_specified () const
- {
- return this->options_file_specified_;
- }
-
- inline const dir_path& options::
- default_options () const
- {
- return this->default_options_;
- }
-
- inline bool options::
- default_options_specified () const
- {
- return this->default_options_specified_;
- }
-
- inline const bool& options::
- no_default_options () const
- {
- return this->no_default_options_;
- }
-
- inline const bool& options::
- help () const
- {
- return this->help_;
- }
-
- inline const bool& options::
- version () const
- {
- return this->version_;
- }
-}
-
-// Begin epilogue.
-//
-//
-// End epilogue.
diff --git a/build2/b.cxx b/build2/b.cxx
index 03ded28..95be718 100644
--- a/build2/b.cxx
+++ b/build2/b.cxx
@@ -11,17 +11,14 @@
# include <locale>
#endif
-#include <limits>
#include <sstream>
-#include <cstring> // strcmp(), strchr()
#include <typeinfo>
#include <iostream> // cout
#include <exception> // terminate(), set_terminate(), terminate_handler
#include <libbutl/pager.hxx>
-#include <libbutl/fdstream.hxx> // stderr_fd(), fdterm()
-#include <libbutl/backtrace.hxx> // backtrace()
-#include <libbutl/default-options.hxx>
+#include <libbutl/fdstream.hxx> // stderr_fd(), fdterm()
+#include <libbutl/backtrace.hxx> // backtrace()
#include <libbuild2/types.hxx>
#include <libbuild2/utility.hxx>
@@ -44,7 +41,8 @@
#include <libbuild2/parser.hxx>
-#include <build2/b-options.hxx>
+#include <libbuild2/cmdline.hxx>
+#include <libbuild2/b-options.hxx>
// Build system modules.
//
@@ -71,403 +69,6 @@ using namespace std;
namespace build2
{
- struct cmdline
- {
- strings cmd_vars;
- string buildspec;
- uint16_t verbosity;
- };
-
- static cmdline
- parse_cmdline (tracer& trace, int argc, char* argv[], options& ops)
- {
- // @@ cl namespace
-
- // Note that the diagnostics verbosity level can only be calculated after
- // default options are loaded and merged (see below). Thus, until then we
- // refer to the verbosity level specified on the command line.
- //
- auto verbosity = [&ops] ()
- {
- uint16_t v (
- ops.verbose_specified ()
- ? ops.verbose ()
- : ops.V () ? 3 : ops.v () ? 2 : ops.quiet () || ops.silent () ? 0 : 1);
- return v;
- };
-
- cmdline r;
-
- // We want to be able to specify options, vars, and buildspecs in any
- // order (it is really handy to just add -v at the end of the command
- // line).
- //
- try
- {
- // Command line arguments starting position.
- //
- // We want the positions of the command line arguments to be after the
- // default options files. Normally that would be achieved by passing the
- // last position of the previous scanner to the next. The problem is
- // that we parse the command line arguments first (for good reasons).
- // Also the default options files parsing machinery needs the maximum
- // number of arguments to be specified and assigns the positions below
- // this value (see load_default_options() for details). So we are going
- // to "reserve" the first half of the size_t value range for the default
- // options positions and the second half for the command line arguments
- // positions.
- //
- size_t args_pos (numeric_limits<size_t>::max () / 2);
- cl::argv_file_scanner scan (argc, argv, "--options-file", args_pos);
-
- size_t argn (0); // Argument count.
- bool shortcut (false); // True if the shortcut syntax is used.
-
- for (bool opt (true), var (true); scan.more (); )
- {
- if (opt)
- {
- // Parse the next chunk of options until we reach an argument (or
- // eos).
- //
- if (ops.parse (scan) && !scan.more ())
- break;
-
- // If we see first "--", then we are done parsing options.
- //
- if (strcmp (scan.peek (), "--") == 0)
- {
- scan.next ();
- opt = false;
- continue;
- }
-
- // Fall through.
- }
-
- const char* s (scan.next ());
-
- // See if this is a command line variable. What if someone needs to
- // pass a buildspec that contains '='? One way to support this would
- // be to quote such a buildspec (e.g., "'/tmp/foo=bar/'"). Or invent
- // another separator. Or use a second "--". Actually, let's just do
- // the second "--".
- //
- if (var)
- {
- // If we see second "--", then we are also done parsing variables.
- //
- if (strcmp (s, "--") == 0)
- {
- var = false;
- continue;
- }
-
- if (const char* p = strchr (s, '=')) // Covers =, +=, and =+.
- {
- // Diagnose the empty variable name situation. Note that we don't
- // allow "partially broken down" assignments (as in foo =bar)
- // since foo= bar would be ambigous.
- //
- if (p == s || (p == s + 1 && *s == '+'))
- fail << "missing variable name in '" << s << "'";
-
- r.cmd_vars.push_back (s);
- continue;
- }
-
- // Handle the "broken down" variable assignments (i.e., foo = bar
- // instead of foo=bar).
- //
- if (scan.more ())
- {
- const char* a (scan.peek ());
-
- if (strcmp (a, "=" ) == 0 ||
- strcmp (a, "+=") == 0 ||
- strcmp (a, "=+") == 0)
- {
- string v (s);
- v += a;
-
- scan.next ();
-
- if (scan.more ())
- v += scan.next ();
-
- r.cmd_vars.push_back (move (v));
- continue;
- }
- }
-
- // Fall through.
- }
-
- // Merge all the individual buildspec arguments into a single string.
- // We use newlines to separate arguments so that line numbers in
- // diagnostics signify argument numbers. Clever, huh?
- //
- if (argn != 0)
- r.buildspec += '\n';
-
- r.buildspec += s;
-
- // See if we are using the shortcut syntax.
- //
- if (argn == 0 && r.buildspec.back () == ':')
- {
- r.buildspec.back () = '(';
- shortcut = true;
- }
-
- argn++;
- }
-
- // Add the closing parenthesis unless there wasn't anything in between
- // in which case pop the opening one.
- //
- if (shortcut)
- {
- if (argn == 1)
- r.buildspec.pop_back ();
- else
- r.buildspec += ')';
- }
-
- // Get/set an environment variable tracing the operation.
- //
- auto get_env = [&verbosity, &trace] (const char* nm)
- {
- optional<string> r (getenv (nm));
-
- if (verbosity () >= 5)
- {
- if (r)
- trace << nm << ": '" << *r << "'";
- else
- trace << nm << ": <NULL>";
- }
-
- return r;
- };
-
- auto set_env = [&verbosity, &trace] (const char* nm, const string& vl)
- {
- try
- {
- if (verbosity () >= 5)
- trace << "setting " << nm << "='" << vl << "'";
-
- setenv (nm, vl);
- }
- catch (const system_error& e)
- {
- // The variable value can potentially be long/multi-line, so let's
- // print it last.
- //
- fail << "unable to set environment variable " << nm << ": " << e <<
- info << "value: '" << vl << "'";
- }
- };
-
- // If the BUILD2_VAR_OVR environment variable is present, then parse its
- // value as a newline-separated global variable overrides and prepend
- // them to the overrides specified on the command line.
- //
- // Note that this means global overrides may not contain a newline.
-
- // Verify that the string is a valid global override. Uses the file name
- // and the options flag for diagnostics only.
- //
- auto verify_glb_ovr = [] (const string& v, const path_name& fn, bool opt)
- {
- size_t p (v.find ('=', 1));
- if (p == string::npos || v[0] != '!')
- {
- diag_record dr (fail (fn));
- dr << "expected " << (opt ? "option or " : "") << "global "
- << "variable override instead of '" << v << "'";
-
- if (p != string::npos)
- dr << info << "prefix variable assignment with '!'";
- }
-
- if (p == 1 || (p == 2 && v[1] == '+')) // '!=' or '!+=' ?
- fail (fn) << "missing variable name in '" << v << "'";
- };
-
- optional<string> env_ovr (get_env ("BUILD2_VAR_OVR"));
- if (env_ovr)
- {
- path_name fn ("<BUILD2_VAR_OVR>");
-
- auto i (r.cmd_vars.begin ());
- for (size_t b (0), e (0); next_word (*env_ovr, b, e, '\n', '\r'); )
- {
- // Extract the override from the current line, stripping the leading
- // and trailing spaces.
- //
- string s (*env_ovr, b, e - b);
- trim (s);
-
- // Verify and save the override, unless the line is empty.
- //
- if (!s.empty ())
- {
- verify_glb_ovr (s, fn, false /* opt */);
- i = r.cmd_vars.insert (i, move (s)) + 1;
- }
- }
- }
-
- // Load the default options files, unless --no-default-options is
- // specified on the command line or the BUILD2_DEF_OPT environment
- // variable is set to a value other than 'true' or '1'.
- //
- // If loaded, prepend the default global overrides to the variables
- // specified on the command line, unless BUILD2_VAR_OVR is set in which
- // case just ignore them.
- //
- optional<string> env_def (get_env ("BUILD2_DEF_OPT"));
-
- // False if --no-default-options is specified on the command line. Note
- // that we cache the flag since it can be overridden by a default
- // options file.
- //
- bool cmd_def (!ops.no_default_options ());
-
- if (cmd_def && (!env_def || *env_def == "true" || *env_def == "1"))
- try
- {
- optional<dir_path> extra;
- if (ops.default_options_specified ())
- extra = ops.default_options ();
-
- // Load default options files.
- //
- default_options<options> def_ops (
- load_default_options<options,
- cl::argv_file_scanner,
- cl::unknown_mode> (
- nullopt /* sys_dir */,
- path::home_directory (), // The home variable is not assigned yet.
- extra,
- default_options_files {{path ("b.options")},
- nullopt /* start */},
- [&trace, &verbosity] (const path& f, bool r, bool o)
- {
- if (verbosity () >= 3)
- {
- if (o)
- trace << "treating " << f << " as "
- << (r ? "remote" : "local");
- else
- trace << "loading " << (r ? "remote " : "local ") << f;
- }
- },
- "--options-file",
- args_pos,
- 1024,
- true /* args */));
-
- // Merge the default and command line options.
- //
- ops = merge_default_options (def_ops, ops);
-
- // Merge the default and command line global overrides, unless
- // BUILD2_VAR_OVR is already set (in which case we assume this has
- // already been done).
- //
- // Note that the "broken down" variable assignments occupying a single
- // line are naturally supported.
- //
- if (!env_ovr)
- r.cmd_vars =
- merge_default_arguments (
- def_ops,
- r.cmd_vars,
- [&verify_glb_ovr] (const default_options_entry<options>& e,
- const strings&)
- {
- path_name fn (e.file);
-
- // Verify that all arguments are global overrides.
- //
- for (const string& a: e.arguments)
- verify_glb_ovr (a, fn, true /* opt */);
- });
- }
- catch (const invalid_argument& e)
- {
- fail << "unable to load default options files: " << e;
- }
- catch (const pair<path, system_error>& e)
- {
- fail << "unable to load default options files: " << e.first << ": "
- << e.second;
- }
- catch (const system_error& e)
- {
- fail << "unable to obtain home directory: " << e;
- }
-
- // Verify and save the global overrides present in cmd_vars (default,
- // from the command line, etc), if any, into the BUILD2_VAR_OVR
- // environment variable.
- //
- if (!r.cmd_vars.empty ())
- {
- string ovr;
- for (const string& v: r.cmd_vars)
- {
- if (v[0] == '!')
- {
- if (v.find_first_of ("\n\r") != string::npos)
- fail << "newline in global variable override '" << v << "'";
-
- if (!ovr.empty ())
- ovr += '\n';
-
- ovr += v;
- }
- }
-
- // Optimize for the common case.
- //
- // Note: cmd_vars may contain non-global overrides.
- //
- if (!ovr.empty () && (!env_ovr || *env_ovr != ovr))
- set_env ("BUILD2_VAR_OVR", ovr);
- }
-
- // Propagate disabling of the default options files to the potential
- // nested invocations.
- //
- if (!cmd_def && (!env_def || *env_def != "0"))
- set_env ("BUILD2_DEF_OPT", "0");
-
- // Validate options.
- //
- if (ops.progress () && ops.no_progress ())
- fail << "both --progress and --no-progress specified";
-
- if (ops.mtime_check () && ops.no_mtime_check ())
- fail << "both --mtime-check and --no-mtime-check specified";
- }
- catch (const cl::exception& e)
- {
- fail << e;
- }
-
- r.verbosity = verbosity ();
-
- if (ops.silent () && r.verbosity != 0)
- fail << "specified with -v, -V, or --verbose verbosity level "
- << r.verbosity << " is incompatible with --silent";
-
- return r;
- }
-
int
main (int argc, char* argv[]);
diff --git a/build2/buildfile b/build2/buildfile
index 0da38a8..0c21388 100644
--- a/build2/buildfile
+++ b/build2/buildfile
@@ -17,7 +17,7 @@ for m: bash bin c cc cxx in version
libs += ../libbuild2/$m/lib{build2-$m}
}
-exe{b}: {hxx ixx txx cxx}{** -b-options} {hxx ixx cxx}{b-options} $libs
+exe{b}: {hxx ixx txx cxx}{**} $libs
# Target metadata, see also --build2-metadata in b.cxx.
#
@@ -71,36 +71,3 @@ switch $cxx.target.class
: "-Wl,--stack,$stack_size")
}
}
-
-# Generated options parser.
-#
-if $cli.configured
-{
- cli.cxx{b-options}: cli{b}
-
- cli.options += --std c++11 -I $src_root --include-with-brackets \
---include-prefix build2 --guard-prefix BUILD2 \
---cxx-prologue "#include <build2/types-parsers.hxx>" \
---cli-namespace build2::cl --generate-file-scanner --keep-separator \
---generate-parse --generate-merge --generate-specifier
-
- # Usage options.
- #
- cli.options += --suppress-undocumented --long-usage --ansi-color \
---ascii-tree --page-usage 'build2::print_$name$_' --option-length 21
-
- cli.cxx{*}:
- {
- # Include the generated cli files into the distribution and don't remove
- # them when cleaning in src (so that clean results in a state identical to
- # distributed).
- #
- dist = true
- clean = ($src_root != $out_root)
-
- # We keep the generated code in the repository so copy it back to src in
- # case of a forwarded configuration.
- #
- backlink = overwrite
- }
-}
diff --git a/build2/types-parsers.cxx b/build2/types-parsers.cxx
deleted file mode 100644
index 3593143..0000000
--- a/build2/types-parsers.cxx
+++ /dev/null
@@ -1,50 +0,0 @@
-// file : build2/types-parsers.cxx -*- C++ -*-
-// license : MIT; see accompanying LICENSE file
-
-#include <build2/types-parsers.hxx>
-
-#include <build2/b-options.hxx> // build2::cl namespace
-
-namespace build2
-{
- namespace cl
- {
- template <typename T>
- static void
- parse_path (T& x, scanner& s)
- {
- const char* o (s.next ());
-
- if (!s.more ())
- throw missing_value (o);
-
- const char* v (s.next ());
-
- try
- {
- x = T (v);
-
- if (x.empty ())
- throw invalid_value (o, v);
- }
- catch (const invalid_path&)
- {
- throw invalid_value (o, v);
- }
- }
-
- void parser<path>::
- parse (path& x, bool& xs, scanner& s)
- {
- xs = true;
- parse_path (x, s);
- }
-
- void parser<dir_path>::
- parse (dir_path& x, bool& xs, scanner& s)
- {
- xs = true;
- parse_path (x, s);
- }
- }
-}
diff --git a/build2/types-parsers.hxx b/build2/types-parsers.hxx
deleted file mode 100644
index d39a096..0000000
--- a/build2/types-parsers.hxx
+++ /dev/null
@@ -1,43 +0,0 @@
-// file : build2/types-parsers.hxx -*- C++ -*-
-// license : MIT; see accompanying LICENSE file
-
-// CLI parsers, included into the generated source files.
-//
-
-#ifndef BUILD2_TYPES_PARSERS_HXX
-#define BUILD2_TYPES_PARSERS_HXX
-
-#include <libbuild2/types.hxx>
-
-namespace build2
-{
- namespace cl
- {
- class scanner;
-
- template <typename T>
- struct parser;
-
- template <>
- struct parser<path>
- {
- static void
- parse (path&, bool&, scanner&);
-
- static void
- merge (path& b, const path& a) {b = a;}
- };
-
- template <>
- struct parser<dir_path>
- {
- static void
- parse (dir_path&, bool&, scanner&);
-
- static void
- merge (dir_path& b, const dir_path& a) {b = a;}
- };
- }
-}
-
-#endif // BUILD2_TYPES_PARSERS_HXX
diff --git a/doc/cli.sh b/doc/cli.sh
index 4d9556e..011f482 100755
--- a/doc/cli.sh
+++ b/doc/cli.sh
@@ -47,7 +47,7 @@ function compile ()
--generate-html --html-suffix .xhtml \
--html-prologue-file man-prologue.xhtml \
--html-epilogue-file man-epilogue.xhtml \
-../build2/$n.cli
+../libbuild2/$n.cli
cli -I .. \
-v project="build2" \
@@ -58,7 +58,7 @@ function compile ()
--generate-man --man-suffix .1 --ascii-tree \
--man-prologue-file man-prologue.1 \
--man-epilogue-file man-epilogue.1 \
-../build2/$n.cli
+../libbuild2/$n.cli
}
o="--output-prefix b-"
diff --git a/build2/b-options.cxx b/libbuild2/b-options.cxx
index 1c59231..86f5bfe 100644
--- a/build2/b-options.cxx
+++ b/libbuild2/b-options.cxx
@@ -6,11 +6,11 @@
// Begin prologue.
//
-#include <build2/types-parsers.hxx>
+#include <libbuild2/types-parsers.hxx>
//
// End prologue.
-#include <build2/b-options.hxx>
+#include <libbuild2/b-options.hxx>
#include <map>
#include <set>
@@ -24,697 +24,700 @@
namespace build2
{
- namespace cl
+ namespace build
{
- // unknown_option
- //
- unknown_option::
- ~unknown_option () throw ()
- {
- }
-
- void unknown_option::
- print (::std::ostream& os) const
+ namespace cli
{
- os << "unknown option '" << option ().c_str () << "'";
- }
+ // unknown_option
+ //
+ unknown_option::
+ ~unknown_option () throw ()
+ {
+ }
- const char* unknown_option::
- what () const throw ()
- {
- return "unknown option";
- }
+ void unknown_option::
+ print (::std::ostream& os) const
+ {
+ os << "unknown option '" << option ().c_str () << "'";
+ }
- // unknown_argument
- //
- unknown_argument::
- ~unknown_argument () throw ()
- {
- }
+ const char* unknown_option::
+ what () const throw ()
+ {
+ return "unknown option";
+ }
- void unknown_argument::
- print (::std::ostream& os) const
- {
- os << "unknown argument '" << argument ().c_str () << "'";
- }
+ // unknown_argument
+ //
+ unknown_argument::
+ ~unknown_argument () throw ()
+ {
+ }
- const char* unknown_argument::
- what () const throw ()
- {
- return "unknown argument";
- }
+ void unknown_argument::
+ print (::std::ostream& os) const
+ {
+ os << "unknown argument '" << argument ().c_str () << "'";
+ }
- // missing_value
- //
- missing_value::
- ~missing_value () throw ()
- {
- }
+ const char* unknown_argument::
+ what () const throw ()
+ {
+ return "unknown argument";
+ }
- void missing_value::
- print (::std::ostream& os) const
- {
- os << "missing value for option '" << option ().c_str () << "'";
- }
+ // missing_value
+ //
+ missing_value::
+ ~missing_value () throw ()
+ {
+ }
- const char* missing_value::
- what () const throw ()
- {
- return "missing option value";
- }
+ void missing_value::
+ print (::std::ostream& os) const
+ {
+ os << "missing value for option '" << option ().c_str () << "'";
+ }
- // invalid_value
- //
- invalid_value::
- ~invalid_value () throw ()
- {
- }
+ const char* missing_value::
+ what () const throw ()
+ {
+ return "missing option value";
+ }
- void invalid_value::
- print (::std::ostream& os) const
- {
- os << "invalid value '" << value ().c_str () << "' for option '"
- << option ().c_str () << "'";
+ // invalid_value
+ //
+ invalid_value::
+ ~invalid_value () throw ()
+ {
+ }
- if (!message ().empty ())
- os << ": " << message ().c_str ();
- }
+ void invalid_value::
+ print (::std::ostream& os) const
+ {
+ os << "invalid value '" << value ().c_str () << "' for option '"
+ << option ().c_str () << "'";
- const char* invalid_value::
- what () const throw ()
- {
- return "invalid option value";
- }
+ if (!message ().empty ())
+ os << ": " << message ().c_str ();
+ }
- // eos_reached
- //
- void eos_reached::
- print (::std::ostream& os) const
- {
- os << what ();
- }
+ const char* invalid_value::
+ what () const throw ()
+ {
+ return "invalid option value";
+ }
- const char* eos_reached::
- what () const throw ()
- {
- return "end of argument stream reached";
- }
+ // eos_reached
+ //
+ void eos_reached::
+ print (::std::ostream& os) const
+ {
+ os << what ();
+ }
- // file_io_failure
- //
- file_io_failure::
- ~file_io_failure () throw ()
- {
- }
+ const char* eos_reached::
+ what () const throw ()
+ {
+ return "end of argument stream reached";
+ }
- void file_io_failure::
- print (::std::ostream& os) const
- {
- os << "unable to open file '" << file ().c_str () << "' or read failure";
- }
+ // file_io_failure
+ //
+ file_io_failure::
+ ~file_io_failure () throw ()
+ {
+ }
- const char* file_io_failure::
- what () const throw ()
- {
- return "unable to open file or read failure";
- }
+ void file_io_failure::
+ print (::std::ostream& os) const
+ {
+ os << "unable to open file '" << file ().c_str () << "' or read failure";
+ }
- // unmatched_quote
- //
- unmatched_quote::
- ~unmatched_quote () throw ()
- {
- }
+ const char* file_io_failure::
+ what () const throw ()
+ {
+ return "unable to open file or read failure";
+ }
- void unmatched_quote::
- print (::std::ostream& os) const
- {
- os << "unmatched quote in argument '" << argument ().c_str () << "'";
- }
+ // unmatched_quote
+ //
+ unmatched_quote::
+ ~unmatched_quote () throw ()
+ {
+ }
- const char* unmatched_quote::
- what () const throw ()
- {
- return "unmatched quote";
- }
+ void unmatched_quote::
+ print (::std::ostream& os) const
+ {
+ os << "unmatched quote in argument '" << argument ().c_str () << "'";
+ }
- // scanner
- //
- scanner::
- ~scanner ()
- {
- }
+ const char* unmatched_quote::
+ what () const throw ()
+ {
+ return "unmatched quote";
+ }
- // argv_scanner
- //
- bool argv_scanner::
- more ()
- {
- return i_ < argc_;
- }
+ // scanner
+ //
+ scanner::
+ ~scanner ()
+ {
+ }
- const char* argv_scanner::
- peek ()
- {
- if (i_ < argc_)
- return argv_[i_];
- else
- throw eos_reached ();
- }
+ // argv_scanner
+ //
+ bool argv_scanner::
+ more ()
+ {
+ return i_ < argc_;
+ }
- const char* argv_scanner::
- next ()
- {
- if (i_ < argc_)
+ const char* argv_scanner::
+ peek ()
{
- const char* r (argv_[i_]);
+ if (i_ < argc_)
+ return argv_[i_];
+ else
+ throw eos_reached ();
+ }
- if (erase_)
+ const char* argv_scanner::
+ next ()
+ {
+ if (i_ < argc_)
{
- for (int i (i_ + 1); i < argc_; ++i)
- argv_[i - 1] = argv_[i];
+ const char* r (argv_[i_]);
- --argc_;
- argv_[argc_] = 0;
+ if (erase_)
+ {
+ for (int i (i_ + 1); i < argc_; ++i)
+ argv_[i - 1] = argv_[i];
+
+ --argc_;
+ argv_[argc_] = 0;
+ }
+ else
+ ++i_;
+
+ ++start_position_;
+ return r;
}
else
- ++i_;
-
- ++start_position_;
- return r;
+ throw eos_reached ();
}
- else
- throw eos_reached ();
- }
- void argv_scanner::
- skip ()
- {
- if (i_ < argc_)
+ void argv_scanner::
+ skip ()
{
- ++i_;
- ++start_position_;
+ if (i_ < argc_)
+ {
+ ++i_;
+ ++start_position_;
+ }
+ else
+ throw eos_reached ();
}
- else
- throw eos_reached ();
- }
-
- std::size_t argv_scanner::
- position ()
- {
- return start_position_;
- }
- // argv_file_scanner
- //
- int argv_file_scanner::zero_argc_ = 0;
- std::string argv_file_scanner::empty_string_;
+ std::size_t argv_scanner::
+ position ()
+ {
+ return start_position_;
+ }
- bool argv_file_scanner::
- more ()
- {
- if (!args_.empty ())
- return true;
+ // argv_file_scanner
+ //
+ int argv_file_scanner::zero_argc_ = 0;
+ std::string argv_file_scanner::empty_string_;
- while (base::more ())
+ bool argv_file_scanner::
+ more ()
{
- // See if the next argument is the file option.
- //
- const char* a (base::peek ());
- const option_info* oi = 0;
- const char* ov = 0;
+ if (!args_.empty ())
+ return true;
- if (!skip_)
+ while (base::more ())
{
- if ((oi = find (a)) != 0)
+ // See if the next argument is the file option.
+ //
+ const char* a (base::peek ());
+ const option_info* oi = 0;
+ const char* ov = 0;
+
+ if (!skip_)
{
- base::next ();
+ if ((oi = find (a)) != 0)
+ {
+ base::next ();
- if (!base::more ())
- throw missing_value (a);
+ if (!base::more ())
+ throw missing_value (a);
- ov = base::next ();
- }
- else if (std::strncmp (a, "-", 1) == 0)
- {
- if ((ov = std::strchr (a, '=')) != 0)
+ ov = base::next ();
+ }
+ else if (std::strncmp (a, "-", 1) == 0)
{
- std::string o (a, 0, ov - a);
- if ((oi = find (o.c_str ())) != 0)
+ if ((ov = std::strchr (a, '=')) != 0)
{
- base::next ();
- ++ov;
+ std::string o (a, 0, ov - a);
+ if ((oi = find (o.c_str ())) != 0)
+ {
+ base::next ();
+ ++ov;
+ }
}
}
}
- }
- if (oi != 0)
- {
- if (oi->search_func != 0)
+ if (oi != 0)
{
- std::string f (oi->search_func (ov, oi->arg));
+ if (oi->search_func != 0)
+ {
+ std::string f (oi->search_func (ov, oi->arg));
+
+ if (!f.empty ())
+ load (f);
+ }
+ else
+ load (ov);
- if (!f.empty ())
- load (f);
+ if (!args_.empty ())
+ return true;
}
else
- load (ov);
+ {
+ if (!skip_)
+ skip_ = (std::strcmp (a, "--") == 0);
- if (!args_.empty ())
return true;
+ }
}
- else
- {
- if (!skip_)
- skip_ = (std::strcmp (a, "--") == 0);
- return true;
- }
+ return false;
}
- return false;
- }
-
- const char* argv_file_scanner::
- peek ()
- {
- if (!more ())
- throw eos_reached ();
-
- return args_.empty () ? base::peek () : args_.front ().value.c_str ();
- }
+ const char* argv_file_scanner::
+ peek ()
+ {
+ if (!more ())
+ throw eos_reached ();
- const std::string& argv_file_scanner::
- peek_file ()
- {
- if (!more ())
- throw eos_reached ();
+ return args_.empty () ? base::peek () : args_.front ().value.c_str ();
+ }
- return args_.empty () ? empty_string_ : *args_.front ().file;
- }
+ const std::string& argv_file_scanner::
+ peek_file ()
+ {
+ if (!more ())
+ throw eos_reached ();
- std::size_t argv_file_scanner::
- peek_line ()
- {
- if (!more ())
- throw eos_reached ();
+ return args_.empty () ? empty_string_ : *args_.front ().file;
+ }
- return args_.empty () ? 0 : args_.front ().line;
- }
+ std::size_t argv_file_scanner::
+ peek_line ()
+ {
+ if (!more ())
+ throw eos_reached ();
- const char* argv_file_scanner::
- next ()
- {
- if (!more ())
- throw eos_reached ();
+ return args_.empty () ? 0 : args_.front ().line;
+ }
- if (args_.empty ())
- return base::next ();
- else
+ const char* argv_file_scanner::
+ next ()
{
- hold_[i_ == 0 ? ++i_ : --i_].swap (args_.front ().value);
- args_.pop_front ();
- ++start_position_;
- return hold_[i_].c_str ();
- }
- }
+ if (!more ())
+ throw eos_reached ();
- void argv_file_scanner::
- skip ()
- {
- if (!more ())
- throw eos_reached ();
+ if (args_.empty ())
+ return base::next ();
+ else
+ {
+ hold_[i_ == 0 ? ++i_ : --i_].swap (args_.front ().value);
+ args_.pop_front ();
+ ++start_position_;
+ return hold_[i_].c_str ();
+ }
+ }
- if (args_.empty ())
- return base::skip ();
- else
+ void argv_file_scanner::
+ skip ()
{
- args_.pop_front ();
- ++start_position_;
- }
- }
+ if (!more ())
+ throw eos_reached ();
- 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];
+ if (args_.empty ())
+ return base::skip ();
+ else
+ {
+ args_.pop_front ();
+ ++start_position_;
+ }
+ }
- return 0;
- }
+ 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];
- std::size_t argv_file_scanner::
- position ()
- {
- return start_position_;
- }
+ return 0;
+ }
- void argv_file_scanner::
- load (const std::string& file)
- {
- using namespace std;
+ std::size_t argv_file_scanner::
+ position ()
+ {
+ return start_position_;
+ }
- ifstream is (file.c_str ());
+ void argv_file_scanner::
+ load (const std::string& file)
+ {
+ using namespace std;
- if (!is.is_open ())
- throw file_io_failure (file);
+ ifstream is (file.c_str ());
- files_.push_back (file);
+ if (!is.is_open ())
+ throw file_io_failure (file);
- arg a;
- a.file = &*files_.rbegin ();
+ files_.push_back (file);
- for (a.line = 1; !is.eof (); ++a.line)
- {
- string line;
- getline (is, line);
+ arg a;
+ a.file = &*files_.rbegin ();
- if (is.fail () && !is.eof ())
- throw file_io_failure (file);
+ for (a.line = 1; !is.eof (); ++a.line)
+ {
+ string line;
+ getline (is, line);
- string::size_type n (line.size ());
+ if (is.fail () && !is.eof ())
+ throw file_io_failure (file);
- // Trim the line from leading and trailing whitespaces.
- //
- if (n != 0)
- {
- const char* f (line.c_str ());
- const char* l (f + n);
+ string::size_type n (line.size ());
- const char* of (f);
- while (f < l && (*f == ' ' || *f == '\t' || *f == '\r'))
- ++f;
+ // Trim the line from leading and trailing whitespaces.
+ //
+ if (n != 0)
+ {
+ const char* f (line.c_str ());
+ const char* l (f + n);
- --l;
+ const char* of (f);
+ while (f < l && (*f == ' ' || *f == '\t' || *f == '\r'))
+ ++f;
- 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 ();
- }
+ const char* ol (l);
+ while (l > f && (*l == ' ' || *l == '\t' || *l == '\r'))
+ --l;
- // Ignore empty lines, those that start with #.
- //
- if (line.empty () || line[0] == '#')
- continue;
+ if (f != of || l != ol)
+ line = f <= l ? string (f, l - f + 1) : string ();
+ }
- string::size_type p (string::npos);
- if (line.compare (0, 1, "-") == 0)
- {
- p = line.find (' ');
+ // Ignore empty lines, those that start with #.
+ //
+ if (line.empty () || line[0] == '#')
+ continue;
- string::size_type q (line.find ('='));
- if (q != string::npos && q < p)
- p = q;
- }
+ string::size_type p (string::npos);
+ if (line.compare (0, 1, "-") == 0)
+ {
+ p = line.find (' ');
- string s1;
- if (p != string::npos)
- {
- s1.assign (line, 0, p);
+ string::size_type q (line.find ('='));
+ if (q != string::npos && q < p)
+ p = q;
+ }
- // Skip leading whitespaces in the argument.
- //
- if (line[p] == '=')
- ++p;
- else
+ string s1;
+ if (p != string::npos)
{
- n = line.size ();
- for (++p; p < n; ++p)
+ s1.assign (line, 0, p);
+
+ // Skip leading whitespaces in the argument.
+ //
+ if (line[p] == '=')
+ ++p;
+ else
{
- char c (line[p]);
- if (c != ' ' && c != '\t' && c != '\r')
- break;
+ n = line.size ();
+ for (++p; p < n; ++p)
+ {
+ char c (line[p]);
+ if (c != ' ' && c != '\t' && c != '\r')
+ break;
+ }
}
}
- }
- else if (!skip_)
- skip_ = (line == "--");
+ else if (!skip_)
+ skip_ = (line == "--");
- string s2 (line, p != string::npos ? p : 0);
+ string s2 (line, p != string::npos ? p : 0);
- // If the string (which is an option value or argument) is
- // wrapped in quotes, remove them.
- //
- n = s2.size ();
- char cf (s2[0]), cl (s2[n - 1]);
+ // If the string (which is an option value or argument) 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);
+ if (cf == '"' || cf == '\'' || cl == '"' || cl == '\'')
+ {
+ if (n == 1 || cf != cl)
+ throw unmatched_quote (s2);
- s2 = string (s2, 1, n - 2);
- }
+ s2 = string (s2, 1, n - 2);
+ }
- if (!s1.empty ())
- {
- // See if this is another file option.
- //
- const option_info* oi;
- if (!skip_ && (oi = find (s1.c_str ())))
+ if (!s1.empty ())
{
- if (s2.empty ())
- throw missing_value (oi->option);
-
- if (oi->search_func != 0)
+ // See if this is another file option.
+ //
+ const option_info* oi;
+ if (!skip_ && (oi = find (s1.c_str ())))
{
- string f (oi->search_func (s2.c_str (), oi->arg));
- if (!f.empty ())
- load (f);
- }
- else
- {
- // If the path of the file being parsed is not simple and the
- // path of the file that needs to be loaded is relative, then
- // complete the latter using the former as a base.
- //
+ if (s2.empty ())
+ throw missing_value (oi->option);
+
+ if (oi->search_func != 0)
+ {
+ string f (oi->search_func (s2.c_str (), oi->arg));
+ if (!f.empty ())
+ load (f);
+ }
+ else
+ {
+ // If the path of the file being parsed is not simple and the
+ // path of the file that needs to be loaded is relative, then
+ // complete the latter using the former as a base.
+ //
#ifndef _WIN32
- string::size_type p (file.find_last_of ('/'));
- bool c (p != string::npos && s2[0] != '/');
+ string::size_type p (file.find_last_of ('/'));
+ bool c (p != string::npos && s2[0] != '/');
#else
- string::size_type p (file.find_last_of ("/\\"));
- bool c (p != string::npos && s2[1] != ':');
+ string::size_type p (file.find_last_of ("/\\"));
+ bool c (p != string::npos && s2[1] != ':');
#endif
- if (c)
- s2.insert (0, file, 0, p + 1);
+ if (c)
+ s2.insert (0, file, 0, p + 1);
- load (s2);
+ load (s2);
+ }
+
+ continue;
}
- continue;
+ a.value = s1;
+ args_.push_back (a);
}
- a.value = s1;
+ a.value = s2;
args_.push_back (a);
}
-
- a.value = s2;
- args_.push_back (a);
}
- }
- template <typename X>
- struct parser
- {
- static void
- parse (X& x, bool& xs, scanner& s)
+ template <typename X>
+ struct parser
{
- using namespace std;
-
- const char* o (s.next ());
- if (s.more ())
+ static void
+ parse (X& x, bool& xs, scanner& s)
{
- string v (s.next ());
- istringstream is (v);
- if (!(is >> x && is.peek () == istringstream::traits_type::eof ()))
- throw invalid_value (o, v);
+ 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;
}
- else
- throw missing_value (o);
- xs = true;
- }
+ static void
+ merge (X& b, const X& a)
+ {
+ b = a;
+ }
+ };
- static void
- merge (X& b, const X& a)
+ template <>
+ struct parser<bool>
{
- b = a;
- }
- };
+ static void
+ parse (bool& x, scanner& s)
+ {
+ s.next ();
+ x = true;
+ }
- template <>
- struct parser<bool>
- {
- static void
- parse (bool& x, scanner& s)
- {
- s.next ();
- x = true;
- }
+ static void
+ merge (bool& b, const bool&)
+ {
+ b = true;
+ }
+ };
- static void
- merge (bool& b, const bool&)
+ template <>
+ struct parser<std::string>
{
- b = true;
- }
- };
+ static void
+ parse (std::string& x, bool& xs, scanner& s)
+ {
+ const char* o (s.next ());
- 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);
- if (s.more ())
- x = s.next ();
- else
- throw missing_value (o);
+ xs = true;
+ }
- xs = true;
- }
+ static void
+ merge (std::string& b, const std::string& a)
+ {
+ b = a;
+ }
+ };
- static void
- merge (std::string& b, const std::string& a)
+ template <typename X>
+ struct parser<std::pair<X, std::size_t> >
{
- b = a;
- }
- };
+ 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::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;
+ }
+ };
- static void
- merge (std::pair<X, std::size_t>& b, const std::pair<X, std::size_t>& a)
+ template <typename X>
+ struct parser<std::vector<X> >
{
- b = a;
- }
- };
+ 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::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 ());
+ }
+ };
- static void
- merge (std::vector<X>& b, const std::vector<X>& a)
+ template <typename X, typename C>
+ struct parser<std::set<X, C> >
{
- b.insert (b.end (), a.begin (), a.end ());
- }
- };
+ 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 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 ());
+ }
+ };
- static void
- merge (std::set<X, C>& b, const std::set<X, C>& a)
+ template <typename K, typename V, typename C>
+ struct parser<std::map<K, V, C> >
{
- b.insert (a.begin (), a.end ());
- }
- };
+ static void
+ parse (std::map<K, V, C>& m, bool& xs, scanner& s)
+ {
+ const char* o (s.next ());
- 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 ('=');
- 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 ()));
- 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
+ };
- 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);
+ }
- 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);
+ }
- 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);
- m[k] = v;
+ xs = true;
}
- 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;
+ }
+ };
- static void
- merge (std::map<K, V, C>& b, const std::map<K, V, C>& a)
+ template <typename X, typename T, T X::*M>
+ void
+ thunk (X& x, scanner& s)
{
- for (typename std::map<K, V, C>::const_iterator i (a.begin ());
- i != a.end ();
- ++i)
- b[i->first] = i->second;
+ parser<T>::parse (x.*M, s);
}
- };
-
- 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);
+ 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);
+ }
}
}
}
@@ -785,10 +788,10 @@ namespace build2
parse (int& argc,
char** argv,
bool erase,
- ::build2::cl::unknown_mode opt,
- ::build2::cl::unknown_mode arg)
+ ::build2::build::cli::unknown_mode opt,
+ ::build2::build::cli::unknown_mode arg)
{
- ::build2::cl::argv_scanner s (argc, argv, erase);
+ ::build2::build::cli::argv_scanner s (argc, argv, erase);
bool r = _parse (s, opt, arg);
return r;
}
@@ -798,10 +801,10 @@ namespace build2
int& argc,
char** argv,
bool erase,
- ::build2::cl::unknown_mode opt,
- ::build2::cl::unknown_mode arg)
+ ::build2::build::cli::unknown_mode opt,
+ ::build2::build::cli::unknown_mode arg)
{
- ::build2::cl::argv_scanner s (start, argc, argv, erase);
+ ::build2::build::cli::argv_scanner s (start, argc, argv, erase);
bool r = _parse (s, opt, arg);
return r;
}
@@ -811,10 +814,10 @@ namespace build2
char** argv,
int& end,
bool erase,
- ::build2::cl::unknown_mode opt,
- ::build2::cl::unknown_mode arg)
+ ::build2::build::cli::unknown_mode opt,
+ ::build2::build::cli::unknown_mode arg)
{
- ::build2::cl::argv_scanner s (argc, argv, erase);
+ ::build2::build::cli::argv_scanner s (argc, argv, erase);
bool r = _parse (s, opt, arg);
end = s.end ();
return r;
@@ -826,19 +829,19 @@ namespace build2
char** argv,
int& end,
bool erase,
- ::build2::cl::unknown_mode opt,
- ::build2::cl::unknown_mode arg)
+ ::build2::build::cli::unknown_mode opt,
+ ::build2::build::cli::unknown_mode arg)
{
- ::build2::cl::argv_scanner s (start, argc, argv, erase);
+ ::build2::build::cli::argv_scanner s (start, argc, argv, erase);
bool r = _parse (s, opt, arg);
end = s.end ();
return r;
}
bool options::
- parse (::build2::cl::scanner& s,
- ::build2::cl::unknown_mode opt,
- ::build2::cl::unknown_mode arg)
+ parse (::build2::build::cli::scanner& s,
+ ::build2::build::cli::unknown_mode opt,
+ ::build2::build::cli::unknown_mode arg)
{
bool r = _parse (s, opt, arg);
return r;
@@ -851,230 +854,230 @@ namespace build2
if (a.build2_metadata_specified_)
{
- ::build2::cl::parser< uint64_t>::merge (
+ ::build2::build::cli::parser< uint64_t>::merge (
this->build2_metadata_, a.build2_metadata_);
this->build2_metadata_specified_ = true;
}
if (a.v_)
{
- ::build2::cl::parser< bool>::merge (
+ ::build2::build::cli::parser< bool>::merge (
this->v_, a.v_);
}
if (a.V_)
{
- ::build2::cl::parser< bool>::merge (
+ ::build2::build::cli::parser< bool>::merge (
this->V_, a.V_);
}
if (a.quiet_)
{
- ::build2::cl::parser< bool>::merge (
+ ::build2::build::cli::parser< bool>::merge (
this->quiet_, a.quiet_);
}
if (a.silent_)
{
- ::build2::cl::parser< bool>::merge (
+ ::build2::build::cli::parser< bool>::merge (
this->silent_, a.silent_);
}
if (a.verbose_specified_)
{
- ::build2::cl::parser< uint16_t>::merge (
+ ::build2::build::cli::parser< uint16_t>::merge (
this->verbose_, a.verbose_);
this->verbose_specified_ = true;
}
if (a.stat_)
{
- ::build2::cl::parser< bool>::merge (
+ ::build2::build::cli::parser< bool>::merge (
this->stat_, a.stat_);
}
if (a.dump_specified_)
{
- ::build2::cl::parser< std::set<string>>::merge (
+ ::build2::build::cli::parser< std::set<string>>::merge (
this->dump_, a.dump_);
this->dump_specified_ = true;
}
if (a.progress_)
{
- ::build2::cl::parser< bool>::merge (
+ ::build2::build::cli::parser< bool>::merge (
this->progress_, a.progress_);
}
if (a.no_progress_)
{
- ::build2::cl::parser< bool>::merge (
+ ::build2::build::cli::parser< bool>::merge (
this->no_progress_, a.no_progress_);
}
if (a.jobs_specified_)
{
- ::build2::cl::parser< size_t>::merge (
+ ::build2::build::cli::parser< size_t>::merge (
this->jobs_, a.jobs_);
this->jobs_specified_ = true;
}
if (a.max_jobs_specified_)
{
- ::build2::cl::parser< size_t>::merge (
+ ::build2::build::cli::parser< size_t>::merge (
this->max_jobs_, a.max_jobs_);
this->max_jobs_specified_ = true;
}
if (a.queue_depth_specified_)
{
- ::build2::cl::parser< size_t>::merge (
+ ::build2::build::cli::parser< size_t>::merge (
this->queue_depth_, a.queue_depth_);
this->queue_depth_specified_ = true;
}
if (a.file_cache_specified_)
{
- ::build2::cl::parser< string>::merge (
+ ::build2::build::cli::parser< string>::merge (
this->file_cache_, a.file_cache_);
this->file_cache_specified_ = true;
}
if (a.max_stack_specified_)
{
- ::build2::cl::parser< size_t>::merge (
+ ::build2::build::cli::parser< size_t>::merge (
this->max_stack_, a.max_stack_);
this->max_stack_specified_ = true;
}
if (a.serial_stop_)
{
- ::build2::cl::parser< bool>::merge (
+ ::build2::build::cli::parser< bool>::merge (
this->serial_stop_, a.serial_stop_);
}
if (a.dry_run_)
{
- ::build2::cl::parser< bool>::merge (
+ ::build2::build::cli::parser< bool>::merge (
this->dry_run_, a.dry_run_);
}
if (a.match_only_)
{
- ::build2::cl::parser< bool>::merge (
+ ::build2::build::cli::parser< bool>::merge (
this->match_only_, a.match_only_);
}
if (a.no_external_modules_)
{
- ::build2::cl::parser< bool>::merge (
+ ::build2::build::cli::parser< bool>::merge (
this->no_external_modules_, a.no_external_modules_);
}
if (a.structured_result_)
{
- ::build2::cl::parser< bool>::merge (
+ ::build2::build::cli::parser< bool>::merge (
this->structured_result_, a.structured_result_);
}
if (a.mtime_check_)
{
- ::build2::cl::parser< bool>::merge (
+ ::build2::build::cli::parser< bool>::merge (
this->mtime_check_, a.mtime_check_);
}
if (a.no_mtime_check_)
{
- ::build2::cl::parser< bool>::merge (
+ ::build2::build::cli::parser< bool>::merge (
this->no_mtime_check_, a.no_mtime_check_);
}
if (a.no_column_)
{
- ::build2::cl::parser< bool>::merge (
+ ::build2::build::cli::parser< bool>::merge (
this->no_column_, a.no_column_);
}
if (a.no_line_)
{
- ::build2::cl::parser< bool>::merge (
+ ::build2::build::cli::parser< bool>::merge (
this->no_line_, a.no_line_);
}
if (a.buildfile_specified_)
{
- ::build2::cl::parser< path>::merge (
+ ::build2::build::cli::parser< path>::merge (
this->buildfile_, a.buildfile_);
this->buildfile_specified_ = true;
}
if (a.config_guess_specified_)
{
- ::build2::cl::parser< path>::merge (
+ ::build2::build::cli::parser< path>::merge (
this->config_guess_, a.config_guess_);
this->config_guess_specified_ = true;
}
if (a.config_sub_specified_)
{
- ::build2::cl::parser< path>::merge (
+ ::build2::build::cli::parser< path>::merge (
this->config_sub_, a.config_sub_);
this->config_sub_specified_ = true;
}
if (a.pager_specified_)
{
- ::build2::cl::parser< string>::merge (
+ ::build2::build::cli::parser< string>::merge (
this->pager_, a.pager_);
this->pager_specified_ = true;
}
if (a.pager_option_specified_)
{
- ::build2::cl::parser< strings>::merge (
+ ::build2::build::cli::parser< strings>::merge (
this->pager_option_, a.pager_option_);
this->pager_option_specified_ = true;
}
if (a.options_file_specified_)
{
- ::build2::cl::parser< string>::merge (
+ ::build2::build::cli::parser< string>::merge (
this->options_file_, a.options_file_);
this->options_file_specified_ = true;
}
if (a.default_options_specified_)
{
- ::build2::cl::parser< dir_path>::merge (
+ ::build2::build::cli::parser< dir_path>::merge (
this->default_options_, a.default_options_);
this->default_options_specified_ = true;
}
if (a.no_default_options_)
{
- ::build2::cl::parser< bool>::merge (
+ ::build2::build::cli::parser< bool>::merge (
this->no_default_options_, a.no_default_options_);
}
if (a.help_)
{
- ::build2::cl::parser< bool>::merge (
+ ::build2::build::cli::parser< bool>::merge (
this->help_, a.help_);
}
if (a.version_)
{
- ::build2::cl::parser< bool>::merge (
+ ::build2::build::cli::parser< bool>::merge (
this->version_, a.version_);
}
}
- ::build2::cl::usage_para options::
- print_usage (::std::ostream& os, ::build2::cl::usage_para p)
+ ::build2::build::cli::usage_para options::
+ print_usage (::std::ostream& os, ::build2::build::cli::usage_para p)
{
CLI_POTENTIALLY_UNUSED (os);
- if (p != ::build2::cl::usage_para::none)
+ if (p != ::build2::build::cli::usage_para::none)
os << ::std::endl;
os << "\033[1mOPTIONS\033[0m" << ::std::endl;
@@ -1312,13 +1315,13 @@ namespace build2
os << std::endl
<< "\033[1m--version\033[0m Print version and exit." << ::std::endl;
- p = ::build2::cl::usage_para::option;
+ p = ::build2::build::cli::usage_para::option;
return p;
}
typedef
- std::map<std::string, void (*) (options&, ::build2::cl::scanner&)>
+ std::map<std::string, void (*) (options&, ::build2::build::cli::scanner&)>
_cli_options_map;
static _cli_options_map _cli_options_map_;
@@ -1328,110 +1331,110 @@ namespace build2
_cli_options_map_init ()
{
_cli_options_map_["--build2-metadata"] =
- &::build2::cl::thunk< options, uint64_t, &options::build2_metadata_,
+ &::build2::build::cli::thunk< options, uint64_t, &options::build2_metadata_,
&options::build2_metadata_specified_ >;
_cli_options_map_["-v"] =
- &::build2::cl::thunk< options, bool, &options::v_ >;
+ &::build2::build::cli::thunk< options, bool, &options::v_ >;
_cli_options_map_["-V"] =
- &::build2::cl::thunk< options, bool, &options::V_ >;
+ &::build2::build::cli::thunk< options, bool, &options::V_ >;
_cli_options_map_["--quiet"] =
- &::build2::cl::thunk< options, bool, &options::quiet_ >;
+ &::build2::build::cli::thunk< options, bool, &options::quiet_ >;
_cli_options_map_["-q"] =
- &::build2::cl::thunk< options, bool, &options::quiet_ >;
+ &::build2::build::cli::thunk< options, bool, &options::quiet_ >;
_cli_options_map_["--silent"] =
- &::build2::cl::thunk< options, bool, &options::silent_ >;
+ &::build2::build::cli::thunk< options, bool, &options::silent_ >;
_cli_options_map_["--verbose"] =
- &::build2::cl::thunk< options, uint16_t, &options::verbose_,
+ &::build2::build::cli::thunk< options, uint16_t, &options::verbose_,
&options::verbose_specified_ >;
_cli_options_map_["--stat"] =
- &::build2::cl::thunk< options, bool, &options::stat_ >;
+ &::build2::build::cli::thunk< options, bool, &options::stat_ >;
_cli_options_map_["--dump"] =
- &::build2::cl::thunk< options, std::set<string>, &options::dump_,
+ &::build2::build::cli::thunk< options, std::set<string>, &options::dump_,
&options::dump_specified_ >;
_cli_options_map_["--progress"] =
- &::build2::cl::thunk< options, bool, &options::progress_ >;
+ &::build2::build::cli::thunk< options, bool, &options::progress_ >;
_cli_options_map_["--no-progress"] =
- &::build2::cl::thunk< options, bool, &options::no_progress_ >;
+ &::build2::build::cli::thunk< options, bool, &options::no_progress_ >;
_cli_options_map_["--jobs"] =
- &::build2::cl::thunk< options, size_t, &options::jobs_,
+ &::build2::build::cli::thunk< options, size_t, &options::jobs_,
&options::jobs_specified_ >;
_cli_options_map_["-j"] =
- &::build2::cl::thunk< options, size_t, &options::jobs_,
+ &::build2::build::cli::thunk< options, size_t, &options::jobs_,
&options::jobs_specified_ >;
_cli_options_map_["--max-jobs"] =
- &::build2::cl::thunk< options, size_t, &options::max_jobs_,
+ &::build2::build::cli::thunk< options, size_t, &options::max_jobs_,
&options::max_jobs_specified_ >;
_cli_options_map_["-J"] =
- &::build2::cl::thunk< options, size_t, &options::max_jobs_,
+ &::build2::build::cli::thunk< options, size_t, &options::max_jobs_,
&options::max_jobs_specified_ >;
_cli_options_map_["--queue-depth"] =
- &::build2::cl::thunk< options, size_t, &options::queue_depth_,
+ &::build2::build::cli::thunk< options, size_t, &options::queue_depth_,
&options::queue_depth_specified_ >;
_cli_options_map_["-Q"] =
- &::build2::cl::thunk< options, size_t, &options::queue_depth_,
+ &::build2::build::cli::thunk< options, size_t, &options::queue_depth_,
&options::queue_depth_specified_ >;
_cli_options_map_["--file-cache"] =
- &::build2::cl::thunk< options, string, &options::file_cache_,
+ &::build2::build::cli::thunk< options, string, &options::file_cache_,
&options::file_cache_specified_ >;
_cli_options_map_["--max-stack"] =
- &::build2::cl::thunk< options, size_t, &options::max_stack_,
+ &::build2::build::cli::thunk< options, size_t, &options::max_stack_,
&options::max_stack_specified_ >;
_cli_options_map_["--serial-stop"] =
- &::build2::cl::thunk< options, bool, &options::serial_stop_ >;
+ &::build2::build::cli::thunk< options, bool, &options::serial_stop_ >;
_cli_options_map_["-s"] =
- &::build2::cl::thunk< options, bool, &options::serial_stop_ >;
+ &::build2::build::cli::thunk< options, bool, &options::serial_stop_ >;
_cli_options_map_["--dry-run"] =
- &::build2::cl::thunk< options, bool, &options::dry_run_ >;
+ &::build2::build::cli::thunk< options, bool, &options::dry_run_ >;
_cli_options_map_["-n"] =
- &::build2::cl::thunk< options, bool, &options::dry_run_ >;
+ &::build2::build::cli::thunk< options, bool, &options::dry_run_ >;
_cli_options_map_["--match-only"] =
- &::build2::cl::thunk< options, bool, &options::match_only_ >;
+ &::build2::build::cli::thunk< options, bool, &options::match_only_ >;
_cli_options_map_["--no-external-modules"] =
- &::build2::cl::thunk< options, bool, &options::no_external_modules_ >;
+ &::build2::build::cli::thunk< options, bool, &options::no_external_modules_ >;
_cli_options_map_["--structured-result"] =
- &::build2::cl::thunk< options, bool, &options::structured_result_ >;
+ &::build2::build::cli::thunk< options, bool, &options::structured_result_ >;
_cli_options_map_["--mtime-check"] =
- &::build2::cl::thunk< options, bool, &options::mtime_check_ >;
+ &::build2::build::cli::thunk< options, bool, &options::mtime_check_ >;
_cli_options_map_["--no-mtime-check"] =
- &::build2::cl::thunk< options, bool, &options::no_mtime_check_ >;
+ &::build2::build::cli::thunk< options, bool, &options::no_mtime_check_ >;
_cli_options_map_["--no-column"] =
- &::build2::cl::thunk< options, bool, &options::no_column_ >;
+ &::build2::build::cli::thunk< options, bool, &options::no_column_ >;
_cli_options_map_["--no-line"] =
- &::build2::cl::thunk< options, bool, &options::no_line_ >;
+ &::build2::build::cli::thunk< options, bool, &options::no_line_ >;
_cli_options_map_["--buildfile"] =
- &::build2::cl::thunk< options, path, &options::buildfile_,
+ &::build2::build::cli::thunk< options, path, &options::buildfile_,
&options::buildfile_specified_ >;
_cli_options_map_["--config-guess"] =
- &::build2::cl::thunk< options, path, &options::config_guess_,
+ &::build2::build::cli::thunk< options, path, &options::config_guess_,
&options::config_guess_specified_ >;
_cli_options_map_["--config-sub"] =
- &::build2::cl::thunk< options, path, &options::config_sub_,
+ &::build2::build::cli::thunk< options, path, &options::config_sub_,
&options::config_sub_specified_ >;
_cli_options_map_["--pager"] =
- &::build2::cl::thunk< options, string, &options::pager_,
+ &::build2::build::cli::thunk< options, string, &options::pager_,
&options::pager_specified_ >;
_cli_options_map_["--pager-option"] =
- &::build2::cl::thunk< options, strings, &options::pager_option_,
+ &::build2::build::cli::thunk< options, strings, &options::pager_option_,
&options::pager_option_specified_ >;
_cli_options_map_["--options-file"] =
- &::build2::cl::thunk< options, string, &options::options_file_,
+ &::build2::build::cli::thunk< options, string, &options::options_file_,
&options::options_file_specified_ >;
_cli_options_map_["--default-options"] =
- &::build2::cl::thunk< options, dir_path, &options::default_options_,
+ &::build2::build::cli::thunk< options, dir_path, &options::default_options_,
&options::default_options_specified_ >;
_cli_options_map_["--no-default-options"] =
- &::build2::cl::thunk< options, bool, &options::no_default_options_ >;
+ &::build2::build::cli::thunk< options, bool, &options::no_default_options_ >;
_cli_options_map_["--help"] =
- &::build2::cl::thunk< options, bool, &options::help_ >;
+ &::build2::build::cli::thunk< options, bool, &options::help_ >;
_cli_options_map_["--version"] =
- &::build2::cl::thunk< options, bool, &options::version_ >;
+ &::build2::build::cli::thunk< options, bool, &options::version_ >;
}
};
static _cli_options_map_init _cli_options_map_init_;
bool options::
- _parse (const char* o, ::build2::cl::scanner& s)
+ _parse (const char* o, ::build2::build::cli::scanner& s)
{
_cli_options_map::const_iterator i (_cli_options_map_.find (o));
@@ -1445,13 +1448,13 @@ namespace build2
}
bool options::
- _parse (::build2::cl::scanner& s,
- ::build2::cl::unknown_mode opt_mode,
- ::build2::cl::unknown_mode arg_mode)
+ _parse (::build2::build::cli::scanner& s,
+ ::build2::build::cli::unknown_mode opt_mode,
+ ::build2::build::cli::unknown_mode arg_mode)
{
// Can't skip combined flags (--no-combined-flags).
//
- assert (opt_mode != ::build2::cl::unknown_mode::skip);
+ assert (opt_mode != ::build2::build::cli::unknown_mode::skip);
bool r = false;
bool opt = true;
@@ -1490,14 +1493,14 @@ namespace build2
const_cast<char*> (v)
};
- ::build2::cl::argv_scanner ns (0, ac, av);
+ ::build2::build::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 ::build2::cl::invalid_value (co, v);
+ throw ::build2::build::cli::invalid_value (co, v);
s.next ();
r = true;
@@ -1538,7 +1541,7 @@ namespace build2
cf
};
- ::build2::cl::argv_scanner ns (0, ac, av);
+ ::build2::build::cli::argv_scanner ns (0, ac, av);
if (!_parse (cf, ns))
break;
@@ -1563,19 +1566,19 @@ namespace build2
switch (opt_mode)
{
- case ::build2::cl::unknown_mode::skip:
+ case ::build2::build::cli::unknown_mode::skip:
{
s.skip ();
r = true;
continue;
}
- case ::build2::cl::unknown_mode::stop:
+ case ::build2::build::cli::unknown_mode::stop:
{
break;
}
- case ::build2::cl::unknown_mode::fail:
+ case ::build2::build::cli::unknown_mode::fail:
{
- throw ::build2::cl::unknown_option (o);
+ throw ::build2::build::cli::unknown_option (o);
}
}
@@ -1585,19 +1588,19 @@ namespace build2
switch (arg_mode)
{
- case ::build2::cl::unknown_mode::skip:
+ case ::build2::build::cli::unknown_mode::skip:
{
s.skip ();
r = true;
continue;
}
- case ::build2::cl::unknown_mode::stop:
+ case ::build2::build::cli::unknown_mode::stop:
{
break;
}
- case ::build2::cl::unknown_mode::fail:
+ case ::build2::build::cli::unknown_mode::fail:
{
- throw ::build2::cl::unknown_argument (o);
+ throw ::build2::build::cli::unknown_argument (o);
}
}
@@ -1610,12 +1613,12 @@ namespace build2
namespace build2
{
- ::build2::cl::usage_para
- print_b_usage (::std::ostream& os, ::build2::cl::usage_para p)
+ ::build2::build::cli::usage_para
+ print_b_usage (::std::ostream& os, ::build2::build::cli::usage_para p)
{
CLI_POTENTIALLY_UNUSED (os);
- if (p != ::build2::cl::usage_para::none)
+ if (p != ::build2::build::cli::usage_para::none)
os << ::std::endl;
os << "\033[1mSYNOPSIS\033[0m" << ::std::endl
@@ -1638,9 +1641,9 @@ namespace build2
<< "\033[1m'--'\033[0m separator. To avoid treating an argument that contains \033[1m'='\033[0m as a variable," << ::std::endl
<< "add the second \033[1m'--'\033[0m separator." << ::std::endl;
- p = ::build2::options::print_usage (os, ::build2::cl::usage_para::text);
+ p = ::build2::options::print_usage (os, ::build2::build::cli::usage_para::text);
- if (p != ::build2::cl::usage_para::none)
+ if (p != ::build2::build::cli::usage_para::none)
os << ::std::endl;
os << "\033[1mDEFAULT OPTIONS FILES\033[0m" << ::std::endl
@@ -1694,7 +1697,7 @@ namespace build2
<< "options files in nested build system driver invocations. Its values are \033[1mfalse\033[0m" << ::std::endl
<< "or \033[1m0\033[0m to suppress and \033[1mtrue\033[0m or \033[1m1\033[0m to load." << ::std::endl;
- p = ::build2::cl::usage_para::text;
+ p = ::build2::build::cli::usage_para::text;
return p;
}
diff --git a/libbuild2/b-options.hxx b/libbuild2/b-options.hxx
new file mode 100644
index 0000000..dda9f08
--- /dev/null
+++ b/libbuild2/b-options.hxx
@@ -0,0 +1,726 @@
+// -*- C++ -*-
+//
+// This file was generated by CLI, a command line interface
+// compiler for C++.
+//
+
+#ifndef LIBBUILD2_B_OPTIONS_HXX
+#define LIBBUILD2_B_OPTIONS_HXX
+
+// Begin prologue.
+//
+#include <libbuild2/export.hxx>
+//
+// End prologue.
+
+#include <list>
+#include <deque>
+#include <iosfwd>
+#include <string>
+#include <cstddef>
+#include <exception>
+
+#ifndef CLI_POTENTIALLY_UNUSED
+# if defined(_MSC_VER) || defined(__xlC__)
+# define CLI_POTENTIALLY_UNUSED(x) (void*)&x
+# else
+# define CLI_POTENTIALLY_UNUSED(x) (void)x
+# endif
+#endif
+
+namespace build2
+{
+ namespace build
+ {
+ namespace cli
+ {
+ class usage_para
+ {
+ public:
+ enum value
+ {
+ none,
+ text,
+ option
+ };
+
+ usage_para (value);
+
+ operator value () const
+ {
+ return v_;
+ }
+
+ private:
+ value v_;
+ };
+
+ class unknown_mode
+ {
+ public:
+ enum value
+ {
+ skip,
+ stop,
+ fail
+ };
+
+ unknown_mode (value);
+
+ operator value () const
+ {
+ return v_;
+ }
+
+ private:
+ value v_;
+ };
+
+ // Exceptions.
+ //
+
+ class LIBBUILD2_SYMEXPORT exception: public std::exception
+ {
+ public:
+ virtual void
+ print (::std::ostream&) const = 0;
+ };
+
+ ::std::ostream&
+ operator<< (::std::ostream&, const exception&);
+
+ class LIBBUILD2_SYMEXPORT unknown_option: public exception
+ {
+ public:
+ virtual
+ ~unknown_option () throw ();
+
+ unknown_option (const std::string& option);
+
+ const std::string&
+ option () const;
+
+ virtual void
+ print (::std::ostream&) const;
+
+ virtual const char*
+ what () const throw ();
+
+ private:
+ std::string option_;
+ };
+
+ class LIBBUILD2_SYMEXPORT unknown_argument: public exception
+ {
+ public:
+ virtual
+ ~unknown_argument () throw ();
+
+ unknown_argument (const std::string& argument);
+
+ const std::string&
+ argument () const;
+
+ virtual void
+ print (::std::ostream&) const;
+
+ virtual const char*
+ what () const throw ();
+
+ private:
+ std::string argument_;
+ };
+
+ class LIBBUILD2_SYMEXPORT missing_value: public exception
+ {
+ public:
+ virtual
+ ~missing_value () throw ();
+
+ missing_value (const std::string& option);
+
+ const std::string&
+ option () const;
+
+ virtual void
+ print (::std::ostream&) const;
+
+ virtual const char*
+ what () const throw ();
+
+ private:
+ std::string option_;
+ };
+
+ class LIBBUILD2_SYMEXPORT invalid_value: public exception
+ {
+ public:
+ virtual
+ ~invalid_value () throw ();
+
+ invalid_value (const std::string& option,
+ const std::string& value,
+ const std::string& message = std::string ());
+
+ const std::string&
+ option () const;
+
+ const std::string&
+ value () const;
+
+ const std::string&
+ message () const;
+
+ virtual void
+ print (::std::ostream&) const;
+
+ virtual const char*
+ what () const throw ();
+
+ private:
+ std::string option_;
+ std::string value_;
+ std::string message_;
+ };
+
+ class LIBBUILD2_SYMEXPORT eos_reached: public exception
+ {
+ public:
+ virtual void
+ print (::std::ostream&) const;
+
+ virtual const char*
+ what () const throw ();
+ };
+
+ class LIBBUILD2_SYMEXPORT file_io_failure: public exception
+ {
+ public:
+ virtual
+ ~file_io_failure () throw ();
+
+ file_io_failure (const std::string& file);
+
+ const std::string&
+ file () const;
+
+ virtual void
+ print (::std::ostream&) const;
+
+ virtual const char*
+ what () const throw ();
+
+ private:
+ std::string file_;
+ };
+
+ class LIBBUILD2_SYMEXPORT unmatched_quote: public exception
+ {
+ public:
+ virtual
+ ~unmatched_quote () throw ();
+
+ unmatched_quote (const std::string& argument);
+
+ const std::string&
+ argument () const;
+
+ virtual void
+ print (::std::ostream&) const;
+
+ virtual const char*
+ what () const throw ();
+
+ private:
+ std::string argument_;
+ };
+
+ // Command line argument scanner interface.
+ //
+ // The values returned by next() are guaranteed to be valid
+ // for the two previous arguments up until a call to a third
+ // peek() or next().
+ //
+ // The position() function returns a monotonically-increasing
+ // number which, if stored, can later be used to determine the
+ // relative position of the argument returned by the following
+ // call to next(). Note that if multiple scanners are used to
+ // extract arguments from multiple sources, then the end
+ // position of the previous scanner should be used as the
+ // start position of the next.
+ //
+ class LIBBUILD2_SYMEXPORT scanner
+ {
+ public:
+ virtual
+ ~scanner ();
+
+ virtual bool
+ more () = 0;
+
+ virtual const char*
+ peek () = 0;
+
+ virtual const char*
+ next () = 0;
+
+ virtual void
+ skip () = 0;
+
+ virtual std::size_t
+ position () = 0;
+ };
+
+ class LIBBUILD2_SYMEXPORT argv_scanner: public scanner
+ {
+ public:
+ argv_scanner (int& argc,
+ char** argv,
+ bool erase = false,
+ std::size_t start_position = 0);
+
+ argv_scanner (int start,
+ int& argc,
+ char** argv,
+ bool erase = false,
+ std::size_t start_position = 0);
+
+ int
+ end () const;
+
+ virtual bool
+ more ();
+
+ virtual const char*
+ peek ();
+
+ virtual const char*
+ next ();
+
+ virtual void
+ skip ();
+
+ virtual std::size_t
+ position ();
+
+ protected:
+ std::size_t start_position_;
+ int i_;
+ int& argc_;
+ char** argv_;
+ bool erase_;
+ };
+
+ class LIBBUILD2_SYMEXPORT argv_file_scanner: public argv_scanner
+ {
+ public:
+ argv_file_scanner (int& argc,
+ char** argv,
+ const std::string& option,
+ bool erase = false,
+ std::size_t start_position = 0);
+
+ argv_file_scanner (int start,
+ int& argc,
+ char** argv,
+ const std::string& option,
+ bool erase = false,
+ std::size_t start_position = 0);
+
+ argv_file_scanner (const std::string& file,
+ const std::string& option,
+ std::size_t start_position = 0);
+
+ struct option_info
+ {
+ // If search_func is not NULL, it is called, with the arg
+ // value as the second argument, to locate the options file.
+ // If it returns an empty string, then the file is ignored.
+ //
+ const char* option;
+ std::string (*search_func) (const char*, void* arg);
+ void* arg;
+ };
+
+ argv_file_scanner (int& argc,
+ char** argv,
+ const option_info* options,
+ std::size_t options_count,
+ bool erase = false,
+ std::size_t start_position = 0);
+
+ argv_file_scanner (int start,
+ int& argc,
+ char** argv,
+ const option_info* options,
+ std::size_t options_count,
+ bool erase = false,
+ std::size_t start_position = 0);
+
+ argv_file_scanner (const std::string& file,
+ const option_info* options = 0,
+ std::size_t options_count = 0,
+ std::size_t start_position = 0);
+
+ virtual bool
+ more ();
+
+ virtual const char*
+ peek ();
+
+ virtual const char*
+ next ();
+
+ virtual void
+ skip ();
+
+ virtual std::size_t
+ position ();
+
+ // Return the file path if the peeked at argument came from a file and
+ // the empty string otherwise. The reference is guaranteed to be valid
+ // till the end of the scanner lifetime.
+ //
+ const std::string&
+ peek_file ();
+
+ // Return the 1-based line number if the peeked at argument came from
+ // a file and zero otherwise.
+ //
+ std::size_t
+ peek_line ();
+
+ private:
+ const option_info*
+ find (const char*) const;
+
+ void
+ load (const std::string& file);
+
+ typedef argv_scanner base;
+
+ const std::string option_;
+ option_info option_info_;
+ const option_info* options_;
+ std::size_t options_count_;
+
+ struct arg
+ {
+ std::string value;
+ const std::string* file;
+ std::size_t line;
+ };
+
+ std::deque<arg> args_;
+ std::list<std::string> files_;
+
+ // Circular buffer of two arguments.
+ //
+ std::string hold_[2];
+ std::size_t i_;
+
+ bool skip_;
+
+ static int zero_argc_;
+ static std::string empty_string_;
+ };
+
+ template <typename X>
+ struct parser;
+ }
+ }
+}
+
+#include <set>
+
+#include <libbuild2/types.hxx>
+
+namespace build2
+{
+ class LIBBUILD2_SYMEXPORT options
+ {
+ public:
+ options ();
+
+ // Return true if anything has been parsed.
+ //
+ bool
+ parse (int& argc,
+ char** argv,
+ bool erase = false,
+ ::build2::build::cli::unknown_mode option = ::build2::build::cli::unknown_mode::fail,
+ ::build2::build::cli::unknown_mode argument = ::build2::build::cli::unknown_mode::stop);
+
+ bool
+ parse (int start,
+ int& argc,
+ char** argv,
+ bool erase = false,
+ ::build2::build::cli::unknown_mode option = ::build2::build::cli::unknown_mode::fail,
+ ::build2::build::cli::unknown_mode argument = ::build2::build::cli::unknown_mode::stop);
+
+ bool
+ parse (int& argc,
+ char** argv,
+ int& end,
+ bool erase = false,
+ ::build2::build::cli::unknown_mode option = ::build2::build::cli::unknown_mode::fail,
+ ::build2::build::cli::unknown_mode argument = ::build2::build::cli::unknown_mode::stop);
+
+ bool
+ parse (int start,
+ int& argc,
+ char** argv,
+ int& end,
+ bool erase = false,
+ ::build2::build::cli::unknown_mode option = ::build2::build::cli::unknown_mode::fail,
+ ::build2::build::cli::unknown_mode argument = ::build2::build::cli::unknown_mode::stop);
+
+ bool
+ parse (::build2::build::cli::scanner&,
+ ::build2::build::cli::unknown_mode option = ::build2::build::cli::unknown_mode::fail,
+ ::build2::build::cli::unknown_mode argument = ::build2::build::cli::unknown_mode::stop);
+
+ // Merge options from the specified instance appending/overriding
+ // them as if they appeared after options in this instance.
+ //
+ void
+ merge (const options&);
+
+ // Option accessors.
+ //
+ const uint64_t&
+ build2_metadata () const;
+
+ bool
+ build2_metadata_specified () const;
+
+ const bool&
+ v () const;
+
+ const bool&
+ V () const;
+
+ const bool&
+ quiet () const;
+
+ const bool&
+ silent () const;
+
+ const uint16_t&
+ verbose () const;
+
+ bool
+ verbose_specified () const;
+
+ const bool&
+ stat () const;
+
+ const std::set<string>&
+ dump () const;
+
+ bool
+ dump_specified () const;
+
+ const bool&
+ progress () const;
+
+ const bool&
+ no_progress () const;
+
+ const size_t&
+ jobs () const;
+
+ bool
+ jobs_specified () const;
+
+ const size_t&
+ max_jobs () const;
+
+ bool
+ max_jobs_specified () const;
+
+ const size_t&
+ queue_depth () const;
+
+ bool
+ queue_depth_specified () const;
+
+ const string&
+ file_cache () const;
+
+ bool
+ file_cache_specified () const;
+
+ const size_t&
+ max_stack () const;
+
+ bool
+ max_stack_specified () const;
+
+ const bool&
+ serial_stop () const;
+
+ const bool&
+ dry_run () const;
+
+ const bool&
+ match_only () const;
+
+ const bool&
+ no_external_modules () const;
+
+ const bool&
+ structured_result () const;
+
+ const bool&
+ mtime_check () const;
+
+ const bool&
+ no_mtime_check () const;
+
+ const bool&
+ no_column () const;
+
+ const bool&
+ no_line () const;
+
+ const path&
+ buildfile () const;
+
+ bool
+ buildfile_specified () const;
+
+ const path&
+ config_guess () const;
+
+ bool
+ config_guess_specified () const;
+
+ const path&
+ config_sub () const;
+
+ bool
+ config_sub_specified () const;
+
+ const string&
+ pager () const;
+
+ bool
+ pager_specified () const;
+
+ const strings&
+ pager_option () const;
+
+ bool
+ pager_option_specified () const;
+
+ const string&
+ options_file () const;
+
+ bool
+ options_file_specified () const;
+
+ const dir_path&
+ default_options () const;
+
+ bool
+ default_options_specified () const;
+
+ const bool&
+ no_default_options () const;
+
+ const bool&
+ help () const;
+
+ const bool&
+ version () const;
+
+ // Print usage information.
+ //
+ static ::build2::build::cli::usage_para
+ print_usage (::std::ostream&,
+ ::build2::build::cli::usage_para = ::build2::build::cli::usage_para::none);
+
+ // Implementation details.
+ //
+ protected:
+ bool
+ _parse (const char*, ::build2::build::cli::scanner&);
+
+ private:
+ bool
+ _parse (::build2::build::cli::scanner&,
+ ::build2::build::cli::unknown_mode option,
+ ::build2::build::cli::unknown_mode argument);
+
+ public:
+ uint64_t build2_metadata_;
+ bool build2_metadata_specified_;
+ bool v_;
+ bool V_;
+ bool quiet_;
+ bool silent_;
+ uint16_t verbose_;
+ bool verbose_specified_;
+ bool stat_;
+ std::set<string> dump_;
+ bool dump_specified_;
+ bool progress_;
+ bool no_progress_;
+ size_t jobs_;
+ bool jobs_specified_;
+ size_t max_jobs_;
+ bool max_jobs_specified_;
+ size_t queue_depth_;
+ bool queue_depth_specified_;
+ string file_cache_;
+ bool file_cache_specified_;
+ size_t max_stack_;
+ bool max_stack_specified_;
+ bool serial_stop_;
+ bool dry_run_;
+ bool match_only_;
+ bool no_external_modules_;
+ bool structured_result_;
+ bool mtime_check_;
+ bool no_mtime_check_;
+ bool no_column_;
+ bool no_line_;
+ path buildfile_;
+ bool buildfile_specified_;
+ path config_guess_;
+ bool config_guess_specified_;
+ path config_sub_;
+ bool config_sub_specified_;
+ string pager_;
+ bool pager_specified_;
+ strings pager_option_;
+ bool pager_option_specified_;
+ string options_file_;
+ bool options_file_specified_;
+ dir_path default_options_;
+ bool default_options_specified_;
+ bool no_default_options_;
+ bool help_;
+ bool version_;
+ };
+}
+
+// Print page usage information.
+//
+namespace build2
+{
+ LIBBUILD2_SYMEXPORT ::build2::build::cli::usage_para
+ print_b_usage (::std::ostream&,
+ ::build2::build::cli::usage_para = ::build2::build::cli::usage_para::none);
+}
+
+#include <libbuild2/b-options.ixx>
+
+// Begin epilogue.
+//
+//
+// End epilogue.
+
+#endif // LIBBUILD2_B_OPTIONS_HXX
diff --git a/libbuild2/b-options.ixx b/libbuild2/b-options.ixx
new file mode 100644
index 0000000..62c8299
--- /dev/null
+++ b/libbuild2/b-options.ixx
@@ -0,0 +1,585 @@
+// -*- C++ -*-
+//
+// This file was generated by CLI, a command line interface
+// compiler for C++.
+//
+
+// Begin prologue.
+//
+//
+// End prologue.
+
+#include <cassert>
+
+namespace build2
+{
+ namespace build
+ {
+ namespace cli
+ {
+ // usage_para
+ //
+ inline usage_para::
+ usage_para (value v)
+ : v_ (v)
+ {
+ }
+
+ // unknown_mode
+ //
+ inline unknown_mode::
+ unknown_mode (value v)
+ : v_ (v)
+ {
+ }
+
+ // exception
+ //
+ inline ::std::ostream&
+ operator<< (::std::ostream& os, const exception& e)
+ {
+ e.print (os);
+ return os;
+ }
+
+ // unknown_option
+ //
+ inline unknown_option::
+ unknown_option (const std::string& option)
+ : option_ (option)
+ {
+ }
+
+ inline const std::string& unknown_option::
+ option () const
+ {
+ return option_;
+ }
+
+ // unknown_argument
+ //
+ inline unknown_argument::
+ unknown_argument (const std::string& argument)
+ : argument_ (argument)
+ {
+ }
+
+ inline const std::string& unknown_argument::
+ argument () const
+ {
+ return argument_;
+ }
+
+ // missing_value
+ //
+ inline missing_value::
+ missing_value (const std::string& option)
+ : option_ (option)
+ {
+ }
+
+ inline const std::string& missing_value::
+ option () const
+ {
+ return option_;
+ }
+
+ // invalid_value
+ //
+ inline invalid_value::
+ invalid_value (const std::string& option,
+ const std::string& value,
+ const std::string& message)
+ : option_ (option),
+ value_ (value),
+ message_ (message)
+ {
+ }
+
+ inline const std::string& invalid_value::
+ option () const
+ {
+ return option_;
+ }
+
+ inline const std::string& invalid_value::
+ value () const
+ {
+ return value_;
+ }
+
+ inline const std::string& invalid_value::
+ message () const
+ {
+ return message_;
+ }
+
+ // file_io_failure
+ //
+ inline file_io_failure::
+ file_io_failure (const std::string& file)
+ : file_ (file)
+ {
+ }
+
+ inline const std::string& file_io_failure::
+ file () const
+ {
+ return file_;
+ }
+
+ // unmatched_quote
+ //
+ inline unmatched_quote::
+ unmatched_quote (const std::string& argument)
+ : argument_ (argument)
+ {
+ }
+
+ inline const std::string& unmatched_quote::
+ argument () const
+ {
+ return argument_;
+ }
+
+ // argv_scanner
+ //
+ inline argv_scanner::
+ argv_scanner (int& argc,
+ char** argv,
+ bool erase,
+ std::size_t sp)
+ : start_position_ (sp + 1),
+ i_ (1),
+ argc_ (argc),
+ argv_ (argv),
+ erase_ (erase)
+ {
+ }
+
+ inline argv_scanner::
+ argv_scanner (int start,
+ int& argc,
+ char** argv,
+ bool erase,
+ std::size_t sp)
+ : start_position_ (sp + static_cast<std::size_t> (start)),
+ i_ (start),
+ argc_ (argc),
+ argv_ (argv),
+ erase_ (erase)
+ {
+ }
+
+ inline int argv_scanner::
+ end () const
+ {
+ return i_;
+ }
+
+ // argv_file_scanner
+ //
+ inline argv_file_scanner::
+ argv_file_scanner (int& argc,
+ char** argv,
+ const std::string& option,
+ bool erase,
+ std::size_t sp)
+ : argv_scanner (argc, argv, erase, sp),
+ option_ (option),
+ options_ (&option_info_),
+ options_count_ (1),
+ i_ (1),
+ skip_ (false)
+ {
+ option_info_.option = option_.c_str ();
+ option_info_.search_func = 0;
+ }
+
+ inline argv_file_scanner::
+ argv_file_scanner (int start,
+ int& argc,
+ char** argv,
+ const std::string& option,
+ bool erase,
+ std::size_t sp)
+ : argv_scanner (start, argc, argv, erase, sp),
+ option_ (option),
+ options_ (&option_info_),
+ options_count_ (1),
+ i_ (1),
+ skip_ (false)
+ {
+ option_info_.option = option_.c_str ();
+ option_info_.search_func = 0;
+ }
+
+ inline argv_file_scanner::
+ argv_file_scanner (const std::string& file,
+ const std::string& option,
+ std::size_t sp)
+ : argv_scanner (0, zero_argc_, 0, sp),
+ option_ (option),
+ options_ (&option_info_),
+ options_count_ (1),
+ i_ (1),
+ skip_ (false)
+ {
+ option_info_.option = option_.c_str ();
+ option_info_.search_func = 0;
+
+ load (file);
+ }
+
+ inline argv_file_scanner::
+ argv_file_scanner (int& argc,
+ char** argv,
+ const option_info* options,
+ std::size_t options_count,
+ bool erase,
+ std::size_t sp)
+ : argv_scanner (argc, argv, erase, sp),
+ options_ (options),
+ options_count_ (options_count),
+ i_ (1),
+ skip_ (false)
+ {
+ }
+
+ inline argv_file_scanner::
+ argv_file_scanner (int start,
+ int& argc,
+ char** argv,
+ const option_info* options,
+ std::size_t options_count,
+ bool erase,
+ std::size_t sp)
+ : argv_scanner (start, argc, argv, erase, sp),
+ options_ (options),
+ options_count_ (options_count),
+ i_ (1),
+ skip_ (false)
+ {
+ }
+
+ inline argv_file_scanner::
+ argv_file_scanner (const std::string& file,
+ const option_info* options,
+ std::size_t options_count,
+ std::size_t sp)
+ : argv_scanner (0, zero_argc_, 0, sp),
+ options_ (options),
+ options_count_ (options_count),
+ i_ (1),
+ skip_ (false)
+ {
+ load (file);
+ }
+ }
+ }
+}
+
+namespace build2
+{
+ // options
+ //
+
+ inline const uint64_t& options::
+ build2_metadata () const
+ {
+ return this->build2_metadata_;
+ }
+
+ inline bool options::
+ build2_metadata_specified () const
+ {
+ return this->build2_metadata_specified_;
+ }
+
+ inline const bool& options::
+ v () const
+ {
+ return this->v_;
+ }
+
+ inline const bool& options::
+ V () const
+ {
+ return this->V_;
+ }
+
+ inline const bool& options::
+ quiet () const
+ {
+ return this->quiet_;
+ }
+
+ inline const bool& options::
+ silent () const
+ {
+ return this->silent_;
+ }
+
+ inline const uint16_t& options::
+ verbose () const
+ {
+ return this->verbose_;
+ }
+
+ inline bool options::
+ verbose_specified () const
+ {
+ return this->verbose_specified_;
+ }
+
+ inline const bool& options::
+ stat () const
+ {
+ return this->stat_;
+ }
+
+ inline const std::set<string>& options::
+ dump () const
+ {
+ return this->dump_;
+ }
+
+ inline bool options::
+ dump_specified () const
+ {
+ return this->dump_specified_;
+ }
+
+ inline const bool& options::
+ progress () const
+ {
+ return this->progress_;
+ }
+
+ inline const bool& options::
+ no_progress () const
+ {
+ return this->no_progress_;
+ }
+
+ inline const size_t& options::
+ jobs () const
+ {
+ return this->jobs_;
+ }
+
+ inline bool options::
+ jobs_specified () const
+ {
+ return this->jobs_specified_;
+ }
+
+ inline const size_t& options::
+ max_jobs () const
+ {
+ return this->max_jobs_;
+ }
+
+ inline bool options::
+ max_jobs_specified () const
+ {
+ return this->max_jobs_specified_;
+ }
+
+ inline const size_t& options::
+ queue_depth () const
+ {
+ return this->queue_depth_;
+ }
+
+ inline bool options::
+ queue_depth_specified () const
+ {
+ return this->queue_depth_specified_;
+ }
+
+ inline const string& options::
+ file_cache () const
+ {
+ return this->file_cache_;
+ }
+
+ inline bool options::
+ file_cache_specified () const
+ {
+ return this->file_cache_specified_;
+ }
+
+ inline const size_t& options::
+ max_stack () const
+ {
+ return this->max_stack_;
+ }
+
+ inline bool options::
+ max_stack_specified () const
+ {
+ return this->max_stack_specified_;
+ }
+
+ inline const bool& options::
+ serial_stop () const
+ {
+ return this->serial_stop_;
+ }
+
+ inline const bool& options::
+ dry_run () const
+ {
+ return this->dry_run_;
+ }
+
+ inline const bool& options::
+ match_only () const
+ {
+ return this->match_only_;
+ }
+
+ inline const bool& options::
+ no_external_modules () const
+ {
+ return this->no_external_modules_;
+ }
+
+ inline const bool& options::
+ structured_result () const
+ {
+ return this->structured_result_;
+ }
+
+ inline const bool& options::
+ mtime_check () const
+ {
+ return this->mtime_check_;
+ }
+
+ inline const bool& options::
+ no_mtime_check () const
+ {
+ return this->no_mtime_check_;
+ }
+
+ inline const bool& options::
+ no_column () const
+ {
+ return this->no_column_;
+ }
+
+ inline const bool& options::
+ no_line () const
+ {
+ return this->no_line_;
+ }
+
+ inline const path& options::
+ buildfile () const
+ {
+ return this->buildfile_;
+ }
+
+ inline bool options::
+ buildfile_specified () const
+ {
+ return this->buildfile_specified_;
+ }
+
+ inline const path& options::
+ config_guess () const
+ {
+ return this->config_guess_;
+ }
+
+ inline bool options::
+ config_guess_specified () const
+ {
+ return this->config_guess_specified_;
+ }
+
+ inline const path& options::
+ config_sub () const
+ {
+ return this->config_sub_;
+ }
+
+ inline bool options::
+ config_sub_specified () const
+ {
+ return this->config_sub_specified_;
+ }
+
+ inline const string& options::
+ pager () const
+ {
+ return this->pager_;
+ }
+
+ inline bool options::
+ pager_specified () const
+ {
+ return this->pager_specified_;
+ }
+
+ inline const strings& options::
+ pager_option () const
+ {
+ return this->pager_option_;
+ }
+
+ inline bool options::
+ pager_option_specified () const
+ {
+ return this->pager_option_specified_;
+ }
+
+ inline const string& options::
+ options_file () const
+ {
+ return this->options_file_;
+ }
+
+ inline bool options::
+ options_file_specified () const
+ {
+ return this->options_file_specified_;
+ }
+
+ inline const dir_path& options::
+ default_options () const
+ {
+ return this->default_options_;
+ }
+
+ inline bool options::
+ default_options_specified () const
+ {
+ return this->default_options_specified_;
+ }
+
+ inline const bool& options::
+ no_default_options () const
+ {
+ return this->no_default_options_;
+ }
+
+ inline const bool& options::
+ help () const
+ {
+ return this->help_;
+ }
+
+ inline const bool& options::
+ version () const
+ {
+ return this->version_;
+ }
+}
+
+// Begin epilogue.
+//
+//
+// End epilogue.
diff --git a/build2/b.cli b/libbuild2/b.cli
index 112db2b..112db2b 100644
--- a/build2/b.cli
+++ b/libbuild2/b.cli
diff --git a/libbuild2/buildfile b/libbuild2/buildfile
index ee320e4..74d7485 100644
--- a/libbuild2/buildfile
+++ b/libbuild2/buildfile
@@ -25,8 +25,13 @@ include $bundled_modules
#
intf_libs = $libbutl
-lib{build2}: libul{build2}: \
- {hxx ixx txx cxx}{* -utility-*installed -config -version -*.test...} \
+lib{build2}: libul{build2}: \
+ {hxx ixx txx cxx}{* -utility-*installed \
+ -b-options \
+ -config \
+ -version \
+ -*.test...} \
+ {hxx ixx cxx}{b-options} \
{hxx}{config version}
libul{build2}: script/{hxx ixx txx cxx}{** -*-options -**.test...} \
@@ -227,19 +232,16 @@ else
if $cli.configured
{
cli.options += --std c++11 -I $src_root --include-with-brackets \
---generate-vector-scanner --generate-modifier --generate-specifier \
---suppress-usage
+--generate-specifier
cli.cxx{*}:
{
# Include the generated cli files into the distribution and don't remove
# them when cleaning in src (so that clean results in a state identical
- # to distributed). But don't install their headers since they are only
- # used internally in the testscript implementation.
+ # to distributed).
#
dist = true
clean = ($src_root != $out_root)
- install = false
# We keep the generated code in the repository so copy it back to src in
# case of a forwarded configuration.
@@ -247,10 +249,31 @@ if $cli.configured
backlink = overwrite
}
+ cli.cxx{b-options}: cli{b}
+ {
+ cli.options += --cli-namespace build2::build::cli \
+--include-prefix libbuild2 --guard-prefix LIBBUILD2 \
+--export-symbol LIBBUILD2_SYMEXPORT \
+--hxx-prologue '#include <libbuild2/export.hxx>' \
+--cxx-prologue "#include <libbuild2/types-parsers.hxx>" \
+--generate-file-scanner --keep-separator --generate-parse --generate-merge
+
+ # Usage options.
+ #
+ cli.options += --suppress-undocumented --long-usage --ansi-color \
+--ascii-tree --page-usage 'build2::print_$name$_' --option-length 21
+ }
+
script/cli.cxx{builtin-options}: script/cli{builtin}
{
cli.options += --cli-namespace build2::script::cli \
---include-prefix libbuild2/script --guard-prefix LIBBUILD2_SCRIPT
+--include-prefix libbuild2/script --guard-prefix LIBBUILD2_SCRIPT \
+--generate-vector-scanner --generate-modifier --suppress-usage
+
+ # Don't install the generated cli headers since they are only used
+ # internally in the script implementation.
+ #
+ install = false
}
build/script/cli.cxx{builtin-options}: build/script/cli{builtin}
@@ -258,7 +281,12 @@ if $cli.configured
cli.options += --cli-namespace build2::build::script::cli \
--include-prefix libbuild2/build/script --guard-prefix LIBBUILD2_BUILD_SCRIPT \
--cxx-prologue "#include <libbuild2/build/script/types-parsers.hxx>" \
---generate-parse
+--generate-parse --generate-vector-scanner --generate-modifier --suppress-usage
+
+ # Don't install the generated cli headers since they are only used
+ # internally in the buildscript implementation.
+ #
+ install = false
}
}
else
diff --git a/libbuild2/cmdline.cxx b/libbuild2/cmdline.cxx
new file mode 100644
index 0000000..a5f9616
--- /dev/null
+++ b/libbuild2/cmdline.cxx
@@ -0,0 +1,408 @@
+// file : libbuild2/cmdline.cxx -*- C++ -*-
+// license : MIT; see accompanying LICENSE file
+
+#include <libbuild2/cmdline.hxx>
+
+#include <limits>
+#include <cstring> // strcmp(), strchr()
+
+#include <libbutl/default-options.hxx>
+
+#include <libbuild2/b-options.hxx>
+#include <libbuild2/diagnostics.hxx>
+
+using namespace std;
+using namespace butl;
+
+namespace cli = build2::build::cli;
+
+namespace build2
+{
+ cmdline
+ parse_cmdline (tracer& trace, int argc, char* argv[], options& ops)
+ {
+ // Note that the diagnostics verbosity level can only be calculated after
+ // default options are loaded and merged (see below). Thus, until then we
+ // refer to the verbosity level specified on the command line.
+ //
+ auto verbosity = [&ops] ()
+ {
+ uint16_t v (
+ ops.verbose_specified ()
+ ? ops.verbose ()
+ : ops.V () ? 3 : ops.v () ? 2 : ops.quiet () || ops.silent () ? 0 : 1);
+ return v;
+ };
+
+ cmdline r;
+
+ // We want to be able to specify options, vars, and buildspecs in any
+ // order (it is really handy to just add -v at the end of the command
+ // line).
+ //
+ try
+ {
+ // Command line arguments starting position.
+ //
+ // We want the positions of the command line arguments to be after the
+ // default options files. Normally that would be achieved by passing the
+ // last position of the previous scanner to the next. The problem is
+ // that we parse the command line arguments first (for good reasons).
+ // Also the default options files parsing machinery needs the maximum
+ // number of arguments to be specified and assigns the positions below
+ // this value (see load_default_options() for details). So we are going
+ // to "reserve" the first half of the size_t value range for the default
+ // options positions and the second half for the command line arguments
+ // positions.
+ //
+ size_t args_pos (numeric_limits<size_t>::max () / 2);
+ cli::argv_file_scanner scan (argc, argv, "--options-file", args_pos);
+
+ size_t argn (0); // Argument count.
+ bool shortcut (false); // True if the shortcut syntax is used.
+
+ for (bool opt (true), var (true); scan.more (); )
+ {
+ if (opt)
+ {
+ // Parse the next chunk of options until we reach an argument (or
+ // eos).
+ //
+ if (ops.parse (scan) && !scan.more ())
+ break;
+
+ // If we see first "--", then we are done parsing options.
+ //
+ if (strcmp (scan.peek (), "--") == 0)
+ {
+ scan.next ();
+ opt = false;
+ continue;
+ }
+
+ // Fall through.
+ }
+
+ const char* s (scan.next ());
+
+ // See if this is a command line variable. What if someone needs to
+ // pass a buildspec that contains '='? One way to support this would
+ // be to quote such a buildspec (e.g., "'/tmp/foo=bar/'"). Or invent
+ // another separator. Or use a second "--". Actually, let's just do
+ // the second "--".
+ //
+ if (var)
+ {
+ // If we see second "--", then we are also done parsing variables.
+ //
+ if (strcmp (s, "--") == 0)
+ {
+ var = false;
+ continue;
+ }
+
+ if (const char* p = strchr (s, '=')) // Covers =, +=, and =+.
+ {
+ // Diagnose the empty variable name situation. Note that we don't
+ // allow "partially broken down" assignments (as in foo =bar)
+ // since foo= bar would be ambigous.
+ //
+ if (p == s || (p == s + 1 && *s == '+'))
+ fail << "missing variable name in '" << s << "'";
+
+ r.cmd_vars.push_back (s);
+ continue;
+ }
+
+ // Handle the "broken down" variable assignments (i.e., foo = bar
+ // instead of foo=bar).
+ //
+ if (scan.more ())
+ {
+ const char* a (scan.peek ());
+
+ if (strcmp (a, "=" ) == 0 ||
+ strcmp (a, "+=") == 0 ||
+ strcmp (a, "=+") == 0)
+ {
+ string v (s);
+ v += a;
+
+ scan.next ();
+
+ if (scan.more ())
+ v += scan.next ();
+
+ r.cmd_vars.push_back (move (v));
+ continue;
+ }
+ }
+
+ // Fall through.
+ }
+
+ // Merge all the individual buildspec arguments into a single string.
+ // We use newlines to separate arguments so that line numbers in
+ // diagnostics signify argument numbers. Clever, huh?
+ //
+ if (argn != 0)
+ r.buildspec += '\n';
+
+ r.buildspec += s;
+
+ // See if we are using the shortcut syntax.
+ //
+ if (argn == 0 && r.buildspec.back () == ':')
+ {
+ r.buildspec.back () = '(';
+ shortcut = true;
+ }
+
+ argn++;
+ }
+
+ // Add the closing parenthesis unless there wasn't anything in between
+ // in which case pop the opening one.
+ //
+ if (shortcut)
+ {
+ if (argn == 1)
+ r.buildspec.pop_back ();
+ else
+ r.buildspec += ')';
+ }
+
+ // Get/set an environment variable tracing the operation.
+ //
+ auto get_env = [&verbosity, &trace] (const char* nm)
+ {
+ optional<string> r (getenv (nm));
+
+ if (verbosity () >= 5)
+ {
+ if (r)
+ trace << nm << ": '" << *r << "'";
+ else
+ trace << nm << ": <NULL>";
+ }
+
+ return r;
+ };
+
+ auto set_env = [&verbosity, &trace] (const char* nm, const string& vl)
+ {
+ try
+ {
+ if (verbosity () >= 5)
+ trace << "setting " << nm << "='" << vl << "'";
+
+ setenv (nm, vl);
+ }
+ catch (const system_error& e)
+ {
+ // The variable value can potentially be long/multi-line, so let's
+ // print it last.
+ //
+ fail << "unable to set environment variable " << nm << ": " << e <<
+ info << "value: '" << vl << "'";
+ }
+ };
+
+ // If the BUILD2_VAR_OVR environment variable is present, then parse its
+ // value as a newline-separated global variable overrides and prepend
+ // them to the overrides specified on the command line.
+ //
+ // Note that this means global overrides may not contain a newline.
+
+ // Verify that the string is a valid global override. Uses the file name
+ // and the options flag for diagnostics only.
+ //
+ auto verify_glb_ovr = [] (const string& v, const path_name& fn, bool opt)
+ {
+ size_t p (v.find ('=', 1));
+ if (p == string::npos || v[0] != '!')
+ {
+ diag_record dr (fail (fn));
+ dr << "expected " << (opt ? "option or " : "") << "global "
+ << "variable override instead of '" << v << "'";
+
+ if (p != string::npos)
+ dr << info << "prefix variable assignment with '!'";
+ }
+
+ if (p == 1 || (p == 2 && v[1] == '+')) // '!=' or '!+=' ?
+ fail (fn) << "missing variable name in '" << v << "'";
+ };
+
+ optional<string> env_ovr (get_env ("BUILD2_VAR_OVR"));
+ if (env_ovr)
+ {
+ path_name fn ("<BUILD2_VAR_OVR>");
+
+ auto i (r.cmd_vars.begin ());
+ for (size_t b (0), e (0); next_word (*env_ovr, b, e, '\n', '\r'); )
+ {
+ // Extract the override from the current line, stripping the leading
+ // and trailing spaces.
+ //
+ string s (*env_ovr, b, e - b);
+ trim (s);
+
+ // Verify and save the override, unless the line is empty.
+ //
+ if (!s.empty ())
+ {
+ verify_glb_ovr (s, fn, false /* opt */);
+ i = r.cmd_vars.insert (i, move (s)) + 1;
+ }
+ }
+ }
+
+ // Load the default options files, unless --no-default-options is
+ // specified on the command line or the BUILD2_DEF_OPT environment
+ // variable is set to a value other than 'true' or '1'.
+ //
+ // If loaded, prepend the default global overrides to the variables
+ // specified on the command line, unless BUILD2_VAR_OVR is set in which
+ // case just ignore them.
+ //
+ optional<string> env_def (get_env ("BUILD2_DEF_OPT"));
+
+ // False if --no-default-options is specified on the command line. Note
+ // that we cache the flag since it can be overridden by a default
+ // options file.
+ //
+ bool cmd_def (!ops.no_default_options ());
+
+ if (cmd_def && (!env_def || *env_def == "true" || *env_def == "1"))
+ try
+ {
+ optional<dir_path> extra;
+ if (ops.default_options_specified ())
+ extra = ops.default_options ();
+
+ // Load default options files.
+ //
+ default_options<options> def_ops (
+ load_default_options<options,
+ cli::argv_file_scanner,
+ cli::unknown_mode> (
+ nullopt /* sys_dir */,
+ path::home_directory (), // The home variable is not assigned yet.
+ extra,
+ default_options_files {{path ("b.options")},
+ nullopt /* start */},
+ [&trace, &verbosity] (const path& f, bool r, bool o)
+ {
+ if (verbosity () >= 3)
+ {
+ if (o)
+ trace << "treating " << f << " as "
+ << (r ? "remote" : "local");
+ else
+ trace << "loading " << (r ? "remote " : "local ") << f;
+ }
+ },
+ "--options-file",
+ args_pos,
+ 1024,
+ true /* args */));
+
+ // Merge the default and command line options.
+ //
+ ops = merge_default_options (def_ops, ops);
+
+ // Merge the default and command line global overrides, unless
+ // BUILD2_VAR_OVR is already set (in which case we assume this has
+ // already been done).
+ //
+ // Note that the "broken down" variable assignments occupying a single
+ // line are naturally supported.
+ //
+ if (!env_ovr)
+ r.cmd_vars =
+ merge_default_arguments (
+ def_ops,
+ r.cmd_vars,
+ [&verify_glb_ovr] (const default_options_entry<options>& e,
+ const strings&)
+ {
+ path_name fn (e.file);
+
+ // Verify that all arguments are global overrides.
+ //
+ for (const string& a: e.arguments)
+ verify_glb_ovr (a, fn, true /* opt */);
+ });
+ }
+ catch (const invalid_argument& e)
+ {
+ fail << "unable to load default options files: " << e;
+ }
+ catch (const pair<path, system_error>& e)
+ {
+ fail << "unable to load default options files: " << e.first << ": "
+ << e.second;
+ }
+ catch (const system_error& e)
+ {
+ fail << "unable to obtain home directory: " << e;
+ }
+
+ // Verify and save the global overrides present in cmd_vars (default,
+ // from the command line, etc), if any, into the BUILD2_VAR_OVR
+ // environment variable.
+ //
+ if (!r.cmd_vars.empty ())
+ {
+ string ovr;
+ for (const string& v: r.cmd_vars)
+ {
+ if (v[0] == '!')
+ {
+ if (v.find_first_of ("\n\r") != string::npos)
+ fail << "newline in global variable override '" << v << "'";
+
+ if (!ovr.empty ())
+ ovr += '\n';
+
+ ovr += v;
+ }
+ }
+
+ // Optimize for the common case.
+ //
+ // Note: cmd_vars may contain non-global overrides.
+ //
+ if (!ovr.empty () && (!env_ovr || *env_ovr != ovr))
+ set_env ("BUILD2_VAR_OVR", ovr);
+ }
+
+ // Propagate disabling of the default options files to the potential
+ // nested invocations.
+ //
+ if (!cmd_def && (!env_def || *env_def != "0"))
+ set_env ("BUILD2_DEF_OPT", "0");
+
+ // Validate options.
+ //
+ if (ops.progress () && ops.no_progress ())
+ fail << "both --progress and --no-progress specified";
+
+ if (ops.mtime_check () && ops.no_mtime_check ())
+ fail << "both --mtime-check and --no-mtime-check specified";
+ }
+ catch (const cli::exception& e)
+ {
+ fail << e;
+ }
+
+ r.verbosity = verbosity ();
+
+ if (ops.silent () && r.verbosity != 0)
+ fail << "specified with -v, -V, or --verbose verbosity level "
+ << r.verbosity << " is incompatible with --silent";
+
+ return r;
+ }
+}
diff --git a/libbuild2/cmdline.hxx b/libbuild2/cmdline.hxx
new file mode 100644
index 0000000..7bf41c2
--- /dev/null
+++ b/libbuild2/cmdline.hxx
@@ -0,0 +1,29 @@
+// file : libbuild2/cmdline.hxx -*- C++ -*-
+// license : MIT; see accompanying LICENSE file
+
+#ifndef LIBBUILD2_CMDLINE_HXX
+#define LIBBUILD2_CMDLINE_HXX
+
+#include <libbuild2/types.hxx>
+#include <libbuild2/forward.hxx>
+#include <libbuild2/utility.hxx>
+
+#include <libbuild2/b-options.hxx>
+#include <libbuild2/diagnostics.hxx>
+
+#include <libbuild2/export.hxx>
+
+namespace build2
+{
+ struct cmdline
+ {
+ strings cmd_vars;
+ string buildspec;
+ uint16_t verbosity;
+ };
+
+ LIBBUILD2_SYMEXPORT cmdline
+ parse_cmdline (tracer&, int argc, char* argv[], options&);
+}
+
+#endif // LIBBUILD2_CMDLINE_HXX
diff --git a/libbuild2/types-parsers.cxx b/libbuild2/types-parsers.cxx
new file mode 100644
index 0000000..86ce219
--- /dev/null
+++ b/libbuild2/types-parsers.cxx
@@ -0,0 +1,53 @@
+// file : libbuild2/types-parsers.cxx -*- C++ -*-
+// license : MIT; see accompanying LICENSE file
+
+#include <libbuild2/types-parsers.hxx>
+
+#include <libbuild2/b-options.hxx> // build2::build::cli namespace
+
+namespace build2
+{
+ namespace build
+ {
+ namespace cli
+ {
+ template <typename T>
+ static void
+ parse_path (T& x, scanner& s)
+ {
+ const char* o (s.next ());
+
+ if (!s.more ())
+ throw missing_value (o);
+
+ const char* v (s.next ());
+
+ try
+ {
+ x = T (v);
+
+ if (x.empty ())
+ throw invalid_value (o, v);
+ }
+ catch (const invalid_path&)
+ {
+ throw invalid_value (o, v);
+ }
+ }
+
+ void parser<path>::
+ parse (path& x, bool& xs, scanner& s)
+ {
+ xs = true;
+ parse_path (x, s);
+ }
+
+ void parser<dir_path>::
+ parse (dir_path& x, bool& xs, scanner& s)
+ {
+ xs = true;
+ parse_path (x, s);
+ }
+ }
+ }
+}
diff --git a/libbuild2/types-parsers.hxx b/libbuild2/types-parsers.hxx
new file mode 100644
index 0000000..c64e0f6
--- /dev/null
+++ b/libbuild2/types-parsers.hxx
@@ -0,0 +1,48 @@
+// file : libbuild2/types-parsers.hxx -*- C++ -*-
+// license : MIT; see accompanying LICENSE file
+
+// CLI parsers, included into the generated source files.
+//
+
+#ifndef LIBBUILD2_TYPES_PARSERS_HXX
+#define LIBBUILD2_TYPES_PARSERS_HXX
+
+#include <libbuild2/types.hxx>
+
+#include <libbuild2/types-parsers.hxx>
+
+namespace build2
+{
+ namespace build
+ {
+ namespace cli
+ {
+ class scanner;
+
+ template <typename T>
+ struct parser;
+
+ template <>
+ struct parser<path>
+ {
+ static void
+ parse (path&, bool&, scanner&);
+
+ static void
+ merge (path& b, const path& a) {b = a;}
+ };
+
+ template <>
+ struct parser<dir_path>
+ {
+ static void
+ parse (dir_path&, bool&, scanner&);
+
+ static void
+ merge (dir_path& b, const dir_path& a) {b = a;}
+ };
+ }
+ }
+}
+
+#endif // LIBBUILD2_TYPES_PARSERS_HXX