aboutsummaryrefslogtreecommitdiff
path: root/tests/default-options/driver.cxx
diff options
context:
space:
mode:
Diffstat (limited to 'tests/default-options/driver.cxx')
-rw-r--r--tests/default-options/driver.cxx174
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;
}