aboutsummaryrefslogtreecommitdiff
path: root/libbutl/default-options.txx
diff options
context:
space:
mode:
Diffstat (limited to 'libbutl/default-options.txx')
-rw-r--r--libbutl/default-options.txx104
1 files changed, 94 insertions, 10 deletions
diff --git a/libbutl/default-options.txx b/libbutl/default-options.txx
index 5245bd6..aa254b2 100644
--- a/libbutl/default-options.txx
+++ b/libbutl/default-options.txx
@@ -1,7 +1,15 @@
// file : libbutl/default-options.txx -*- C++ -*-
// license : MIT; see accompanying LICENSE file
-LIBBUTL_MODEXPORT namespace butl //@@ MOD Clang needs this for some reason.
+#include <utility> // move(), forward(), make_pair()
+#include <algorithm> // reverse()
+#include <stdexcept> // invalid_argument
+#include <system_error>
+
+#include <libbutl/git.hxx>
+#include <libbutl/filesystem.hxx>
+
+namespace butl
{
inline bool
options_dir_exists (const dir_path& d)
@@ -14,10 +22,11 @@ LIBBUTL_MODEXPORT namespace butl //@@ MOD Clang needs this for some reason.
throw std::make_pair (path_cast<path> (d), std::move (e));
}
- // Search for and parse the options files in the specified directory and
- // its local/ subdirectory, if exists, in the reverse order and append the
- // options to the resulting list. Return false if --no-default-options is
- // encountered.
+ // Search for and parse the options files in the specified directory and its
+ // local/ subdirectory, if exists, in the reverse order and append the
+ // options to the resulting list. Verify that the number of arguments
+ // doesn't exceed the limits and decrement arg_max by arg_max_file after
+ // parsing each file. Return false if --no-default-options is encountered.
//
// Note that by default we check for the local/ subdirectory even if we
// don't think it belongs to the remote directory; the user may move things
@@ -31,10 +40,13 @@ 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,
F&& fn,
+ std::size_t& arg_max,
+ std::size_t arg_max_file,
default_options<O>& def_ops,
bool load_sub = true,
bool load_dir = true)
@@ -43,7 +55,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, &arg_max, arg_max_file, &r]
+ (const dir_path& d, bool rem)
{
using namespace std;
@@ -55,9 +68,14 @@ LIBBUTL_MODEXPORT namespace butl //@@ MOD Clang needs this for some reason.
{
if (file_exists (p)) // Follows symlinks.
{
+ if (arg_max < arg_max_file)
+ throw invalid_argument ("too many options files");
+
+ size_t start_pos (arg_max - arg_max_file);
+
fn (p, rem, false /* overwrite */);
- S s (p.string ());
+ S s (p.string (), opt, start_pos);
// @@ Note that the potentially thrown exceptions (unknown option,
// unexpected argument, etc) will not contain any location
@@ -66,7 +84,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)
{
@@ -79,6 +97,15 @@ LIBBUTL_MODEXPORT namespace butl //@@ MOD Clang needs this for some reason.
else
o.parse (s, U::fail, U::fail);
+ if (s.position () > arg_max)
+ throw invalid_argument ("too many options in file " +
+ p.string ());
+
+ // Don't decrement arg_max for the empty option files.
+ //
+ if (s.position () != start_pos)
+ arg_max = start_pos;
+
if (o.no_default_options ())
r = false;
@@ -88,9 +115,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 +143,9 @@ 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,
+ std::size_t arg_max,
+ std::size_t arg_max_file,
bool args)
{
if (sys_dir)
@@ -206,10 +236,13 @@ 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,
std::forward<F> (fn),
+ arg_max,
+ arg_max_file,
r);
load_extra = false;
@@ -219,10 +252,13 @@ 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,
std::forward<F> (fn),
+ arg_max,
+ arg_max_file,
r,
load_build2_local,
load_build2);
@@ -235,10 +271,13 @@ 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,
std::forward<F> (fn),
+ arg_max,
+ arg_max_file,
r);
if (load && home_dir)
@@ -247,19 +286,25 @@ 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,
std::forward<F> (fn),
+ arg_max,
+ arg_max_file,
r);
}
if (load && sys_dir && options_dir_exists (*sys_dir))
load_default_options_files<O, S, U> (*sys_dir,
+ opt,
args,
false /* remote */,
ofs.files,
std::forward<F> (fn),
+ arg_max,
+ arg_max_file,
r);
std::reverse (r.begin (), r.end ());
@@ -310,4 +355,43 @@ LIBBUTL_MODEXPORT namespace butl //@@ MOD Clang needs this for some reason.
r.insert (r.end (), cmd_args.begin (), cmd_args.end ());
return r;
}
+
+ template <typename I, typename F>
+ optional<dir_path>
+ default_options_start (const optional<dir_path>& home, I b, I e, F&& f)
+ {
+ if (home)
+ assert (home->absolute () && home->normalized ());
+
+ if (b == e)
+ return nullopt;
+
+ // Use the first directory as a start.
+ //
+ I i (b);
+ dir_path d (f (i));
+
+ // Try to find a common prefix for each subsequent directory.
+ //
+ for (++i; i != e; ++i)
+ {
+ bool p (false);
+
+ for (;
+ !(d.root () || (home && d == *home));
+ d = d.directory ())
+ {
+ if (f (i).sub (d))
+ {
+ p = true;
+ break;
+ }
+ }
+
+ if (!p)
+ return nullopt;
+ }
+
+ return d;
+ }
}