aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--libbutl/default-options.mxx11
-rw-r--r--libbutl/default-options.txx18
-rw-r--r--tests/default-options/driver.cxx64
-rw-r--r--tests/default-options/testscript33
4 files changed, 88 insertions, 38 deletions
diff --git a/libbutl/default-options.mxx b/libbutl/default-options.mxx
index aeb246d..11f7bb2 100644
--- a/libbutl/default-options.mxx
+++ b/libbutl/default-options.mxx
@@ -61,10 +61,12 @@ LIBBUTL_MODEXPORT namespace butl
using default_options = small_vector<default_options_entry<O>, 4>;
// Search for and load the specified list of options files in the specified
- // directories returning a vector of option class instances (O). If args is
- // false, only options are allowed and are parsed using scanner S in the
- // U::fail mode. If args is true, then both options and arguments are
- // allowed in any order with options parsed in the U::stop mode.
+ // directories returning a vector of option class instances (O). Read
+ // additional options from files referenced by the specified option
+ // (normally --options-file). If args is false, only options are allowed and
+ // are parsed using scanner S in the U::fail mode. If args is true, then
+ // both options and arguments are allowed in any order with options parsed
+ // in the U::stop mode.
//
// Pass each default options file path to the specified function prior to
// load (can be used for tracing, etc). The function signature is:
@@ -112,6 +114,7 @@ LIBBUTL_MODEXPORT namespace butl
const optional<dir_path>& extra_dir,
const default_options_files&,
F&&,
+ const std::string& option,
bool args = false);
// Merge the default options/arguments and the command line
diff --git a/libbutl/default-options.txx b/libbutl/default-options.txx
index 5245bd6..eaf4235 100644
--- a/libbutl/default-options.txx
+++ b/libbutl/default-options.txx
@@ -31,6 +31,7 @@ LIBBUTL_MODEXPORT namespace butl //@@ MOD Clang needs this for some reason.
template <typename O, typename S, typename U, typename F>
bool
load_default_options_files (const dir_path& d,
+ const std::string& opt,
bool args,
bool remote,
const small_vector<path, 2>& fs,
@@ -43,7 +44,8 @@ LIBBUTL_MODEXPORT namespace butl //@@ MOD Clang needs this for some reason.
bool r (true);
- auto load = [args, &fs, &fn, &def_ops, &r] (const dir_path& d, bool rem)
+ auto load = [&opt, args, &fs, &fn, &def_ops, &r]
+ (const dir_path& d, bool rem)
{
using namespace std;
@@ -57,7 +59,7 @@ LIBBUTL_MODEXPORT namespace butl //@@ MOD Clang needs this for some reason.
{
fn (p, rem, false /* overwrite */);
- S s (p.string ());
+ S s (p.string (), opt);
// @@ Note that the potentially thrown exceptions (unknown option,
// unexpected argument, etc) will not contain any location
@@ -66,7 +68,7 @@ LIBBUTL_MODEXPORT namespace butl //@@ MOD Clang needs this for some reason.
// this in CLI.
//
O o;
- small_vector<std::string, 1> as;
+ small_vector<string, 1> as;
if (args)
{
@@ -88,9 +90,9 @@ LIBBUTL_MODEXPORT namespace butl //@@ MOD Clang needs this for some reason.
rem});
}
}
- catch (std::system_error& e)
+ catch (system_error& e)
{
- throw std::make_pair (move (p), std::move (e));
+ throw make_pair (move (p), move (e));
}
}
};
@@ -116,6 +118,7 @@ LIBBUTL_MODEXPORT namespace butl //@@ MOD Clang needs this for some reason.
const optional<dir_path>& extra_dir,
const default_options_files& ofs,
F&& fn,
+ const std::string& opt,
bool args)
{
if (sys_dir)
@@ -206,6 +209,7 @@ LIBBUTL_MODEXPORT namespace butl //@@ MOD Clang needs this for some reason.
if (load_extra && extra_dir->sub (d))
{
load = load_default_options_files<O, S, U> (*extra_dir,
+ opt,
args,
false /* remote */,
ofs.files,
@@ -219,6 +223,7 @@ LIBBUTL_MODEXPORT namespace butl //@@ MOD Clang needs this for some reason.
if (load && options_dir_exists (od))
load = load_default_options_files<O, S, U> (od,
+ opt,
args,
remote,
ofs.files,
@@ -235,6 +240,7 @@ LIBBUTL_MODEXPORT namespace butl //@@ MOD Clang needs this for some reason.
if (load && load_extra)
load = load_default_options_files<O, S, U> (*extra_dir,
+ opt,
args,
false /* remote */,
ofs.files,
@@ -247,6 +253,7 @@ LIBBUTL_MODEXPORT namespace butl //@@ MOD Clang needs this for some reason.
if (options_dir_exists (d))
load = load_default_options_files<O, S, U> (d,
+ opt,
args,
false /* remote */,
ofs.files,
@@ -256,6 +263,7 @@ LIBBUTL_MODEXPORT namespace butl //@@ MOD Clang needs this for some reason.
if (load && sys_dir && options_dir_exists (*sys_dir))
load_default_options_files<O, S, U> (*sys_dir,
+ opt,
args,
false /* remote */,
ofs.files,
diff --git a/tests/default-options/driver.cxx b/tests/default-options/driver.cxx
index 574e002..b3f66bf 100644
--- a/tests/default-options/driver.cxx
+++ b/tests/default-options/driver.cxx
@@ -35,7 +35,7 @@ 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
@@ -78,56 +78,61 @@ 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)
+ : option_ (option) {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_++];
+ }
+
+ private:
+ void
+ load (const path& f)
+ {
+ ifdstream is (f, fdopen_mode::in, ifdstream::badbit);
- string s;
- if (peeked_)
+ 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)));
- return s;
+ // 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);
+
+ 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;
};
enum class unknow_mode
@@ -264,6 +269,7 @@ main (int argc, const char* argv[])
cerr << (overwrite ? "overwriting " : "loading ")
<< (remote ? "remote " : "local ") << f << endl;
},
+ "--options-file",
args);
}
catch (const invalid_argument& e)
diff --git a/tests/default-options/testscript b/tests/default-options/testscript
index b168ca9..09bb2ec 100644
--- a/tests/default-options/testscript
+++ b/tests/default-options/testscript
@@ -345,3 +345,36 @@
EOO
}
}
+
+: options-file
+:
+{
+ d = work/.build2;
+ mkdir -p work/.build2;
+
+ cat <<EOI >=$d/foo;
+ --foo
+ --options-file
+ bar
+ --fox
+ EOI
+
+ cat <<EOI >=$d/bar;
+ --bar
+ --options-file
+ baz
+ --box
+ EOI
+
+ cat <<EOI >=$d/baz;
+ --baz
+ EOI
+
+ $* -d $~/work -f foo >>EOO
+ --foo
+ --bar
+ --baz
+ --box
+ --fox
+ EOO
+}