diff options
Diffstat (limited to 'tests/default-options/driver.cxx')
-rw-r--r-- | tests/default-options/driver.cxx | 174 |
1 files changed, 112 insertions, 62 deletions
diff --git a/tests/default-options/driver.cxx b/tests/default-options/driver.cxx index 574e002..766dca8 100644 --- a/tests/default-options/driver.cxx +++ b/tests/default-options/driver.cxx @@ -1,61 +1,48 @@ // file : tests/default-options/driver.cxx -*- C++ -*- // license : MIT; see accompanying LICENSE file -#include <cassert> - -#ifndef __cpp_lib_modules_ts +#include <limits> #include <string> #include <vector> #include <iostream> +#include <exception> #include <stdexcept> // invalid_argument -#endif - -// Other includes. - -#ifdef __cpp_modules_ts -#ifdef __cpp_lib_modules_ts -import std.core; -import std.io; -#endif -import butl.path; -import butl.path_io; -import butl.optional; -import butl.fdstream; -import butl.default_options; -#else -#include <libbutl/path.mxx> -#include <libbutl/path-io.mxx> -#include <libbutl/utility.mxx> // eof() -#include <libbutl/optional.mxx> -#include <libbutl/fdstream.mxx> -#include <libbutl/default-options.mxx> -#endif + +#include <libbutl/path.hxx> +#include <libbutl/path-io.hxx> +#include <libbutl/utility.hxx> // eof() +#include <libbutl/optional.hxx> +#include <libbutl/fdstream.hxx> +#include <libbutl/default-options.hxx> + +#undef NDEBUG +#include <cassert> using namespace std; using namespace butl; // Usage: argv[0] [-f <file>] [-d <start-dir>] [-s <sys-dir>] [-h <home-dir>] -// [-x <extra-dir>] [-e] [-t] <cmd-options> +// [-x <extra-dir>] [-a] [-e] [-t] <cmd-options> // // Parse default options files, merge them with the command line options, and // print the resulting options to STDOUT one per line. Note that the options // instance is a vector of arbitrary strings. // -// -f +// -f <file> // Default options file name. Can be specified multiple times. // -// -d +// -d <start-dir> // Directory to start the default options files search from. Can be // specified multiple times, in which case a common start (parent) // directory is deduced. // -// -s +// -s <sys-dir> // System directory. // -// -h +// -h <home-dir> // Home directory. // -// -x +// -x <extra-dir> // Extra directory. // // -a @@ -70,6 +57,12 @@ using namespace butl; // -t // Trace the default options files search to STDERR. // +// -m <num> +// Maximum number of arguments globally (SIZE_MAX/2 by default). +// +// -l <num> +// Maximum number of arguments in the options file (1024 by default). +// int main (int argc, const char* argv[]) { @@ -78,56 +71,68 @@ main (int argc, const char* argv[]) class scanner { public: - scanner (const string& f): ifs_ (f, fdopen_mode::in, ifdstream::badbit) {} + scanner (const string& f, const string& option, size_t pos) + : option_ (option), start_pos_ (pos) {load (path (f));} bool more () { - if (peeked_) - return true; - - if (!eof_) - eof_ = ifs_.peek () == ifdstream::traits_type::eof (); - - return !eof_; + return i_ < args_.size (); } string peek () { assert (more ()); - - if (peeked_) - return *peeked_; - - string s; - getline (ifs_, s); - - peeked_ = move (s); - return *peeked_; + return args_[i_]; } string next () { assert (more ()); + return args_[i_++]; + } + + size_t + position () + { + return start_pos_ + i_; + } - string s; - if (peeked_) + private: + void + load (const path& f) + { + ifdstream is (f, fdopen_mode::in, ifdstream::badbit); + + for (string l; !eof (getline (is, l)); ) { - s = move (*peeked_); - peeked_ = nullopt; - } - else - getline (ifs_, s); + if (option_ && *option_ == l) + { + assert (!eof (getline (is, l))); + + // 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. + // + path p (l); - return s; + if (!f.simple () && p.relative ()) + p = f.directory () / p; + + load (p); + } + else + args_.push_back (move (l)); + } } private: - ifdstream ifs_; - bool eof_ = false; - optional<string> peeked_; + optional<string> option_; + vector<string> args_; + size_t i_ = 0; + size_t start_pos_; }; enum class unknow_mode @@ -136,6 +141,15 @@ main (int argc, const char* argv[]) fail }; + class unknown_argument: public std::exception + { + public: + string argument; + + explicit + unknown_argument (string a): argument (move (a)) {} + }; + class options: public vector<string> { public: @@ -152,7 +166,7 @@ main (int argc, const char* argv[]) switch (m) { case unknow_mode::stop: return r; - case unknow_mode::fail: throw invalid_argument (a); + case unknow_mode::fail: throw unknown_argument (move (a)); } } @@ -195,6 +209,23 @@ main (int argc, const char* argv[]) vector<string> cmd_args; bool print_entries (false); bool trace (false); + size_t arg_max (numeric_limits<size_t>::max () / 2); + size_t arg_max_file (1024); + + auto num = [] (const string& s) -> size_t + { + assert (!s.empty ()); + + char* e (nullptr); + errno = 0; // We must clear it according to POSIX. + uint64_t r (strtoull (s.c_str (), &e, 10)); // Can't throw. + + assert (errno != ERANGE && + e == s.c_str () + s.size () && + r <= numeric_limits<size_t>::max ()); + + return static_cast<size_t> (r); + }; for (int i (1); i != argc; ++i) { @@ -237,6 +268,16 @@ main (int argc, const char* argv[]) { trace = true; } + else if (a == "-m") + { + assert (++i != argc); + arg_max = num (argv[i]); + } + else if (a == "-l") + { + assert (++i != argc); + arg_max_file = num (argv[i]); + } else if (a.compare (0, 2, "--") == 0) cmd_ops.push_back (move (a)); else @@ -245,7 +286,7 @@ main (int argc, const char* argv[]) // Deduce a common start directory. // - fs.start = default_options_start (home_dir, dirs); + fs.start = default_options_start (home_dir, dirs.begin (), dirs.end ()); // Load and print the default options. // @@ -264,11 +305,20 @@ main (int argc, const char* argv[]) cerr << (overwrite ? "overwriting " : "loading ") << (remote ? "remote " : "local ") << f << endl; }, + "--options-file", + arg_max, + arg_max_file, args); } + catch (const unknown_argument& e) + { + cerr << "error: unexpected argument '" << e.argument << "'" << endl; + return 1; + } catch (const invalid_argument& e) { - cerr << "error: unexpected argument '" << e.what () << "'" << endl; + cerr << "error: unable to load default options files: " << e.what () + << endl; return 1; } |