aboutsummaryrefslogtreecommitdiff
path: root/libbuild2/test/script
diff options
context:
space:
mode:
authorKaren Arutyunov <karen@codesynthesis.com>2019-09-10 23:23:43 +0300
committerKaren Arutyunov <karen@codesynthesis.com>2019-09-27 18:04:30 +0300
commitdbed808c7d534069f76e63a1a68a85f30d2be81c (patch)
tree3161d9c9617f2fccf37bd278f0c9bf45fad2e20e /libbuild2/test/script
parent6e84c0f9c5e4d7d98d2a352eec6bc19de0d75d28 (diff)
Move testscript builtins to libbutl
Diffstat (limited to 'libbuild2/test/script')
-rw-r--r--libbuild2/test/script/builtin-options.cxx3091
-rw-r--r--libbuild2/test/script/builtin-options.hxx680
-rw-r--r--libbuild2/test/script/builtin-options.ixx138
-rw-r--r--libbuild2/test/script/builtin.cli79
-rw-r--r--libbuild2/test/script/builtin.cxx1924
-rw-r--r--libbuild2/test/script/builtin.hxx74
-rw-r--r--libbuild2/test/script/runner.cxx250
7 files changed, 242 insertions, 5994 deletions
diff --git a/libbuild2/test/script/builtin-options.cxx b/libbuild2/test/script/builtin-options.cxx
index 9a7968e..6b6afe0 100644
--- a/libbuild2/test/script/builtin-options.cxx
+++ b/libbuild2/test/script/builtin-options.cxx
@@ -366,2274 +366,6 @@ namespace build2
{
namespace script
{
- // cleanup_options
- //
-
- cleanup_options::
- cleanup_options ()
- : no_cleanup_ ()
- {
- }
-
- typedef
- std::map<std::string, void (*) (cleanup_options&, ::build2::test::script::cli::scanner&)>
- _cli_cleanup_options_map;
-
- static _cli_cleanup_options_map _cli_cleanup_options_map_;
-
- struct _cli_cleanup_options_map_init
- {
- _cli_cleanup_options_map_init ()
- {
- _cli_cleanup_options_map_["--no-cleanup"] =
- &::build2::test::script::cli::thunk< cleanup_options, bool, &cleanup_options::no_cleanup_ >;
- }
- };
-
- static _cli_cleanup_options_map_init _cli_cleanup_options_map_init_;
-
- bool cleanup_options::
- _parse (const char* o, ::build2::test::script::cli::scanner& s)
- {
- _cli_cleanup_options_map::const_iterator i (_cli_cleanup_options_map_.find (o));
-
- if (i != _cli_cleanup_options_map_.end ())
- {
- (*(i->second)) (*this, s);
- return true;
- }
-
- return false;
- }
-
- // cat_options
- //
-
- cat_options::
- cat_options ()
- {
- }
-
- cat_options::
- cat_options (int& argc,
- char** argv,
- bool erase,
- ::build2::test::script::cli::unknown_mode opt,
- ::build2::test::script::cli::unknown_mode arg)
- {
- ::build2::test::script::cli::argv_scanner s (argc, argv, erase);
- _parse (s, opt, arg);
- }
-
- cat_options::
- cat_options (int start,
- int& argc,
- char** argv,
- bool erase,
- ::build2::test::script::cli::unknown_mode opt,
- ::build2::test::script::cli::unknown_mode arg)
- {
- ::build2::test::script::cli::argv_scanner s (start, argc, argv, erase);
- _parse (s, opt, arg);
- }
-
- cat_options::
- cat_options (int& argc,
- char** argv,
- int& end,
- bool erase,
- ::build2::test::script::cli::unknown_mode opt,
- ::build2::test::script::cli::unknown_mode arg)
- {
- ::build2::test::script::cli::argv_scanner s (argc, argv, erase);
- _parse (s, opt, arg);
- end = s.end ();
- }
-
- cat_options::
- cat_options (int start,
- int& argc,
- char** argv,
- int& end,
- bool erase,
- ::build2::test::script::cli::unknown_mode opt,
- ::build2::test::script::cli::unknown_mode arg)
- {
- ::build2::test::script::cli::argv_scanner s (start, argc, argv, erase);
- _parse (s, opt, arg);
- end = s.end ();
- }
-
- cat_options::
- cat_options (::build2::test::script::cli::scanner& s,
- ::build2::test::script::cli::unknown_mode opt,
- ::build2::test::script::cli::unknown_mode arg)
- {
- _parse (s, opt, arg);
- }
-
- typedef
- std::map<std::string, void (*) (cat_options&, ::build2::test::script::cli::scanner&)>
- _cli_cat_options_map;
-
- static _cli_cat_options_map _cli_cat_options_map_;
-
- struct _cli_cat_options_map_init
- {
- _cli_cat_options_map_init ()
- {
- }
- };
-
- static _cli_cat_options_map_init _cli_cat_options_map_init_;
-
- bool cat_options::
- _parse (const char* o, ::build2::test::script::cli::scanner& s)
- {
- _cli_cat_options_map::const_iterator i (_cli_cat_options_map_.find (o));
-
- if (i != _cli_cat_options_map_.end ())
- {
- (*(i->second)) (*this, s);
- return true;
- }
-
- return false;
- }
-
- bool cat_options::
- _parse (::build2::test::script::cli::scanner& s,
- ::build2::test::script::cli::unknown_mode opt_mode,
- ::build2::test::script::cli::unknown_mode arg_mode)
- {
- // Can't skip combined flags (--no-combined-flags).
- //
- assert (opt_mode != ::build2::test::script::cli::unknown_mode::skip);
-
- bool r = false;
- bool opt = true;
-
- while (s.more ())
- {
- const char* o = s.peek ();
-
- if (std::strcmp (o, "--") == 0)
- {
- opt = false;
- s.skip ();
- r = true;
- continue;
- }
-
- if (opt)
- {
- if (_parse (o, s))
- {
- r = true;
- continue;
- }
-
- if (std::strncmp (o, "-", 1) == 0 && o[1] != '\0')
- {
- // Handle combined option values.
- //
- std::string co;
- if (const char* v = std::strchr (o, '='))
- {
- co.assign (o, 0, v - o);
- ++v;
-
- int ac (2);
- char* av[] =
- {
- const_cast<char*> (co.c_str ()),
- const_cast<char*> (v)
- };
-
- ::build2::test::script::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::test::script::cli::invalid_value (co, v);
-
- s.next ();
- r = true;
- continue;
- }
- else
- {
- // Set the unknown option and fall through.
- //
- o = co.c_str ();
- }
- }
-
- // Handle combined flags.
- //
- char cf[3];
- {
- const char* p = o + 1;
- for (; *p != '\0'; ++p)
- {
- if (!((*p >= 'a' && *p <= 'z') ||
- (*p >= 'A' && *p <= 'Z') ||
- (*p >= '0' && *p <= '9')))
- break;
- }
-
- if (*p == '\0')
- {
- for (p = o + 1; *p != '\0'; ++p)
- {
- std::strcpy (cf, "-");
- cf[1] = *p;
- cf[2] = '\0';
-
- int ac (1);
- char* av[] =
- {
- cf
- };
-
- ::build2::test::script::cli::argv_scanner ns (0, ac, av);
-
- if (!_parse (cf, ns))
- break;
- }
-
- if (*p == '\0')
- {
- // All handled.
- //
- s.next ();
- r = true;
- continue;
- }
- else
- {
- // Set the unknown option and fall through.
- //
- o = cf;
- }
- }
- }
-
- switch (opt_mode)
- {
- case ::build2::test::script::cli::unknown_mode::skip:
- {
- s.skip ();
- r = true;
- continue;
- }
- case ::build2::test::script::cli::unknown_mode::stop:
- {
- break;
- }
- case ::build2::test::script::cli::unknown_mode::fail:
- {
- throw ::build2::test::script::cli::unknown_option (o);
- }
- }
-
- break;
- }
- }
-
- switch (arg_mode)
- {
- case ::build2::test::script::cli::unknown_mode::skip:
- {
- s.skip ();
- r = true;
- continue;
- }
- case ::build2::test::script::cli::unknown_mode::stop:
- {
- break;
- }
- case ::build2::test::script::cli::unknown_mode::fail:
- {
- throw ::build2::test::script::cli::unknown_argument (o);
- }
- }
-
- break;
- }
-
- return r;
- }
-
- // cp_options
- //
-
- cp_options::
- cp_options ()
- : recursive_ (),
- preserve_ ()
- {
- }
-
- cp_options::
- cp_options (int& argc,
- char** argv,
- bool erase,
- ::build2::test::script::cli::unknown_mode opt,
- ::build2::test::script::cli::unknown_mode arg)
- : recursive_ (),
- preserve_ ()
- {
- ::build2::test::script::cli::argv_scanner s (argc, argv, erase);
- _parse (s, opt, arg);
- }
-
- cp_options::
- cp_options (int start,
- int& argc,
- char** argv,
- bool erase,
- ::build2::test::script::cli::unknown_mode opt,
- ::build2::test::script::cli::unknown_mode arg)
- : recursive_ (),
- preserve_ ()
- {
- ::build2::test::script::cli::argv_scanner s (start, argc, argv, erase);
- _parse (s, opt, arg);
- }
-
- cp_options::
- cp_options (int& argc,
- char** argv,
- int& end,
- bool erase,
- ::build2::test::script::cli::unknown_mode opt,
- ::build2::test::script::cli::unknown_mode arg)
- : recursive_ (),
- preserve_ ()
- {
- ::build2::test::script::cli::argv_scanner s (argc, argv, erase);
- _parse (s, opt, arg);
- end = s.end ();
- }
-
- cp_options::
- cp_options (int start,
- int& argc,
- char** argv,
- int& end,
- bool erase,
- ::build2::test::script::cli::unknown_mode opt,
- ::build2::test::script::cli::unknown_mode arg)
- : recursive_ (),
- preserve_ ()
- {
- ::build2::test::script::cli::argv_scanner s (start, argc, argv, erase);
- _parse (s, opt, arg);
- end = s.end ();
- }
-
- cp_options::
- cp_options (::build2::test::script::cli::scanner& s,
- ::build2::test::script::cli::unknown_mode opt,
- ::build2::test::script::cli::unknown_mode arg)
- : recursive_ (),
- preserve_ ()
- {
- _parse (s, opt, arg);
- }
-
- typedef
- std::map<std::string, void (*) (cp_options&, ::build2::test::script::cli::scanner&)>
- _cli_cp_options_map;
-
- static _cli_cp_options_map _cli_cp_options_map_;
-
- struct _cli_cp_options_map_init
- {
- _cli_cp_options_map_init ()
- {
- _cli_cp_options_map_["--recursive"] =
- &::build2::test::script::cli::thunk< cp_options, bool, &cp_options::recursive_ >;
- _cli_cp_options_map_["-R"] =
- &::build2::test::script::cli::thunk< cp_options, bool, &cp_options::recursive_ >;
- _cli_cp_options_map_["-r"] =
- &::build2::test::script::cli::thunk< cp_options, bool, &cp_options::recursive_ >;
- _cli_cp_options_map_["--preserve"] =
- &::build2::test::script::cli::thunk< cp_options, bool, &cp_options::preserve_ >;
- _cli_cp_options_map_["-p"] =
- &::build2::test::script::cli::thunk< cp_options, bool, &cp_options::preserve_ >;
- }
- };
-
- static _cli_cp_options_map_init _cli_cp_options_map_init_;
-
- bool cp_options::
- _parse (const char* o, ::build2::test::script::cli::scanner& s)
- {
- _cli_cp_options_map::const_iterator i (_cli_cp_options_map_.find (o));
-
- if (i != _cli_cp_options_map_.end ())
- {
- (*(i->second)) (*this, s);
- return true;
- }
-
- // cleanup_options base
- //
- if (::build2::test::script::cleanup_options::_parse (o, s))
- return true;
-
- return false;
- }
-
- bool cp_options::
- _parse (::build2::test::script::cli::scanner& s,
- ::build2::test::script::cli::unknown_mode opt_mode,
- ::build2::test::script::cli::unknown_mode arg_mode)
- {
- // Can't skip combined flags (--no-combined-flags).
- //
- assert (opt_mode != ::build2::test::script::cli::unknown_mode::skip);
-
- bool r = false;
- bool opt = true;
-
- while (s.more ())
- {
- const char* o = s.peek ();
-
- if (std::strcmp (o, "--") == 0)
- {
- opt = false;
- s.skip ();
- r = true;
- continue;
- }
-
- if (opt)
- {
- if (_parse (o, s))
- {
- r = true;
- continue;
- }
-
- if (std::strncmp (o, "-", 1) == 0 && o[1] != '\0')
- {
- // Handle combined option values.
- //
- std::string co;
- if (const char* v = std::strchr (o, '='))
- {
- co.assign (o, 0, v - o);
- ++v;
-
- int ac (2);
- char* av[] =
- {
- const_cast<char*> (co.c_str ()),
- const_cast<char*> (v)
- };
-
- ::build2::test::script::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::test::script::cli::invalid_value (co, v);
-
- s.next ();
- r = true;
- continue;
- }
- else
- {
- // Set the unknown option and fall through.
- //
- o = co.c_str ();
- }
- }
-
- // Handle combined flags.
- //
- char cf[3];
- {
- const char* p = o + 1;
- for (; *p != '\0'; ++p)
- {
- if (!((*p >= 'a' && *p <= 'z') ||
- (*p >= 'A' && *p <= 'Z') ||
- (*p >= '0' && *p <= '9')))
- break;
- }
-
- if (*p == '\0')
- {
- for (p = o + 1; *p != '\0'; ++p)
- {
- std::strcpy (cf, "-");
- cf[1] = *p;
- cf[2] = '\0';
-
- int ac (1);
- char* av[] =
- {
- cf
- };
-
- ::build2::test::script::cli::argv_scanner ns (0, ac, av);
-
- if (!_parse (cf, ns))
- break;
- }
-
- if (*p == '\0')
- {
- // All handled.
- //
- s.next ();
- r = true;
- continue;
- }
- else
- {
- // Set the unknown option and fall through.
- //
- o = cf;
- }
- }
- }
-
- switch (opt_mode)
- {
- case ::build2::test::script::cli::unknown_mode::skip:
- {
- s.skip ();
- r = true;
- continue;
- }
- case ::build2::test::script::cli::unknown_mode::stop:
- {
- break;
- }
- case ::build2::test::script::cli::unknown_mode::fail:
- {
- throw ::build2::test::script::cli::unknown_option (o);
- }
- }
-
- break;
- }
- }
-
- switch (arg_mode)
- {
- case ::build2::test::script::cli::unknown_mode::skip:
- {
- s.skip ();
- r = true;
- continue;
- }
- case ::build2::test::script::cli::unknown_mode::stop:
- {
- break;
- }
- case ::build2::test::script::cli::unknown_mode::fail:
- {
- throw ::build2::test::script::cli::unknown_argument (o);
- }
- }
-
- break;
- }
-
- return r;
- }
-
- // ln_options
- //
-
- ln_options::
- ln_options ()
- : symbolic_ ()
- {
- }
-
- ln_options::
- ln_options (int& argc,
- char** argv,
- bool erase,
- ::build2::test::script::cli::unknown_mode opt,
- ::build2::test::script::cli::unknown_mode arg)
- : symbolic_ ()
- {
- ::build2::test::script::cli::argv_scanner s (argc, argv, erase);
- _parse (s, opt, arg);
- }
-
- ln_options::
- ln_options (int start,
- int& argc,
- char** argv,
- bool erase,
- ::build2::test::script::cli::unknown_mode opt,
- ::build2::test::script::cli::unknown_mode arg)
- : symbolic_ ()
- {
- ::build2::test::script::cli::argv_scanner s (start, argc, argv, erase);
- _parse (s, opt, arg);
- }
-
- ln_options::
- ln_options (int& argc,
- char** argv,
- int& end,
- bool erase,
- ::build2::test::script::cli::unknown_mode opt,
- ::build2::test::script::cli::unknown_mode arg)
- : symbolic_ ()
- {
- ::build2::test::script::cli::argv_scanner s (argc, argv, erase);
- _parse (s, opt, arg);
- end = s.end ();
- }
-
- ln_options::
- ln_options (int start,
- int& argc,
- char** argv,
- int& end,
- bool erase,
- ::build2::test::script::cli::unknown_mode opt,
- ::build2::test::script::cli::unknown_mode arg)
- : symbolic_ ()
- {
- ::build2::test::script::cli::argv_scanner s (start, argc, argv, erase);
- _parse (s, opt, arg);
- end = s.end ();
- }
-
- ln_options::
- ln_options (::build2::test::script::cli::scanner& s,
- ::build2::test::script::cli::unknown_mode opt,
- ::build2::test::script::cli::unknown_mode arg)
- : symbolic_ ()
- {
- _parse (s, opt, arg);
- }
-
- typedef
- std::map<std::string, void (*) (ln_options&, ::build2::test::script::cli::scanner&)>
- _cli_ln_options_map;
-
- static _cli_ln_options_map _cli_ln_options_map_;
-
- struct _cli_ln_options_map_init
- {
- _cli_ln_options_map_init ()
- {
- _cli_ln_options_map_["--symbolic"] =
- &::build2::test::script::cli::thunk< ln_options, bool, &ln_options::symbolic_ >;
- _cli_ln_options_map_["-s"] =
- &::build2::test::script::cli::thunk< ln_options, bool, &ln_options::symbolic_ >;
- }
- };
-
- static _cli_ln_options_map_init _cli_ln_options_map_init_;
-
- bool ln_options::
- _parse (const char* o, ::build2::test::script::cli::scanner& s)
- {
- _cli_ln_options_map::const_iterator i (_cli_ln_options_map_.find (o));
-
- if (i != _cli_ln_options_map_.end ())
- {
- (*(i->second)) (*this, s);
- return true;
- }
-
- // cleanup_options base
- //
- if (::build2::test::script::cleanup_options::_parse (o, s))
- return true;
-
- return false;
- }
-
- bool ln_options::
- _parse (::build2::test::script::cli::scanner& s,
- ::build2::test::script::cli::unknown_mode opt_mode,
- ::build2::test::script::cli::unknown_mode arg_mode)
- {
- // Can't skip combined flags (--no-combined-flags).
- //
- assert (opt_mode != ::build2::test::script::cli::unknown_mode::skip);
-
- bool r = false;
- bool opt = true;
-
- while (s.more ())
- {
- const char* o = s.peek ();
-
- if (std::strcmp (o, "--") == 0)
- {
- opt = false;
- s.skip ();
- r = true;
- continue;
- }
-
- if (opt)
- {
- if (_parse (o, s))
- {
- r = true;
- continue;
- }
-
- if (std::strncmp (o, "-", 1) == 0 && o[1] != '\0')
- {
- // Handle combined option values.
- //
- std::string co;
- if (const char* v = std::strchr (o, '='))
- {
- co.assign (o, 0, v - o);
- ++v;
-
- int ac (2);
- char* av[] =
- {
- const_cast<char*> (co.c_str ()),
- const_cast<char*> (v)
- };
-
- ::build2::test::script::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::test::script::cli::invalid_value (co, v);
-
- s.next ();
- r = true;
- continue;
- }
- else
- {
- // Set the unknown option and fall through.
- //
- o = co.c_str ();
- }
- }
-
- // Handle combined flags.
- //
- char cf[3];
- {
- const char* p = o + 1;
- for (; *p != '\0'; ++p)
- {
- if (!((*p >= 'a' && *p <= 'z') ||
- (*p >= 'A' && *p <= 'Z') ||
- (*p >= '0' && *p <= '9')))
- break;
- }
-
- if (*p == '\0')
- {
- for (p = o + 1; *p != '\0'; ++p)
- {
- std::strcpy (cf, "-");
- cf[1] = *p;
- cf[2] = '\0';
-
- int ac (1);
- char* av[] =
- {
- cf
- };
-
- ::build2::test::script::cli::argv_scanner ns (0, ac, av);
-
- if (!_parse (cf, ns))
- break;
- }
-
- if (*p == '\0')
- {
- // All handled.
- //
- s.next ();
- r = true;
- continue;
- }
- else
- {
- // Set the unknown option and fall through.
- //
- o = cf;
- }
- }
- }
-
- switch (opt_mode)
- {
- case ::build2::test::script::cli::unknown_mode::skip:
- {
- s.skip ();
- r = true;
- continue;
- }
- case ::build2::test::script::cli::unknown_mode::stop:
- {
- break;
- }
- case ::build2::test::script::cli::unknown_mode::fail:
- {
- throw ::build2::test::script::cli::unknown_option (o);
- }
- }
-
- break;
- }
- }
-
- switch (arg_mode)
- {
- case ::build2::test::script::cli::unknown_mode::skip:
- {
- s.skip ();
- r = true;
- continue;
- }
- case ::build2::test::script::cli::unknown_mode::stop:
- {
- break;
- }
- case ::build2::test::script::cli::unknown_mode::fail:
- {
- throw ::build2::test::script::cli::unknown_argument (o);
- }
- }
-
- break;
- }
-
- return r;
- }
-
- // mkdir_options
- //
-
- mkdir_options::
- mkdir_options ()
- : parents_ ()
- {
- }
-
- mkdir_options::
- mkdir_options (int& argc,
- char** argv,
- bool erase,
- ::build2::test::script::cli::unknown_mode opt,
- ::build2::test::script::cli::unknown_mode arg)
- : parents_ ()
- {
- ::build2::test::script::cli::argv_scanner s (argc, argv, erase);
- _parse (s, opt, arg);
- }
-
- mkdir_options::
- mkdir_options (int start,
- int& argc,
- char** argv,
- bool erase,
- ::build2::test::script::cli::unknown_mode opt,
- ::build2::test::script::cli::unknown_mode arg)
- : parents_ ()
- {
- ::build2::test::script::cli::argv_scanner s (start, argc, argv, erase);
- _parse (s, opt, arg);
- }
-
- mkdir_options::
- mkdir_options (int& argc,
- char** argv,
- int& end,
- bool erase,
- ::build2::test::script::cli::unknown_mode opt,
- ::build2::test::script::cli::unknown_mode arg)
- : parents_ ()
- {
- ::build2::test::script::cli::argv_scanner s (argc, argv, erase);
- _parse (s, opt, arg);
- end = s.end ();
- }
-
- mkdir_options::
- mkdir_options (int start,
- int& argc,
- char** argv,
- int& end,
- bool erase,
- ::build2::test::script::cli::unknown_mode opt,
- ::build2::test::script::cli::unknown_mode arg)
- : parents_ ()
- {
- ::build2::test::script::cli::argv_scanner s (start, argc, argv, erase);
- _parse (s, opt, arg);
- end = s.end ();
- }
-
- mkdir_options::
- mkdir_options (::build2::test::script::cli::scanner& s,
- ::build2::test::script::cli::unknown_mode opt,
- ::build2::test::script::cli::unknown_mode arg)
- : parents_ ()
- {
- _parse (s, opt, arg);
- }
-
- typedef
- std::map<std::string, void (*) (mkdir_options&, ::build2::test::script::cli::scanner&)>
- _cli_mkdir_options_map;
-
- static _cli_mkdir_options_map _cli_mkdir_options_map_;
-
- struct _cli_mkdir_options_map_init
- {
- _cli_mkdir_options_map_init ()
- {
- _cli_mkdir_options_map_["--parents"] =
- &::build2::test::script::cli::thunk< mkdir_options, bool, &mkdir_options::parents_ >;
- _cli_mkdir_options_map_["-p"] =
- &::build2::test::script::cli::thunk< mkdir_options, bool, &mkdir_options::parents_ >;
- }
- };
-
- static _cli_mkdir_options_map_init _cli_mkdir_options_map_init_;
-
- bool mkdir_options::
- _parse (const char* o, ::build2::test::script::cli::scanner& s)
- {
- _cli_mkdir_options_map::const_iterator i (_cli_mkdir_options_map_.find (o));
-
- if (i != _cli_mkdir_options_map_.end ())
- {
- (*(i->second)) (*this, s);
- return true;
- }
-
- // cleanup_options base
- //
- if (::build2::test::script::cleanup_options::_parse (o, s))
- return true;
-
- return false;
- }
-
- bool mkdir_options::
- _parse (::build2::test::script::cli::scanner& s,
- ::build2::test::script::cli::unknown_mode opt_mode,
- ::build2::test::script::cli::unknown_mode arg_mode)
- {
- // Can't skip combined flags (--no-combined-flags).
- //
- assert (opt_mode != ::build2::test::script::cli::unknown_mode::skip);
-
- bool r = false;
- bool opt = true;
-
- while (s.more ())
- {
- const char* o = s.peek ();
-
- if (std::strcmp (o, "--") == 0)
- {
- opt = false;
- s.skip ();
- r = true;
- continue;
- }
-
- if (opt)
- {
- if (_parse (o, s))
- {
- r = true;
- continue;
- }
-
- if (std::strncmp (o, "-", 1) == 0 && o[1] != '\0')
- {
- // Handle combined option values.
- //
- std::string co;
- if (const char* v = std::strchr (o, '='))
- {
- co.assign (o, 0, v - o);
- ++v;
-
- int ac (2);
- char* av[] =
- {
- const_cast<char*> (co.c_str ()),
- const_cast<char*> (v)
- };
-
- ::build2::test::script::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::test::script::cli::invalid_value (co, v);
-
- s.next ();
- r = true;
- continue;
- }
- else
- {
- // Set the unknown option and fall through.
- //
- o = co.c_str ();
- }
- }
-
- // Handle combined flags.
- //
- char cf[3];
- {
- const char* p = o + 1;
- for (; *p != '\0'; ++p)
- {
- if (!((*p >= 'a' && *p <= 'z') ||
- (*p >= 'A' && *p <= 'Z') ||
- (*p >= '0' && *p <= '9')))
- break;
- }
-
- if (*p == '\0')
- {
- for (p = o + 1; *p != '\0'; ++p)
- {
- std::strcpy (cf, "-");
- cf[1] = *p;
- cf[2] = '\0';
-
- int ac (1);
- char* av[] =
- {
- cf
- };
-
- ::build2::test::script::cli::argv_scanner ns (0, ac, av);
-
- if (!_parse (cf, ns))
- break;
- }
-
- if (*p == '\0')
- {
- // All handled.
- //
- s.next ();
- r = true;
- continue;
- }
- else
- {
- // Set the unknown option and fall through.
- //
- o = cf;
- }
- }
- }
-
- switch (opt_mode)
- {
- case ::build2::test::script::cli::unknown_mode::skip:
- {
- s.skip ();
- r = true;
- continue;
- }
- case ::build2::test::script::cli::unknown_mode::stop:
- {
- break;
- }
- case ::build2::test::script::cli::unknown_mode::fail:
- {
- throw ::build2::test::script::cli::unknown_option (o);
- }
- }
-
- break;
- }
- }
-
- switch (arg_mode)
- {
- case ::build2::test::script::cli::unknown_mode::skip:
- {
- s.skip ();
- r = true;
- continue;
- }
- case ::build2::test::script::cli::unknown_mode::stop:
- {
- break;
- }
- case ::build2::test::script::cli::unknown_mode::fail:
- {
- throw ::build2::test::script::cli::unknown_argument (o);
- }
- }
-
- break;
- }
-
- return r;
- }
-
- // mv_options
- //
-
- mv_options::
- mv_options ()
- : force_ ()
- {
- }
-
- mv_options::
- mv_options (int& argc,
- char** argv,
- bool erase,
- ::build2::test::script::cli::unknown_mode opt,
- ::build2::test::script::cli::unknown_mode arg)
- : force_ ()
- {
- ::build2::test::script::cli::argv_scanner s (argc, argv, erase);
- _parse (s, opt, arg);
- }
-
- mv_options::
- mv_options (int start,
- int& argc,
- char** argv,
- bool erase,
- ::build2::test::script::cli::unknown_mode opt,
- ::build2::test::script::cli::unknown_mode arg)
- : force_ ()
- {
- ::build2::test::script::cli::argv_scanner s (start, argc, argv, erase);
- _parse (s, opt, arg);
- }
-
- mv_options::
- mv_options (int& argc,
- char** argv,
- int& end,
- bool erase,
- ::build2::test::script::cli::unknown_mode opt,
- ::build2::test::script::cli::unknown_mode arg)
- : force_ ()
- {
- ::build2::test::script::cli::argv_scanner s (argc, argv, erase);
- _parse (s, opt, arg);
- end = s.end ();
- }
-
- mv_options::
- mv_options (int start,
- int& argc,
- char** argv,
- int& end,
- bool erase,
- ::build2::test::script::cli::unknown_mode opt,
- ::build2::test::script::cli::unknown_mode arg)
- : force_ ()
- {
- ::build2::test::script::cli::argv_scanner s (start, argc, argv, erase);
- _parse (s, opt, arg);
- end = s.end ();
- }
-
- mv_options::
- mv_options (::build2::test::script::cli::scanner& s,
- ::build2::test::script::cli::unknown_mode opt,
- ::build2::test::script::cli::unknown_mode arg)
- : force_ ()
- {
- _parse (s, opt, arg);
- }
-
- typedef
- std::map<std::string, void (*) (mv_options&, ::build2::test::script::cli::scanner&)>
- _cli_mv_options_map;
-
- static _cli_mv_options_map _cli_mv_options_map_;
-
- struct _cli_mv_options_map_init
- {
- _cli_mv_options_map_init ()
- {
- _cli_mv_options_map_["--force"] =
- &::build2::test::script::cli::thunk< mv_options, bool, &mv_options::force_ >;
- _cli_mv_options_map_["-f"] =
- &::build2::test::script::cli::thunk< mv_options, bool, &mv_options::force_ >;
- }
- };
-
- static _cli_mv_options_map_init _cli_mv_options_map_init_;
-
- bool mv_options::
- _parse (const char* o, ::build2::test::script::cli::scanner& s)
- {
- _cli_mv_options_map::const_iterator i (_cli_mv_options_map_.find (o));
-
- if (i != _cli_mv_options_map_.end ())
- {
- (*(i->second)) (*this, s);
- return true;
- }
-
- // cleanup_options base
- //
- if (::build2::test::script::cleanup_options::_parse (o, s))
- return true;
-
- return false;
- }
-
- bool mv_options::
- _parse (::build2::test::script::cli::scanner& s,
- ::build2::test::script::cli::unknown_mode opt_mode,
- ::build2::test::script::cli::unknown_mode arg_mode)
- {
- // Can't skip combined flags (--no-combined-flags).
- //
- assert (opt_mode != ::build2::test::script::cli::unknown_mode::skip);
-
- bool r = false;
- bool opt = true;
-
- while (s.more ())
- {
- const char* o = s.peek ();
-
- if (std::strcmp (o, "--") == 0)
- {
- opt = false;
- s.skip ();
- r = true;
- continue;
- }
-
- if (opt)
- {
- if (_parse (o, s))
- {
- r = true;
- continue;
- }
-
- if (std::strncmp (o, "-", 1) == 0 && o[1] != '\0')
- {
- // Handle combined option values.
- //
- std::string co;
- if (const char* v = std::strchr (o, '='))
- {
- co.assign (o, 0, v - o);
- ++v;
-
- int ac (2);
- char* av[] =
- {
- const_cast<char*> (co.c_str ()),
- const_cast<char*> (v)
- };
-
- ::build2::test::script::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::test::script::cli::invalid_value (co, v);
-
- s.next ();
- r = true;
- continue;
- }
- else
- {
- // Set the unknown option and fall through.
- //
- o = co.c_str ();
- }
- }
-
- // Handle combined flags.
- //
- char cf[3];
- {
- const char* p = o + 1;
- for (; *p != '\0'; ++p)
- {
- if (!((*p >= 'a' && *p <= 'z') ||
- (*p >= 'A' && *p <= 'Z') ||
- (*p >= '0' && *p <= '9')))
- break;
- }
-
- if (*p == '\0')
- {
- for (p = o + 1; *p != '\0'; ++p)
- {
- std::strcpy (cf, "-");
- cf[1] = *p;
- cf[2] = '\0';
-
- int ac (1);
- char* av[] =
- {
- cf
- };
-
- ::build2::test::script::cli::argv_scanner ns (0, ac, av);
-
- if (!_parse (cf, ns))
- break;
- }
-
- if (*p == '\0')
- {
- // All handled.
- //
- s.next ();
- r = true;
- continue;
- }
- else
- {
- // Set the unknown option and fall through.
- //
- o = cf;
- }
- }
- }
-
- switch (opt_mode)
- {
- case ::build2::test::script::cli::unknown_mode::skip:
- {
- s.skip ();
- r = true;
- continue;
- }
- case ::build2::test::script::cli::unknown_mode::stop:
- {
- break;
- }
- case ::build2::test::script::cli::unknown_mode::fail:
- {
- throw ::build2::test::script::cli::unknown_option (o);
- }
- }
-
- break;
- }
- }
-
- switch (arg_mode)
- {
- case ::build2::test::script::cli::unknown_mode::skip:
- {
- s.skip ();
- r = true;
- continue;
- }
- case ::build2::test::script::cli::unknown_mode::stop:
- {
- break;
- }
- case ::build2::test::script::cli::unknown_mode::fail:
- {
- throw ::build2::test::script::cli::unknown_argument (o);
- }
- }
-
- break;
- }
-
- return r;
- }
-
- // rm_options
- //
-
- rm_options::
- rm_options ()
- : recursive_ (),
- force_ ()
- {
- }
-
- rm_options::
- rm_options (int& argc,
- char** argv,
- bool erase,
- ::build2::test::script::cli::unknown_mode opt,
- ::build2::test::script::cli::unknown_mode arg)
- : recursive_ (),
- force_ ()
- {
- ::build2::test::script::cli::argv_scanner s (argc, argv, erase);
- _parse (s, opt, arg);
- }
-
- rm_options::
- rm_options (int start,
- int& argc,
- char** argv,
- bool erase,
- ::build2::test::script::cli::unknown_mode opt,
- ::build2::test::script::cli::unknown_mode arg)
- : recursive_ (),
- force_ ()
- {
- ::build2::test::script::cli::argv_scanner s (start, argc, argv, erase);
- _parse (s, opt, arg);
- }
-
- rm_options::
- rm_options (int& argc,
- char** argv,
- int& end,
- bool erase,
- ::build2::test::script::cli::unknown_mode opt,
- ::build2::test::script::cli::unknown_mode arg)
- : recursive_ (),
- force_ ()
- {
- ::build2::test::script::cli::argv_scanner s (argc, argv, erase);
- _parse (s, opt, arg);
- end = s.end ();
- }
-
- rm_options::
- rm_options (int start,
- int& argc,
- char** argv,
- int& end,
- bool erase,
- ::build2::test::script::cli::unknown_mode opt,
- ::build2::test::script::cli::unknown_mode arg)
- : recursive_ (),
- force_ ()
- {
- ::build2::test::script::cli::argv_scanner s (start, argc, argv, erase);
- _parse (s, opt, arg);
- end = s.end ();
- }
-
- rm_options::
- rm_options (::build2::test::script::cli::scanner& s,
- ::build2::test::script::cli::unknown_mode opt,
- ::build2::test::script::cli::unknown_mode arg)
- : recursive_ (),
- force_ ()
- {
- _parse (s, opt, arg);
- }
-
- typedef
- std::map<std::string, void (*) (rm_options&, ::build2::test::script::cli::scanner&)>
- _cli_rm_options_map;
-
- static _cli_rm_options_map _cli_rm_options_map_;
-
- struct _cli_rm_options_map_init
- {
- _cli_rm_options_map_init ()
- {
- _cli_rm_options_map_["--recursive"] =
- &::build2::test::script::cli::thunk< rm_options, bool, &rm_options::recursive_ >;
- _cli_rm_options_map_["-r"] =
- &::build2::test::script::cli::thunk< rm_options, bool, &rm_options::recursive_ >;
- _cli_rm_options_map_["--force"] =
- &::build2::test::script::cli::thunk< rm_options, bool, &rm_options::force_ >;
- _cli_rm_options_map_["-f"] =
- &::build2::test::script::cli::thunk< rm_options, bool, &rm_options::force_ >;
- }
- };
-
- static _cli_rm_options_map_init _cli_rm_options_map_init_;
-
- bool rm_options::
- _parse (const char* o, ::build2::test::script::cli::scanner& s)
- {
- _cli_rm_options_map::const_iterator i (_cli_rm_options_map_.find (o));
-
- if (i != _cli_rm_options_map_.end ())
- {
- (*(i->second)) (*this, s);
- return true;
- }
-
- return false;
- }
-
- bool rm_options::
- _parse (::build2::test::script::cli::scanner& s,
- ::build2::test::script::cli::unknown_mode opt_mode,
- ::build2::test::script::cli::unknown_mode arg_mode)
- {
- // Can't skip combined flags (--no-combined-flags).
- //
- assert (opt_mode != ::build2::test::script::cli::unknown_mode::skip);
-
- bool r = false;
- bool opt = true;
-
- while (s.more ())
- {
- const char* o = s.peek ();
-
- if (std::strcmp (o, "--") == 0)
- {
- opt = false;
- s.skip ();
- r = true;
- continue;
- }
-
- if (opt)
- {
- if (_parse (o, s))
- {
- r = true;
- continue;
- }
-
- if (std::strncmp (o, "-", 1) == 0 && o[1] != '\0')
- {
- // Handle combined option values.
- //
- std::string co;
- if (const char* v = std::strchr (o, '='))
- {
- co.assign (o, 0, v - o);
- ++v;
-
- int ac (2);
- char* av[] =
- {
- const_cast<char*> (co.c_str ()),
- const_cast<char*> (v)
- };
-
- ::build2::test::script::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::test::script::cli::invalid_value (co, v);
-
- s.next ();
- r = true;
- continue;
- }
- else
- {
- // Set the unknown option and fall through.
- //
- o = co.c_str ();
- }
- }
-
- // Handle combined flags.
- //
- char cf[3];
- {
- const char* p = o + 1;
- for (; *p != '\0'; ++p)
- {
- if (!((*p >= 'a' && *p <= 'z') ||
- (*p >= 'A' && *p <= 'Z') ||
- (*p >= '0' && *p <= '9')))
- break;
- }
-
- if (*p == '\0')
- {
- for (p = o + 1; *p != '\0'; ++p)
- {
- std::strcpy (cf, "-");
- cf[1] = *p;
- cf[2] = '\0';
-
- int ac (1);
- char* av[] =
- {
- cf
- };
-
- ::build2::test::script::cli::argv_scanner ns (0, ac, av);
-
- if (!_parse (cf, ns))
- break;
- }
-
- if (*p == '\0')
- {
- // All handled.
- //
- s.next ();
- r = true;
- continue;
- }
- else
- {
- // Set the unknown option and fall through.
- //
- o = cf;
- }
- }
- }
-
- switch (opt_mode)
- {
- case ::build2::test::script::cli::unknown_mode::skip:
- {
- s.skip ();
- r = true;
- continue;
- }
- case ::build2::test::script::cli::unknown_mode::stop:
- {
- break;
- }
- case ::build2::test::script::cli::unknown_mode::fail:
- {
- throw ::build2::test::script::cli::unknown_option (o);
- }
- }
-
- break;
- }
- }
-
- switch (arg_mode)
- {
- case ::build2::test::script::cli::unknown_mode::skip:
- {
- s.skip ();
- r = true;
- continue;
- }
- case ::build2::test::script::cli::unknown_mode::stop:
- {
- break;
- }
- case ::build2::test::script::cli::unknown_mode::fail:
- {
- throw ::build2::test::script::cli::unknown_argument (o);
- }
- }
-
- break;
- }
-
- return r;
- }
-
- // rmdir_options
- //
-
- rmdir_options::
- rmdir_options ()
- : force_ ()
- {
- }
-
- rmdir_options::
- rmdir_options (int& argc,
- char** argv,
- bool erase,
- ::build2::test::script::cli::unknown_mode opt,
- ::build2::test::script::cli::unknown_mode arg)
- : force_ ()
- {
- ::build2::test::script::cli::argv_scanner s (argc, argv, erase);
- _parse (s, opt, arg);
- }
-
- rmdir_options::
- rmdir_options (int start,
- int& argc,
- char** argv,
- bool erase,
- ::build2::test::script::cli::unknown_mode opt,
- ::build2::test::script::cli::unknown_mode arg)
- : force_ ()
- {
- ::build2::test::script::cli::argv_scanner s (start, argc, argv, erase);
- _parse (s, opt, arg);
- }
-
- rmdir_options::
- rmdir_options (int& argc,
- char** argv,
- int& end,
- bool erase,
- ::build2::test::script::cli::unknown_mode opt,
- ::build2::test::script::cli::unknown_mode arg)
- : force_ ()
- {
- ::build2::test::script::cli::argv_scanner s (argc, argv, erase);
- _parse (s, opt, arg);
- end = s.end ();
- }
-
- rmdir_options::
- rmdir_options (int start,
- int& argc,
- char** argv,
- int& end,
- bool erase,
- ::build2::test::script::cli::unknown_mode opt,
- ::build2::test::script::cli::unknown_mode arg)
- : force_ ()
- {
- ::build2::test::script::cli::argv_scanner s (start, argc, argv, erase);
- _parse (s, opt, arg);
- end = s.end ();
- }
-
- rmdir_options::
- rmdir_options (::build2::test::script::cli::scanner& s,
- ::build2::test::script::cli::unknown_mode opt,
- ::build2::test::script::cli::unknown_mode arg)
- : force_ ()
- {
- _parse (s, opt, arg);
- }
-
- typedef
- std::map<std::string, void (*) (rmdir_options&, ::build2::test::script::cli::scanner&)>
- _cli_rmdir_options_map;
-
- static _cli_rmdir_options_map _cli_rmdir_options_map_;
-
- struct _cli_rmdir_options_map_init
- {
- _cli_rmdir_options_map_init ()
- {
- _cli_rmdir_options_map_["--force"] =
- &::build2::test::script::cli::thunk< rmdir_options, bool, &rmdir_options::force_ >;
- _cli_rmdir_options_map_["-f"] =
- &::build2::test::script::cli::thunk< rmdir_options, bool, &rmdir_options::force_ >;
- }
- };
-
- static _cli_rmdir_options_map_init _cli_rmdir_options_map_init_;
-
- bool rmdir_options::
- _parse (const char* o, ::build2::test::script::cli::scanner& s)
- {
- _cli_rmdir_options_map::const_iterator i (_cli_rmdir_options_map_.find (o));
-
- if (i != _cli_rmdir_options_map_.end ())
- {
- (*(i->second)) (*this, s);
- return true;
- }
-
- return false;
- }
-
- bool rmdir_options::
- _parse (::build2::test::script::cli::scanner& s,
- ::build2::test::script::cli::unknown_mode opt_mode,
- ::build2::test::script::cli::unknown_mode arg_mode)
- {
- // Can't skip combined flags (--no-combined-flags).
- //
- assert (opt_mode != ::build2::test::script::cli::unknown_mode::skip);
-
- bool r = false;
- bool opt = true;
-
- while (s.more ())
- {
- const char* o = s.peek ();
-
- if (std::strcmp (o, "--") == 0)
- {
- opt = false;
- s.skip ();
- r = true;
- continue;
- }
-
- if (opt)
- {
- if (_parse (o, s))
- {
- r = true;
- continue;
- }
-
- if (std::strncmp (o, "-", 1) == 0 && o[1] != '\0')
- {
- // Handle combined option values.
- //
- std::string co;
- if (const char* v = std::strchr (o, '='))
- {
- co.assign (o, 0, v - o);
- ++v;
-
- int ac (2);
- char* av[] =
- {
- const_cast<char*> (co.c_str ()),
- const_cast<char*> (v)
- };
-
- ::build2::test::script::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::test::script::cli::invalid_value (co, v);
-
- s.next ();
- r = true;
- continue;
- }
- else
- {
- // Set the unknown option and fall through.
- //
- o = co.c_str ();
- }
- }
-
- // Handle combined flags.
- //
- char cf[3];
- {
- const char* p = o + 1;
- for (; *p != '\0'; ++p)
- {
- if (!((*p >= 'a' && *p <= 'z') ||
- (*p >= 'A' && *p <= 'Z') ||
- (*p >= '0' && *p <= '9')))
- break;
- }
-
- if (*p == '\0')
- {
- for (p = o + 1; *p != '\0'; ++p)
- {
- std::strcpy (cf, "-");
- cf[1] = *p;
- cf[2] = '\0';
-
- int ac (1);
- char* av[] =
- {
- cf
- };
-
- ::build2::test::script::cli::argv_scanner ns (0, ac, av);
-
- if (!_parse (cf, ns))
- break;
- }
-
- if (*p == '\0')
- {
- // All handled.
- //
- s.next ();
- r = true;
- continue;
- }
- else
- {
- // Set the unknown option and fall through.
- //
- o = cf;
- }
- }
- }
-
- switch (opt_mode)
- {
- case ::build2::test::script::cli::unknown_mode::skip:
- {
- s.skip ();
- r = true;
- continue;
- }
- case ::build2::test::script::cli::unknown_mode::stop:
- {
- break;
- }
- case ::build2::test::script::cli::unknown_mode::fail:
- {
- throw ::build2::test::script::cli::unknown_option (o);
- }
- }
-
- break;
- }
- }
-
- switch (arg_mode)
- {
- case ::build2::test::script::cli::unknown_mode::skip:
- {
- s.skip ();
- r = true;
- continue;
- }
- case ::build2::test::script::cli::unknown_mode::stop:
- {
- break;
- }
- case ::build2::test::script::cli::unknown_mode::fail:
- {
- throw ::build2::test::script::cli::unknown_argument (o);
- }
- }
-
- break;
- }
-
- return r;
- }
-
- // sed_options
- //
-
- sed_options::
- sed_options ()
- : quiet_ (),
- in_place_ (),
- expression_ (),
- expression_specified_ (false)
- {
- }
-
- sed_options::
- sed_options (int& argc,
- char** argv,
- bool erase,
- ::build2::test::script::cli::unknown_mode opt,
- ::build2::test::script::cli::unknown_mode arg)
- : quiet_ (),
- in_place_ (),
- expression_ (),
- expression_specified_ (false)
- {
- ::build2::test::script::cli::argv_scanner s (argc, argv, erase);
- _parse (s, opt, arg);
- }
-
- sed_options::
- sed_options (int start,
- int& argc,
- char** argv,
- bool erase,
- ::build2::test::script::cli::unknown_mode opt,
- ::build2::test::script::cli::unknown_mode arg)
- : quiet_ (),
- in_place_ (),
- expression_ (),
- expression_specified_ (false)
- {
- ::build2::test::script::cli::argv_scanner s (start, argc, argv, erase);
- _parse (s, opt, arg);
- }
-
- sed_options::
- sed_options (int& argc,
- char** argv,
- int& end,
- bool erase,
- ::build2::test::script::cli::unknown_mode opt,
- ::build2::test::script::cli::unknown_mode arg)
- : quiet_ (),
- in_place_ (),
- expression_ (),
- expression_specified_ (false)
- {
- ::build2::test::script::cli::argv_scanner s (argc, argv, erase);
- _parse (s, opt, arg);
- end = s.end ();
- }
-
- sed_options::
- sed_options (int start,
- int& argc,
- char** argv,
- int& end,
- bool erase,
- ::build2::test::script::cli::unknown_mode opt,
- ::build2::test::script::cli::unknown_mode arg)
- : quiet_ (),
- in_place_ (),
- expression_ (),
- expression_specified_ (false)
- {
- ::build2::test::script::cli::argv_scanner s (start, argc, argv, erase);
- _parse (s, opt, arg);
- end = s.end ();
- }
-
- sed_options::
- sed_options (::build2::test::script::cli::scanner& s,
- ::build2::test::script::cli::unknown_mode opt,
- ::build2::test::script::cli::unknown_mode arg)
- : quiet_ (),
- in_place_ (),
- expression_ (),
- expression_specified_ (false)
- {
- _parse (s, opt, arg);
- }
-
- typedef
- std::map<std::string, void (*) (sed_options&, ::build2::test::script::cli::scanner&)>
- _cli_sed_options_map;
-
- static _cli_sed_options_map _cli_sed_options_map_;
-
- struct _cli_sed_options_map_init
- {
- _cli_sed_options_map_init ()
- {
- _cli_sed_options_map_["--quiet"] =
- &::build2::test::script::cli::thunk< sed_options, bool, &sed_options::quiet_ >;
- _cli_sed_options_map_["-n"] =
- &::build2::test::script::cli::thunk< sed_options, bool, &sed_options::quiet_ >;
- _cli_sed_options_map_["--in-place"] =
- &::build2::test::script::cli::thunk< sed_options, bool, &sed_options::in_place_ >;
- _cli_sed_options_map_["-i"] =
- &::build2::test::script::cli::thunk< sed_options, bool, &sed_options::in_place_ >;
- _cli_sed_options_map_["--expression"] =
- &::build2::test::script::cli::thunk< sed_options, strings, &sed_options::expression_,
- &sed_options::expression_specified_ >;
- _cli_sed_options_map_["-e"] =
- &::build2::test::script::cli::thunk< sed_options, strings, &sed_options::expression_,
- &sed_options::expression_specified_ >;
- }
- };
-
- static _cli_sed_options_map_init _cli_sed_options_map_init_;
-
- bool sed_options::
- _parse (const char* o, ::build2::test::script::cli::scanner& s)
- {
- _cli_sed_options_map::const_iterator i (_cli_sed_options_map_.find (o));
-
- if (i != _cli_sed_options_map_.end ())
- {
- (*(i->second)) (*this, s);
- return true;
- }
-
- return false;
- }
-
- bool sed_options::
- _parse (::build2::test::script::cli::scanner& s,
- ::build2::test::script::cli::unknown_mode opt_mode,
- ::build2::test::script::cli::unknown_mode arg_mode)
- {
- // Can't skip combined flags (--no-combined-flags).
- //
- assert (opt_mode != ::build2::test::script::cli::unknown_mode::skip);
-
- bool r = false;
- bool opt = true;
-
- while (s.more ())
- {
- const char* o = s.peek ();
-
- if (std::strcmp (o, "--") == 0)
- {
- opt = false;
- s.skip ();
- r = true;
- continue;
- }
-
- if (opt)
- {
- if (_parse (o, s))
- {
- r = true;
- continue;
- }
-
- if (std::strncmp (o, "-", 1) == 0 && o[1] != '\0')
- {
- // Handle combined option values.
- //
- std::string co;
- if (const char* v = std::strchr (o, '='))
- {
- co.assign (o, 0, v - o);
- ++v;
-
- int ac (2);
- char* av[] =
- {
- const_cast<char*> (co.c_str ()),
- const_cast<char*> (v)
- };
-
- ::build2::test::script::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::test::script::cli::invalid_value (co, v);
-
- s.next ();
- r = true;
- continue;
- }
- else
- {
- // Set the unknown option and fall through.
- //
- o = co.c_str ();
- }
- }
-
- // Handle combined flags.
- //
- char cf[3];
- {
- const char* p = o + 1;
- for (; *p != '\0'; ++p)
- {
- if (!((*p >= 'a' && *p <= 'z') ||
- (*p >= 'A' && *p <= 'Z') ||
- (*p >= '0' && *p <= '9')))
- break;
- }
-
- if (*p == '\0')
- {
- for (p = o + 1; *p != '\0'; ++p)
- {
- std::strcpy (cf, "-");
- cf[1] = *p;
- cf[2] = '\0';
-
- int ac (1);
- char* av[] =
- {
- cf
- };
-
- ::build2::test::script::cli::argv_scanner ns (0, ac, av);
-
- if (!_parse (cf, ns))
- break;
- }
-
- if (*p == '\0')
- {
- // All handled.
- //
- s.next ();
- r = true;
- continue;
- }
- else
- {
- // Set the unknown option and fall through.
- //
- o = cf;
- }
- }
- }
-
- switch (opt_mode)
- {
- case ::build2::test::script::cli::unknown_mode::skip:
- {
- s.skip ();
- r = true;
- continue;
- }
- case ::build2::test::script::cli::unknown_mode::stop:
- {
- break;
- }
- case ::build2::test::script::cli::unknown_mode::fail:
- {
- throw ::build2::test::script::cli::unknown_option (o);
- }
- }
-
- break;
- }
- }
-
- switch (arg_mode)
- {
- case ::build2::test::script::cli::unknown_mode::skip:
- {
- s.skip ();
- r = true;
- continue;
- }
- case ::build2::test::script::cli::unknown_mode::stop:
- {
- break;
- }
- case ::build2::test::script::cli::unknown_mode::fail:
- {
- throw ::build2::test::script::cli::unknown_argument (o);
- }
- }
-
- break;
- }
-
- return r;
- }
-
// set_options
//
@@ -2924,829 +656,6 @@ namespace build2
return r;
}
-
- // sleep_options
- //
-
- sleep_options::
- sleep_options ()
- {
- }
-
- sleep_options::
- sleep_options (int& argc,
- char** argv,
- bool erase,
- ::build2::test::script::cli::unknown_mode opt,
- ::build2::test::script::cli::unknown_mode arg)
- {
- ::build2::test::script::cli::argv_scanner s (argc, argv, erase);
- _parse (s, opt, arg);
- }
-
- sleep_options::
- sleep_options (int start,
- int& argc,
- char** argv,
- bool erase,
- ::build2::test::script::cli::unknown_mode opt,
- ::build2::test::script::cli::unknown_mode arg)
- {
- ::build2::test::script::cli::argv_scanner s (start, argc, argv, erase);
- _parse (s, opt, arg);
- }
-
- sleep_options::
- sleep_options (int& argc,
- char** argv,
- int& end,
- bool erase,
- ::build2::test::script::cli::unknown_mode opt,
- ::build2::test::script::cli::unknown_mode arg)
- {
- ::build2::test::script::cli::argv_scanner s (argc, argv, erase);
- _parse (s, opt, arg);
- end = s.end ();
- }
-
- sleep_options::
- sleep_options (int start,
- int& argc,
- char** argv,
- int& end,
- bool erase,
- ::build2::test::script::cli::unknown_mode opt,
- ::build2::test::script::cli::unknown_mode arg)
- {
- ::build2::test::script::cli::argv_scanner s (start, argc, argv, erase);
- _parse (s, opt, arg);
- end = s.end ();
- }
-
- sleep_options::
- sleep_options (::build2::test::script::cli::scanner& s,
- ::build2::test::script::cli::unknown_mode opt,
- ::build2::test::script::cli::unknown_mode arg)
- {
- _parse (s, opt, arg);
- }
-
- typedef
- std::map<std::string, void (*) (sleep_options&, ::build2::test::script::cli::scanner&)>
- _cli_sleep_options_map;
-
- static _cli_sleep_options_map _cli_sleep_options_map_;
-
- struct _cli_sleep_options_map_init
- {
- _cli_sleep_options_map_init ()
- {
- }
- };
-
- static _cli_sleep_options_map_init _cli_sleep_options_map_init_;
-
- bool sleep_options::
- _parse (const char* o, ::build2::test::script::cli::scanner& s)
- {
- _cli_sleep_options_map::const_iterator i (_cli_sleep_options_map_.find (o));
-
- if (i != _cli_sleep_options_map_.end ())
- {
- (*(i->second)) (*this, s);
- return true;
- }
-
- return false;
- }
-
- bool sleep_options::
- _parse (::build2::test::script::cli::scanner& s,
- ::build2::test::script::cli::unknown_mode opt_mode,
- ::build2::test::script::cli::unknown_mode arg_mode)
- {
- // Can't skip combined flags (--no-combined-flags).
- //
- assert (opt_mode != ::build2::test::script::cli::unknown_mode::skip);
-
- bool r = false;
- bool opt = true;
-
- while (s.more ())
- {
- const char* o = s.peek ();
-
- if (std::strcmp (o, "--") == 0)
- {
- opt = false;
- s.skip ();
- r = true;
- continue;
- }
-
- if (opt)
- {
- if (_parse (o, s))
- {
- r = true;
- continue;
- }
-
- if (std::strncmp (o, "-", 1) == 0 && o[1] != '\0')
- {
- // Handle combined option values.
- //
- std::string co;
- if (const char* v = std::strchr (o, '='))
- {
- co.assign (o, 0, v - o);
- ++v;
-
- int ac (2);
- char* av[] =
- {
- const_cast<char*> (co.c_str ()),
- const_cast<char*> (v)
- };
-
- ::build2::test::script::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::test::script::cli::invalid_value (co, v);
-
- s.next ();
- r = true;
- continue;
- }
- else
- {
- // Set the unknown option and fall through.
- //
- o = co.c_str ();
- }
- }
-
- // Handle combined flags.
- //
- char cf[3];
- {
- const char* p = o + 1;
- for (; *p != '\0'; ++p)
- {
- if (!((*p >= 'a' && *p <= 'z') ||
- (*p >= 'A' && *p <= 'Z') ||
- (*p >= '0' && *p <= '9')))
- break;
- }
-
- if (*p == '\0')
- {
- for (p = o + 1; *p != '\0'; ++p)
- {
- std::strcpy (cf, "-");
- cf[1] = *p;
- cf[2] = '\0';
-
- int ac (1);
- char* av[] =
- {
- cf
- };
-
- ::build2::test::script::cli::argv_scanner ns (0, ac, av);
-
- if (!_parse (cf, ns))
- break;
- }
-
- if (*p == '\0')
- {
- // All handled.
- //
- s.next ();
- r = true;
- continue;
- }
- else
- {
- // Set the unknown option and fall through.
- //
- o = cf;
- }
- }
- }
-
- switch (opt_mode)
- {
- case ::build2::test::script::cli::unknown_mode::skip:
- {
- s.skip ();
- r = true;
- continue;
- }
- case ::build2::test::script::cli::unknown_mode::stop:
- {
- break;
- }
- case ::build2::test::script::cli::unknown_mode::fail:
- {
- throw ::build2::test::script::cli::unknown_option (o);
- }
- }
-
- break;
- }
- }
-
- switch (arg_mode)
- {
- case ::build2::test::script::cli::unknown_mode::skip:
- {
- s.skip ();
- r = true;
- continue;
- }
- case ::build2::test::script::cli::unknown_mode::stop:
- {
- break;
- }
- case ::build2::test::script::cli::unknown_mode::fail:
- {
- throw ::build2::test::script::cli::unknown_argument (o);
- }
- }
-
- break;
- }
-
- return r;
- }
-
- // test_options
- //
-
- test_options::
- test_options ()
- : file_ (),
- directory_ ()
- {
- }
-
- test_options::
- test_options (int& argc,
- char** argv,
- bool erase,
- ::build2::test::script::cli::unknown_mode opt,
- ::build2::test::script::cli::unknown_mode arg)
- : file_ (),
- directory_ ()
- {
- ::build2::test::script::cli::argv_scanner s (argc, argv, erase);
- _parse (s, opt, arg);
- }
-
- test_options::
- test_options (int start,
- int& argc,
- char** argv,
- bool erase,
- ::build2::test::script::cli::unknown_mode opt,
- ::build2::test::script::cli::unknown_mode arg)
- : file_ (),
- directory_ ()
- {
- ::build2::test::script::cli::argv_scanner s (start, argc, argv, erase);
- _parse (s, opt, arg);
- }
-
- test_options::
- test_options (int& argc,
- char** argv,
- int& end,
- bool erase,
- ::build2::test::script::cli::unknown_mode opt,
- ::build2::test::script::cli::unknown_mode arg)
- : file_ (),
- directory_ ()
- {
- ::build2::test::script::cli::argv_scanner s (argc, argv, erase);
- _parse (s, opt, arg);
- end = s.end ();
- }
-
- test_options::
- test_options (int start,
- int& argc,
- char** argv,
- int& end,
- bool erase,
- ::build2::test::script::cli::unknown_mode opt,
- ::build2::test::script::cli::unknown_mode arg)
- : file_ (),
- directory_ ()
- {
- ::build2::test::script::cli::argv_scanner s (start, argc, argv, erase);
- _parse (s, opt, arg);
- end = s.end ();
- }
-
- test_options::
- test_options (::build2::test::script::cli::scanner& s,
- ::build2::test::script::cli::unknown_mode opt,
- ::build2::test::script::cli::unknown_mode arg)
- : file_ (),
- directory_ ()
- {
- _parse (s, opt, arg);
- }
-
- typedef
- std::map<std::string, void (*) (test_options&, ::build2::test::script::cli::scanner&)>
- _cli_test_options_map;
-
- static _cli_test_options_map _cli_test_options_map_;
-
- struct _cli_test_options_map_init
- {
- _cli_test_options_map_init ()
- {
- _cli_test_options_map_["--file"] =
- &::build2::test::script::cli::thunk< test_options, bool, &test_options::file_ >;
- _cli_test_options_map_["-f"] =
- &::build2::test::script::cli::thunk< test_options, bool, &test_options::file_ >;
- _cli_test_options_map_["--directory"] =
- &::build2::test::script::cli::thunk< test_options, bool, &test_options::directory_ >;
- _cli_test_options_map_["-d"] =
- &::build2::test::script::cli::thunk< test_options, bool, &test_options::directory_ >;
- }
- };
-
- static _cli_test_options_map_init _cli_test_options_map_init_;
-
- bool test_options::
- _parse (const char* o, ::build2::test::script::cli::scanner& s)
- {
- _cli_test_options_map::const_iterator i (_cli_test_options_map_.find (o));
-
- if (i != _cli_test_options_map_.end ())
- {
- (*(i->second)) (*this, s);
- return true;
- }
-
- return false;
- }
-
- bool test_options::
- _parse (::build2::test::script::cli::scanner& s,
- ::build2::test::script::cli::unknown_mode opt_mode,
- ::build2::test::script::cli::unknown_mode arg_mode)
- {
- // Can't skip combined flags (--no-combined-flags).
- //
- assert (opt_mode != ::build2::test::script::cli::unknown_mode::skip);
-
- bool r = false;
- bool opt = true;
-
- while (s.more ())
- {
- const char* o = s.peek ();
-
- if (std::strcmp (o, "--") == 0)
- {
- opt = false;
- s.skip ();
- r = true;
- continue;
- }
-
- if (opt)
- {
- if (_parse (o, s))
- {
- r = true;
- continue;
- }
-
- if (std::strncmp (o, "-", 1) == 0 && o[1] != '\0')
- {
- // Handle combined option values.
- //
- std::string co;
- if (const char* v = std::strchr (o, '='))
- {
- co.assign (o, 0, v - o);
- ++v;
-
- int ac (2);
- char* av[] =
- {
- const_cast<char*> (co.c_str ()),
- const_cast<char*> (v)
- };
-
- ::build2::test::script::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::test::script::cli::invalid_value (co, v);
-
- s.next ();
- r = true;
- continue;
- }
- else
- {
- // Set the unknown option and fall through.
- //
- o = co.c_str ();
- }
- }
-
- // Handle combined flags.
- //
- char cf[3];
- {
- const char* p = o + 1;
- for (; *p != '\0'; ++p)
- {
- if (!((*p >= 'a' && *p <= 'z') ||
- (*p >= 'A' && *p <= 'Z') ||
- (*p >= '0' && *p <= '9')))
- break;
- }
-
- if (*p == '\0')
- {
- for (p = o + 1; *p != '\0'; ++p)
- {
- std::strcpy (cf, "-");
- cf[1] = *p;
- cf[2] = '\0';
-
- int ac (1);
- char* av[] =
- {
- cf
- };
-
- ::build2::test::script::cli::argv_scanner ns (0, ac, av);
-
- if (!_parse (cf, ns))
- break;
- }
-
- if (*p == '\0')
- {
- // All handled.
- //
- s.next ();
- r = true;
- continue;
- }
- else
- {
- // Set the unknown option and fall through.
- //
- o = cf;
- }
- }
- }
-
- switch (opt_mode)
- {
- case ::build2::test::script::cli::unknown_mode::skip:
- {
- s.skip ();
- r = true;
- continue;
- }
- case ::build2::test::script::cli::unknown_mode::stop:
- {
- break;
- }
- case ::build2::test::script::cli::unknown_mode::fail:
- {
- throw ::build2::test::script::cli::unknown_option (o);
- }
- }
-
- break;
- }
- }
-
- switch (arg_mode)
- {
- case ::build2::test::script::cli::unknown_mode::skip:
- {
- s.skip ();
- r = true;
- continue;
- }
- case ::build2::test::script::cli::unknown_mode::stop:
- {
- break;
- }
- case ::build2::test::script::cli::unknown_mode::fail:
- {
- throw ::build2::test::script::cli::unknown_argument (o);
- }
- }
-
- break;
- }
-
- return r;
- }
-
- // touch_options
- //
-
- touch_options::
- touch_options ()
- : after_ (),
- after_specified_ (false)
- {
- }
-
- touch_options::
- touch_options (int& argc,
- char** argv,
- bool erase,
- ::build2::test::script::cli::unknown_mode opt,
- ::build2::test::script::cli::unknown_mode arg)
- : after_ (),
- after_specified_ (false)
- {
- ::build2::test::script::cli::argv_scanner s (argc, argv, erase);
- _parse (s, opt, arg);
- }
-
- touch_options::
- touch_options (int start,
- int& argc,
- char** argv,
- bool erase,
- ::build2::test::script::cli::unknown_mode opt,
- ::build2::test::script::cli::unknown_mode arg)
- : after_ (),
- after_specified_ (false)
- {
- ::build2::test::script::cli::argv_scanner s (start, argc, argv, erase);
- _parse (s, opt, arg);
- }
-
- touch_options::
- touch_options (int& argc,
- char** argv,
- int& end,
- bool erase,
- ::build2::test::script::cli::unknown_mode opt,
- ::build2::test::script::cli::unknown_mode arg)
- : after_ (),
- after_specified_ (false)
- {
- ::build2::test::script::cli::argv_scanner s (argc, argv, erase);
- _parse (s, opt, arg);
- end = s.end ();
- }
-
- touch_options::
- touch_options (int start,
- int& argc,
- char** argv,
- int& end,
- bool erase,
- ::build2::test::script::cli::unknown_mode opt,
- ::build2::test::script::cli::unknown_mode arg)
- : after_ (),
- after_specified_ (false)
- {
- ::build2::test::script::cli::argv_scanner s (start, argc, argv, erase);
- _parse (s, opt, arg);
- end = s.end ();
- }
-
- touch_options::
- touch_options (::build2::test::script::cli::scanner& s,
- ::build2::test::script::cli::unknown_mode opt,
- ::build2::test::script::cli::unknown_mode arg)
- : after_ (),
- after_specified_ (false)
- {
- _parse (s, opt, arg);
- }
-
- typedef
- std::map<std::string, void (*) (touch_options&, ::build2::test::script::cli::scanner&)>
- _cli_touch_options_map;
-
- static _cli_touch_options_map _cli_touch_options_map_;
-
- struct _cli_touch_options_map_init
- {
- _cli_touch_options_map_init ()
- {
- _cli_touch_options_map_["--after"] =
- &::build2::test::script::cli::thunk< touch_options, string, &touch_options::after_,
- &touch_options::after_specified_ >;
- }
- };
-
- static _cli_touch_options_map_init _cli_touch_options_map_init_;
-
- bool touch_options::
- _parse (const char* o, ::build2::test::script::cli::scanner& s)
- {
- _cli_touch_options_map::const_iterator i (_cli_touch_options_map_.find (o));
-
- if (i != _cli_touch_options_map_.end ())
- {
- (*(i->second)) (*this, s);
- return true;
- }
-
- // cleanup_options base
- //
- if (::build2::test::script::cleanup_options::_parse (o, s))
- return true;
-
- return false;
- }
-
- bool touch_options::
- _parse (::build2::test::script::cli::scanner& s,
- ::build2::test::script::cli::unknown_mode opt_mode,
- ::build2::test::script::cli::unknown_mode arg_mode)
- {
- // Can't skip combined flags (--no-combined-flags).
- //
- assert (opt_mode != ::build2::test::script::cli::unknown_mode::skip);
-
- bool r = false;
- bool opt = true;
-
- while (s.more ())
- {
- const char* o = s.peek ();
-
- if (std::strcmp (o, "--") == 0)
- {
- opt = false;
- s.skip ();
- r = true;
- continue;
- }
-
- if (opt)
- {
- if (_parse (o, s))
- {
- r = true;
- continue;
- }
-
- if (std::strncmp (o, "-", 1) == 0 && o[1] != '\0')
- {
- // Handle combined option values.
- //
- std::string co;
- if (const char* v = std::strchr (o, '='))
- {
- co.assign (o, 0, v - o);
- ++v;
-
- int ac (2);
- char* av[] =
- {
- const_cast<char*> (co.c_str ()),
- const_cast<char*> (v)
- };
-
- ::build2::test::script::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::test::script::cli::invalid_value (co, v);
-
- s.next ();
- r = true;
- continue;
- }
- else
- {
- // Set the unknown option and fall through.
- //
- o = co.c_str ();
- }
- }
-
- // Handle combined flags.
- //
- char cf[3];
- {
- const char* p = o + 1;
- for (; *p != '\0'; ++p)
- {
- if (!((*p >= 'a' && *p <= 'z') ||
- (*p >= 'A' && *p <= 'Z') ||
- (*p >= '0' && *p <= '9')))
- break;
- }
-
- if (*p == '\0')
- {
- for (p = o + 1; *p != '\0'; ++p)
- {
- std::strcpy (cf, "-");
- cf[1] = *p;
- cf[2] = '\0';
-
- int ac (1);
- char* av[] =
- {
- cf
- };
-
- ::build2::test::script::cli::argv_scanner ns (0, ac, av);
-
- if (!_parse (cf, ns))
- break;
- }
-
- if (*p == '\0')
- {
- // All handled.
- //
- s.next ();
- r = true;
- continue;
- }
- else
- {
- // Set the unknown option and fall through.
- //
- o = cf;
- }
- }
- }
-
- switch (opt_mode)
- {
- case ::build2::test::script::cli::unknown_mode::skip:
- {
- s.skip ();
- r = true;
- continue;
- }
- case ::build2::test::script::cli::unknown_mode::stop:
- {
- break;
- }
- case ::build2::test::script::cli::unknown_mode::fail:
- {
- throw ::build2::test::script::cli::unknown_option (o);
- }
- }
-
- break;
- }
- }
-
- switch (arg_mode)
- {
- case ::build2::test::script::cli::unknown_mode::skip:
- {
- s.skip ();
- r = true;
- continue;
- }
- case ::build2::test::script::cli::unknown_mode::stop:
- {
- break;
- }
- case ::build2::test::script::cli::unknown_mode::fail:
- {
- throw ::build2::test::script::cli::unknown_argument (o);
- }
- }
-
- break;
- }
-
- return r;
- }
}
}
}
diff --git a/libbuild2/test/script/builtin-options.hxx b/libbuild2/test/script/builtin-options.hxx
index 7ff0bac..44e129a 100644
--- a/libbuild2/test/script/builtin-options.hxx
+++ b/libbuild2/test/script/builtin-options.hxx
@@ -260,514 +260,12 @@ namespace build2
}
}
-#include <libbuild2/types.hxx>
-
namespace build2
{
namespace test
{
namespace script
{
- class cleanup_options
- {
- public:
- // Option accessors.
- //
- const bool&
- no_cleanup () const;
-
- // Implementation details.
- //
- protected:
- cleanup_options ();
-
- bool
- _parse (const char*, ::build2::test::script::cli::scanner&);
-
- public:
- bool no_cleanup_;
- };
-
- class cat_options
- {
- public:
- cat_options ();
-
- cat_options (int& argc,
- char** argv,
- bool erase = false,
- ::build2::test::script::cli::unknown_mode option = ::build2::test::script::cli::unknown_mode::fail,
- ::build2::test::script::cli::unknown_mode argument = ::build2::test::script::cli::unknown_mode::stop);
-
- cat_options (int start,
- int& argc,
- char** argv,
- bool erase = false,
- ::build2::test::script::cli::unknown_mode option = ::build2::test::script::cli::unknown_mode::fail,
- ::build2::test::script::cli::unknown_mode argument = ::build2::test::script::cli::unknown_mode::stop);
-
- cat_options (int& argc,
- char** argv,
- int& end,
- bool erase = false,
- ::build2::test::script::cli::unknown_mode option = ::build2::test::script::cli::unknown_mode::fail,
- ::build2::test::script::cli::unknown_mode argument = ::build2::test::script::cli::unknown_mode::stop);
-
- cat_options (int start,
- int& argc,
- char** argv,
- int& end,
- bool erase = false,
- ::build2::test::script::cli::unknown_mode option = ::build2::test::script::cli::unknown_mode::fail,
- ::build2::test::script::cli::unknown_mode argument = ::build2::test::script::cli::unknown_mode::stop);
-
- cat_options (::build2::test::script::cli::scanner&,
- ::build2::test::script::cli::unknown_mode option = ::build2::test::script::cli::unknown_mode::fail,
- ::build2::test::script::cli::unknown_mode argument = ::build2::test::script::cli::unknown_mode::stop);
-
- // Option accessors.
- //
- // Implementation details.
- //
- protected:
- bool
- _parse (const char*, ::build2::test::script::cli::scanner&);
-
- private:
- bool
- _parse (::build2::test::script::cli::scanner&,
- ::build2::test::script::cli::unknown_mode option,
- ::build2::test::script::cli::unknown_mode argument);
-
- public:
- };
-
- class cp_options: public ::build2::test::script::cleanup_options
- {
- public:
- cp_options ();
-
- cp_options (int& argc,
- char** argv,
- bool erase = false,
- ::build2::test::script::cli::unknown_mode option = ::build2::test::script::cli::unknown_mode::fail,
- ::build2::test::script::cli::unknown_mode argument = ::build2::test::script::cli::unknown_mode::stop);
-
- cp_options (int start,
- int& argc,
- char** argv,
- bool erase = false,
- ::build2::test::script::cli::unknown_mode option = ::build2::test::script::cli::unknown_mode::fail,
- ::build2::test::script::cli::unknown_mode argument = ::build2::test::script::cli::unknown_mode::stop);
-
- cp_options (int& argc,
- char** argv,
- int& end,
- bool erase = false,
- ::build2::test::script::cli::unknown_mode option = ::build2::test::script::cli::unknown_mode::fail,
- ::build2::test::script::cli::unknown_mode argument = ::build2::test::script::cli::unknown_mode::stop);
-
- cp_options (int start,
- int& argc,
- char** argv,
- int& end,
- bool erase = false,
- ::build2::test::script::cli::unknown_mode option = ::build2::test::script::cli::unknown_mode::fail,
- ::build2::test::script::cli::unknown_mode argument = ::build2::test::script::cli::unknown_mode::stop);
-
- cp_options (::build2::test::script::cli::scanner&,
- ::build2::test::script::cli::unknown_mode option = ::build2::test::script::cli::unknown_mode::fail,
- ::build2::test::script::cli::unknown_mode argument = ::build2::test::script::cli::unknown_mode::stop);
-
- // Option accessors.
- //
- const bool&
- recursive () const;
-
- const bool&
- preserve () const;
-
- // Implementation details.
- //
- protected:
- bool
- _parse (const char*, ::build2::test::script::cli::scanner&);
-
- private:
- bool
- _parse (::build2::test::script::cli::scanner&,
- ::build2::test::script::cli::unknown_mode option,
- ::build2::test::script::cli::unknown_mode argument);
-
- public:
- bool recursive_;
- bool preserve_;
- };
-
- class ln_options: public ::build2::test::script::cleanup_options
- {
- public:
- ln_options ();
-
- ln_options (int& argc,
- char** argv,
- bool erase = false,
- ::build2::test::script::cli::unknown_mode option = ::build2::test::script::cli::unknown_mode::fail,
- ::build2::test::script::cli::unknown_mode argument = ::build2::test::script::cli::unknown_mode::stop);
-
- ln_options (int start,
- int& argc,
- char** argv,
- bool erase = false,
- ::build2::test::script::cli::unknown_mode option = ::build2::test::script::cli::unknown_mode::fail,
- ::build2::test::script::cli::unknown_mode argument = ::build2::test::script::cli::unknown_mode::stop);
-
- ln_options (int& argc,
- char** argv,
- int& end,
- bool erase = false,
- ::build2::test::script::cli::unknown_mode option = ::build2::test::script::cli::unknown_mode::fail,
- ::build2::test::script::cli::unknown_mode argument = ::build2::test::script::cli::unknown_mode::stop);
-
- ln_options (int start,
- int& argc,
- char** argv,
- int& end,
- bool erase = false,
- ::build2::test::script::cli::unknown_mode option = ::build2::test::script::cli::unknown_mode::fail,
- ::build2::test::script::cli::unknown_mode argument = ::build2::test::script::cli::unknown_mode::stop);
-
- ln_options (::build2::test::script::cli::scanner&,
- ::build2::test::script::cli::unknown_mode option = ::build2::test::script::cli::unknown_mode::fail,
- ::build2::test::script::cli::unknown_mode argument = ::build2::test::script::cli::unknown_mode::stop);
-
- // Option accessors.
- //
- const bool&
- symbolic () const;
-
- // Implementation details.
- //
- protected:
- bool
- _parse (const char*, ::build2::test::script::cli::scanner&);
-
- private:
- bool
- _parse (::build2::test::script::cli::scanner&,
- ::build2::test::script::cli::unknown_mode option,
- ::build2::test::script::cli::unknown_mode argument);
-
- public:
- bool symbolic_;
- };
-
- class mkdir_options: public ::build2::test::script::cleanup_options
- {
- public:
- mkdir_options ();
-
- mkdir_options (int& argc,
- char** argv,
- bool erase = false,
- ::build2::test::script::cli::unknown_mode option = ::build2::test::script::cli::unknown_mode::fail,
- ::build2::test::script::cli::unknown_mode argument = ::build2::test::script::cli::unknown_mode::stop);
-
- mkdir_options (int start,
- int& argc,
- char** argv,
- bool erase = false,
- ::build2::test::script::cli::unknown_mode option = ::build2::test::script::cli::unknown_mode::fail,
- ::build2::test::script::cli::unknown_mode argument = ::build2::test::script::cli::unknown_mode::stop);
-
- mkdir_options (int& argc,
- char** argv,
- int& end,
- bool erase = false,
- ::build2::test::script::cli::unknown_mode option = ::build2::test::script::cli::unknown_mode::fail,
- ::build2::test::script::cli::unknown_mode argument = ::build2::test::script::cli::unknown_mode::stop);
-
- mkdir_options (int start,
- int& argc,
- char** argv,
- int& end,
- bool erase = false,
- ::build2::test::script::cli::unknown_mode option = ::build2::test::script::cli::unknown_mode::fail,
- ::build2::test::script::cli::unknown_mode argument = ::build2::test::script::cli::unknown_mode::stop);
-
- mkdir_options (::build2::test::script::cli::scanner&,
- ::build2::test::script::cli::unknown_mode option = ::build2::test::script::cli::unknown_mode::fail,
- ::build2::test::script::cli::unknown_mode argument = ::build2::test::script::cli::unknown_mode::stop);
-
- // Option accessors.
- //
- const bool&
- parents () const;
-
- // Implementation details.
- //
- protected:
- bool
- _parse (const char*, ::build2::test::script::cli::scanner&);
-
- private:
- bool
- _parse (::build2::test::script::cli::scanner&,
- ::build2::test::script::cli::unknown_mode option,
- ::build2::test::script::cli::unknown_mode argument);
-
- public:
- bool parents_;
- };
-
- class mv_options: public ::build2::test::script::cleanup_options
- {
- public:
- mv_options ();
-
- mv_options (int& argc,
- char** argv,
- bool erase = false,
- ::build2::test::script::cli::unknown_mode option = ::build2::test::script::cli::unknown_mode::fail,
- ::build2::test::script::cli::unknown_mode argument = ::build2::test::script::cli::unknown_mode::stop);
-
- mv_options (int start,
- int& argc,
- char** argv,
- bool erase = false,
- ::build2::test::script::cli::unknown_mode option = ::build2::test::script::cli::unknown_mode::fail,
- ::build2::test::script::cli::unknown_mode argument = ::build2::test::script::cli::unknown_mode::stop);
-
- mv_options (int& argc,
- char** argv,
- int& end,
- bool erase = false,
- ::build2::test::script::cli::unknown_mode option = ::build2::test::script::cli::unknown_mode::fail,
- ::build2::test::script::cli::unknown_mode argument = ::build2::test::script::cli::unknown_mode::stop);
-
- mv_options (int start,
- int& argc,
- char** argv,
- int& end,
- bool erase = false,
- ::build2::test::script::cli::unknown_mode option = ::build2::test::script::cli::unknown_mode::fail,
- ::build2::test::script::cli::unknown_mode argument = ::build2::test::script::cli::unknown_mode::stop);
-
- mv_options (::build2::test::script::cli::scanner&,
- ::build2::test::script::cli::unknown_mode option = ::build2::test::script::cli::unknown_mode::fail,
- ::build2::test::script::cli::unknown_mode argument = ::build2::test::script::cli::unknown_mode::stop);
-
- // Option accessors.
- //
- const bool&
- force () const;
-
- // Implementation details.
- //
- protected:
- bool
- _parse (const char*, ::build2::test::script::cli::scanner&);
-
- private:
- bool
- _parse (::build2::test::script::cli::scanner&,
- ::build2::test::script::cli::unknown_mode option,
- ::build2::test::script::cli::unknown_mode argument);
-
- public:
- bool force_;
- };
-
- class rm_options
- {
- public:
- rm_options ();
-
- rm_options (int& argc,
- char** argv,
- bool erase = false,
- ::build2::test::script::cli::unknown_mode option = ::build2::test::script::cli::unknown_mode::fail,
- ::build2::test::script::cli::unknown_mode argument = ::build2::test::script::cli::unknown_mode::stop);
-
- rm_options (int start,
- int& argc,
- char** argv,
- bool erase = false,
- ::build2::test::script::cli::unknown_mode option = ::build2::test::script::cli::unknown_mode::fail,
- ::build2::test::script::cli::unknown_mode argument = ::build2::test::script::cli::unknown_mode::stop);
-
- rm_options (int& argc,
- char** argv,
- int& end,
- bool erase = false,
- ::build2::test::script::cli::unknown_mode option = ::build2::test::script::cli::unknown_mode::fail,
- ::build2::test::script::cli::unknown_mode argument = ::build2::test::script::cli::unknown_mode::stop);
-
- rm_options (int start,
- int& argc,
- char** argv,
- int& end,
- bool erase = false,
- ::build2::test::script::cli::unknown_mode option = ::build2::test::script::cli::unknown_mode::fail,
- ::build2::test::script::cli::unknown_mode argument = ::build2::test::script::cli::unknown_mode::stop);
-
- rm_options (::build2::test::script::cli::scanner&,
- ::build2::test::script::cli::unknown_mode option = ::build2::test::script::cli::unknown_mode::fail,
- ::build2::test::script::cli::unknown_mode argument = ::build2::test::script::cli::unknown_mode::stop);
-
- // Option accessors.
- //
- const bool&
- recursive () const;
-
- const bool&
- force () const;
-
- // Implementation details.
- //
- protected:
- bool
- _parse (const char*, ::build2::test::script::cli::scanner&);
-
- private:
- bool
- _parse (::build2::test::script::cli::scanner&,
- ::build2::test::script::cli::unknown_mode option,
- ::build2::test::script::cli::unknown_mode argument);
-
- public:
- bool recursive_;
- bool force_;
- };
-
- class rmdir_options
- {
- public:
- rmdir_options ();
-
- rmdir_options (int& argc,
- char** argv,
- bool erase = false,
- ::build2::test::script::cli::unknown_mode option = ::build2::test::script::cli::unknown_mode::fail,
- ::build2::test::script::cli::unknown_mode argument = ::build2::test::script::cli::unknown_mode::stop);
-
- rmdir_options (int start,
- int& argc,
- char** argv,
- bool erase = false,
- ::build2::test::script::cli::unknown_mode option = ::build2::test::script::cli::unknown_mode::fail,
- ::build2::test::script::cli::unknown_mode argument = ::build2::test::script::cli::unknown_mode::stop);
-
- rmdir_options (int& argc,
- char** argv,
- int& end,
- bool erase = false,
- ::build2::test::script::cli::unknown_mode option = ::build2::test::script::cli::unknown_mode::fail,
- ::build2::test::script::cli::unknown_mode argument = ::build2::test::script::cli::unknown_mode::stop);
-
- rmdir_options (int start,
- int& argc,
- char** argv,
- int& end,
- bool erase = false,
- ::build2::test::script::cli::unknown_mode option = ::build2::test::script::cli::unknown_mode::fail,
- ::build2::test::script::cli::unknown_mode argument = ::build2::test::script::cli::unknown_mode::stop);
-
- rmdir_options (::build2::test::script::cli::scanner&,
- ::build2::test::script::cli::unknown_mode option = ::build2::test::script::cli::unknown_mode::fail,
- ::build2::test::script::cli::unknown_mode argument = ::build2::test::script::cli::unknown_mode::stop);
-
- // Option accessors.
- //
- const bool&
- force () const;
-
- // Implementation details.
- //
- protected:
- bool
- _parse (const char*, ::build2::test::script::cli::scanner&);
-
- private:
- bool
- _parse (::build2::test::script::cli::scanner&,
- ::build2::test::script::cli::unknown_mode option,
- ::build2::test::script::cli::unknown_mode argument);
-
- public:
- bool force_;
- };
-
- class sed_options
- {
- public:
- sed_options ();
-
- sed_options (int& argc,
- char** argv,
- bool erase = false,
- ::build2::test::script::cli::unknown_mode option = ::build2::test::script::cli::unknown_mode::fail,
- ::build2::test::script::cli::unknown_mode argument = ::build2::test::script::cli::unknown_mode::stop);
-
- sed_options (int start,
- int& argc,
- char** argv,
- bool erase = false,
- ::build2::test::script::cli::unknown_mode option = ::build2::test::script::cli::unknown_mode::fail,
- ::build2::test::script::cli::unknown_mode argument = ::build2::test::script::cli::unknown_mode::stop);
-
- sed_options (int& argc,
- char** argv,
- int& end,
- bool erase = false,
- ::build2::test::script::cli::unknown_mode option = ::build2::test::script::cli::unknown_mode::fail,
- ::build2::test::script::cli::unknown_mode argument = ::build2::test::script::cli::unknown_mode::stop);
-
- sed_options (int start,
- int& argc,
- char** argv,
- int& end,
- bool erase = false,
- ::build2::test::script::cli::unknown_mode option = ::build2::test::script::cli::unknown_mode::fail,
- ::build2::test::script::cli::unknown_mode argument = ::build2::test::script::cli::unknown_mode::stop);
-
- sed_options (::build2::test::script::cli::scanner&,
- ::build2::test::script::cli::unknown_mode option = ::build2::test::script::cli::unknown_mode::fail,
- ::build2::test::script::cli::unknown_mode argument = ::build2::test::script::cli::unknown_mode::stop);
-
- // Option accessors.
- //
- const bool&
- quiet () const;
-
- const bool&
- in_place () const;
-
- const strings&
- expression () const;
-
- bool
- expression_specified () const;
-
- // Implementation details.
- //
- protected:
- bool
- _parse (const char*, ::build2::test::script::cli::scanner&);
-
- private:
- bool
- _parse (::build2::test::script::cli::scanner&,
- ::build2::test::script::cli::unknown_mode option,
- ::build2::test::script::cli::unknown_mode argument);
-
- public:
- bool quiet_;
- bool in_place_;
- strings expression_;
- bool expression_specified_;
- };
-
class set_options
{
public:
@@ -833,184 +331,6 @@ namespace build2
bool newline_;
bool whitespace_;
};
-
- class sleep_options
- {
- public:
- sleep_options ();
-
- sleep_options (int& argc,
- char** argv,
- bool erase = false,
- ::build2::test::script::cli::unknown_mode option = ::build2::test::script::cli::unknown_mode::fail,
- ::build2::test::script::cli::unknown_mode argument = ::build2::test::script::cli::unknown_mode::stop);
-
- sleep_options (int start,
- int& argc,
- char** argv,
- bool erase = false,
- ::build2::test::script::cli::unknown_mode option = ::build2::test::script::cli::unknown_mode::fail,
- ::build2::test::script::cli::unknown_mode argument = ::build2::test::script::cli::unknown_mode::stop);
-
- sleep_options (int& argc,
- char** argv,
- int& end,
- bool erase = false,
- ::build2::test::script::cli::unknown_mode option = ::build2::test::script::cli::unknown_mode::fail,
- ::build2::test::script::cli::unknown_mode argument = ::build2::test::script::cli::unknown_mode::stop);
-
- sleep_options (int start,
- int& argc,
- char** argv,
- int& end,
- bool erase = false,
- ::build2::test::script::cli::unknown_mode option = ::build2::test::script::cli::unknown_mode::fail,
- ::build2::test::script::cli::unknown_mode argument = ::build2::test::script::cli::unknown_mode::stop);
-
- sleep_options (::build2::test::script::cli::scanner&,
- ::build2::test::script::cli::unknown_mode option = ::build2::test::script::cli::unknown_mode::fail,
- ::build2::test::script::cli::unknown_mode argument = ::build2::test::script::cli::unknown_mode::stop);
-
- // Option accessors.
- //
- // Implementation details.
- //
- protected:
- bool
- _parse (const char*, ::build2::test::script::cli::scanner&);
-
- private:
- bool
- _parse (::build2::test::script::cli::scanner&,
- ::build2::test::script::cli::unknown_mode option,
- ::build2::test::script::cli::unknown_mode argument);
-
- public:
- };
-
- class test_options
- {
- public:
- test_options ();
-
- test_options (int& argc,
- char** argv,
- bool erase = false,
- ::build2::test::script::cli::unknown_mode option = ::build2::test::script::cli::unknown_mode::fail,
- ::build2::test::script::cli::unknown_mode argument = ::build2::test::script::cli::unknown_mode::stop);
-
- test_options (int start,
- int& argc,
- char** argv,
- bool erase = false,
- ::build2::test::script::cli::unknown_mode option = ::build2::test::script::cli::unknown_mode::fail,
- ::build2::test::script::cli::unknown_mode argument = ::build2::test::script::cli::unknown_mode::stop);
-
- test_options (int& argc,
- char** argv,
- int& end,
- bool erase = false,
- ::build2::test::script::cli::unknown_mode option = ::build2::test::script::cli::unknown_mode::fail,
- ::build2::test::script::cli::unknown_mode argument = ::build2::test::script::cli::unknown_mode::stop);
-
- test_options (int start,
- int& argc,
- char** argv,
- int& end,
- bool erase = false,
- ::build2::test::script::cli::unknown_mode option = ::build2::test::script::cli::unknown_mode::fail,
- ::build2::test::script::cli::unknown_mode argument = ::build2::test::script::cli::unknown_mode::stop);
-
- test_options (::build2::test::script::cli::scanner&,
- ::build2::test::script::cli::unknown_mode option = ::build2::test::script::cli::unknown_mode::fail,
- ::build2::test::script::cli::unknown_mode argument = ::build2::test::script::cli::unknown_mode::stop);
-
- // Option accessors.
- //
- const bool&
- file () const;
-
- const bool&
- directory () const;
-
- // Implementation details.
- //
- protected:
- bool
- _parse (const char*, ::build2::test::script::cli::scanner&);
-
- private:
- bool
- _parse (::build2::test::script::cli::scanner&,
- ::build2::test::script::cli::unknown_mode option,
- ::build2::test::script::cli::unknown_mode argument);
-
- public:
- bool file_;
- bool directory_;
- };
-
- class touch_options: public ::build2::test::script::cleanup_options
- {
- public:
- touch_options ();
-
- touch_options (int& argc,
- char** argv,
- bool erase = false,
- ::build2::test::script::cli::unknown_mode option = ::build2::test::script::cli::unknown_mode::fail,
- ::build2::test::script::cli::unknown_mode argument = ::build2::test::script::cli::unknown_mode::stop);
-
- touch_options (int start,
- int& argc,
- char** argv,
- bool erase = false,
- ::build2::test::script::cli::unknown_mode option = ::build2::test::script::cli::unknown_mode::fail,
- ::build2::test::script::cli::unknown_mode argument = ::build2::test::script::cli::unknown_mode::stop);
-
- touch_options (int& argc,
- char** argv,
- int& end,
- bool erase = false,
- ::build2::test::script::cli::unknown_mode option = ::build2::test::script::cli::unknown_mode::fail,
- ::build2::test::script::cli::unknown_mode argument = ::build2::test::script::cli::unknown_mode::stop);
-
- touch_options (int start,
- int& argc,
- char** argv,
- int& end,
- bool erase = false,
- ::build2::test::script::cli::unknown_mode option = ::build2::test::script::cli::unknown_mode::fail,
- ::build2::test::script::cli::unknown_mode argument = ::build2::test::script::cli::unknown_mode::stop);
-
- touch_options (::build2::test::script::cli::scanner&,
- ::build2::test::script::cli::unknown_mode option = ::build2::test::script::cli::unknown_mode::fail,
- ::build2::test::script::cli::unknown_mode argument = ::build2::test::script::cli::unknown_mode::stop);
-
- // Option accessors.
- //
- const string&
- after () const;
-
- bool
- after_specified () const;
-
- // Implementation details.
- //
- protected:
- bool
- _parse (const char*, ::build2::test::script::cli::scanner&);
-
- private:
- bool
- _parse (::build2::test::script::cli::scanner&,
- ::build2::test::script::cli::unknown_mode option,
- ::build2::test::script::cli::unknown_mode argument);
-
- public:
- string after_;
- bool after_specified_;
- };
}
}
}
diff --git a/libbuild2/test/script/builtin-options.ixx b/libbuild2/test/script/builtin-options.ixx
index 55fd6d2..bdb95b4 100644
--- a/libbuild2/test/script/builtin-options.ixx
+++ b/libbuild2/test/script/builtin-options.ixx
@@ -158,111 +158,6 @@ namespace build2
{
namespace script
{
- // cleanup_options
- //
-
- inline const bool& cleanup_options::
- no_cleanup () const
- {
- return this->no_cleanup_;
- }
-
- // cat_options
- //
-
- // cp_options
- //
-
- inline const bool& cp_options::
- recursive () const
- {
- return this->recursive_;
- }
-
- inline const bool& cp_options::
- preserve () const
- {
- return this->preserve_;
- }
-
- // ln_options
- //
-
- inline const bool& ln_options::
- symbolic () const
- {
- return this->symbolic_;
- }
-
- // mkdir_options
- //
-
- inline const bool& mkdir_options::
- parents () const
- {
- return this->parents_;
- }
-
- // mv_options
- //
-
- inline const bool& mv_options::
- force () const
- {
- return this->force_;
- }
-
- // rm_options
- //
-
- inline const bool& rm_options::
- recursive () const
- {
- return this->recursive_;
- }
-
- inline const bool& rm_options::
- force () const
- {
- return this->force_;
- }
-
- // rmdir_options
- //
-
- inline const bool& rmdir_options::
- force () const
- {
- return this->force_;
- }
-
- // sed_options
- //
-
- inline const bool& sed_options::
- quiet () const
- {
- return this->quiet_;
- }
-
- inline const bool& sed_options::
- in_place () const
- {
- return this->in_place_;
- }
-
- inline const strings& sed_options::
- expression () const
- {
- return this->expression_;
- }
-
- inline bool sed_options::
- expression_specified () const
- {
- return this->expression_specified_;
- }
-
// set_options
//
@@ -283,39 +178,6 @@ namespace build2
{
return this->whitespace_;
}
-
- // sleep_options
- //
-
- // test_options
- //
-
- inline const bool& test_options::
- file () const
- {
- return this->file_;
- }
-
- inline const bool& test_options::
- directory () const
- {
- return this->directory_;
- }
-
- // touch_options
- //
-
- inline const string& touch_options::
- after () const
- {
- return this->after_;
- }
-
- inline bool touch_options::
- after_specified () const
- {
- return this->after_specified_;
- }
}
}
}
diff --git a/libbuild2/test/script/builtin.cli b/libbuild2/test/script/builtin.cli
index 8b8de73..790e6f1 100644
--- a/libbuild2/test/script/builtin.cli
+++ b/libbuild2/test/script/builtin.cli
@@ -2,102 +2,25 @@
// copyright : Copyright (c) 2014-2019 Code Synthesis Ltd
// license : MIT; see accompanying LICENSE file
-include <libbuild2/types.hxx>;
-
// Note that options in this file are undocumented because we generate neither
// the usage printing code nor man pages. Instead, they are documented in the
// Testscript Language Manual's builtin descriptions.
//
-// Also note that the string type is used for the path options because their
-// parsing depends on the testscript scope working directory (see parse_path()
-// for details) and passing this information to the CLI custom parser would
-// not be easy.
-//
namespace build2
{
namespace test
{
namespace script
{
- // Common option base classes.
- //
-
- class cleanup_options = 0
- {
- bool --no-cleanup;
- };
-
- // Builtin options.
+ // Pseudo-builtin options.
//
- class cat_options
- {
- // No options so far.
- //
- };
-
- class cp_options: cleanup_options
- {
- bool --recursive|-R|-r;
- bool --preserve|-p;
- };
-
- class ln_options: cleanup_options
- {
- bool --symbolic|-s;
- };
-
- class mkdir_options: cleanup_options
- {
- bool --parents|-p;
- };
-
- class mv_options: cleanup_options
- {
- bool --force|-f;
- };
-
- class rm_options
- {
- bool --recursive|-r;
- bool --force|-f;
- };
-
- class rmdir_options
- {
- bool --force|-f;
- };
-
- class sed_options
- {
- bool --quiet|-n;
- bool --in-place|-i;
- strings --expression|-e;
- };
-
class set_options
{
bool --exact|-e;
bool --newline|-n;
bool --whitespace|-w;
};
-
- class sleep_options
- {
- // No options so far.
- //
- };
-
- class test_options
- {
- bool --file|-f;
- bool --directory|-d;
- };
-
- class touch_options: cleanup_options
- {
- string --after; // Path (see above).
- };
}
}
}
diff --git a/libbuild2/test/script/builtin.cxx b/libbuild2/test/script/builtin.cxx
deleted file mode 100644
index 06b0cec..0000000
--- a/libbuild2/test/script/builtin.cxx
+++ /dev/null
@@ -1,1924 +0,0 @@
-// file : libbuild2/test/script/builtin.cxx -*- C++ -*-
-// copyright : Copyright (c) 2014-2019 Code Synthesis Ltd
-// license : MIT; see accompanying LICENSE file
-
-#include <libbuild2/test/script/builtin.hxx>
-
-#include <chrono>
-#include <locale>
-#include <ostream>
-#include <sstream>
-#include <cstdlib> // strtoull()
-
-#include <libbutl/regex.mxx>
-#include <libbutl/path-io.mxx> // use default operator<< implementation
-#include <libbutl/fdstream.mxx> // fdopen_mode, fdstream_mode
-#include <libbutl/filesystem.mxx>
-
-#include <libbuild2/context.hxx> // sched
-
-#include <libbuild2/test/script/script.hxx>
-#include <libbuild2/test/script/builtin-options.hxx>
-
-// Strictly speaking a builtin which reads/writes from/to standard streams
-// must be asynchronous so that the caller can communicate with it through
-// pipes without being blocked on I/O operations. However, as an optimization,
-// we allow builtins that only print diagnostics to STDERR to be synchronous
-// assuming that their output will always fit the pipe buffer. Synchronous
-// builtins must not read from STDIN and write to STDOUT. Later we may relax
-// this rule to allow a "short" output for such builtins.
-//
-using namespace std;
-using namespace butl;
-
-namespace build2
-{
- namespace test
- {
- namespace script
- {
- using builtin_impl = uint8_t (scope&,
- const strings& args,
- auto_fd in, auto_fd out, auto_fd err);
-
- // Operation failed, diagnostics has already been issued.
- //
- struct failed {};
-
- // Accumulate an error message, print it atomically in dtor to the
- // provided stream and throw failed afterwards if requested. Prefixes
- // the message with the builtin name.
- //
- // Move constructible-only, not assignable (based to diag_record).
- //
- class error_record
- {
- public:
- template <typename T>
- friend const error_record&
- operator<< (const error_record& r, const T& x)
- {
- r.ss_ << x;
- return r;
- }
-
- error_record (ostream& o, bool fail, const char* name)
- : os_ (o), fail_ (fail), empty_ (false)
- {
- ss_ << name << ": ";
- }
-
- // Older versions of libstdc++ don't have the ostringstream move
- // support. Luckily, GCC doesn't seem to be actually needing move due
- // to copy/move elision.
- //
-#ifdef __GLIBCXX__
- error_record (error_record&&);
-#else
- error_record (error_record&& r)
- : os_ (r.os_),
- ss_ (move (r.ss_)),
- fail_ (r.fail_),
- empty_ (r.empty_)
- {
- r.empty_ = true;
- }
-#endif
-
- ~error_record () noexcept (false)
- {
- if (!empty_)
- {
- // The output stream can be in a bad state (for example as a
- // result of unsuccessful attempt to report a previous error), so
- // we check it.
- //
- if (os_.good ())
- {
- ss_.put ('\n');
- os_ << ss_.str ();
- os_.flush ();
- }
-
- if (fail_)
- throw failed ();
- }
- }
-
- private:
- ostream& os_;
- mutable ostringstream ss_;
-
- bool fail_;
- bool empty_;
- };
-
- // Parse and normalize a path. Also, unless it is already absolute, make
- // the path absolute using the specified directory. Throw invalid_path
- // if the path is empty, and on parsing and normalization failures.
- //
- static path
- parse_path (string s, const dir_path& d)
- {
- path p (move (s));
-
- if (p.empty ())
- throw invalid_path ("");
-
- if (p.relative ())
- p = d / move (p);
-
- p.normalize ();
- return p;
- }
-
- // Builtin commands functions.
- //
-
- // cat <file>...
- //
- // Note that POSIX doesn't specify if after I/O operation failure the
- // command should proceed with the rest of the arguments. The current
- // implementation exits immediatelly in such a case.
- //
- // @@ Shouldn't we check that we don't print a nonempty regular file to
- // itself, as that would merely exhaust the output device? POSIX
- // allows (but not requires) such a check and some implementations do
- // this. That would require to fstat() file descriptors and complicate
- // the code a bit. Was able to reproduce on a big file (should be
- // bigger than the stream buffer size) with the test
- // 'cat file >+file'.
- //
- // Note: must be executed asynchronously.
- //
- static uint8_t
- cat (scope& sp,
- const strings& args,
- auto_fd in, auto_fd out, auto_fd err) noexcept
- try
- {
- uint8_t r (1);
- ofdstream cerr (move (err));
-
- auto error = [&cerr] (bool fail = true)
- {
- return error_record (cerr, fail, "cat");
- };
-
- try
- {
- ifdstream cin (move (in), fdstream_mode::binary);
- ofdstream cout (move (out), fdstream_mode::binary);
-
- // Parse arguments.
- //
- cli::vector_scanner scan (args);
- cat_options ops (scan); // Makes sure no options passed.
-
- // Print files.
- //
- // Copy input stream to STDOUT.
- //
- auto copy = [&cout] (istream& is)
- {
- if (is.peek () != ifdstream::traits_type::eof ())
- cout << is.rdbuf ();
-
- is.clear (istream::eofbit); // Sets eofbit.
- };
-
- // Path of a file being printed to STDOUT. An empty path represents
- // STDIN. Used in diagnostics.
- //
- path p;
-
- try
- {
- // Print STDIN.
- //
- if (!scan.more ())
- copy (cin);
-
- // Print files.
- //
- while (scan.more ())
- {
- string f (scan.next ());
-
- if (f == "-")
- {
- if (!cin.eof ())
- {
- p.clear ();
- copy (cin);
- }
-
- continue;
- }
-
- p = parse_path (move (f), sp.wd_path);
-
- ifdstream is (p, fdopen_mode::binary);
- copy (is);
- is.close ();
- }
- }
- catch (const io_error& e)
- {
- error_record d (error ());
- d << "unable to print ";
-
- if (p.empty ())
- d << "stdin";
- else
- d << "'" << p << "'";
-
- d << ": " << e;
- }
-
- cin.close ();
- cout.close ();
- r = 0;
- }
- catch (const invalid_path& e)
- {
- error (false) << "invalid path '" << e.path << "'";
- }
- // Can be thrown while creating/closing cin, cout or writing to cerr.
- //
- catch (const io_error& e)
- {
- error (false) << e;
- }
- catch (const failed&)
- {
- // Diagnostics has already been issued.
- }
- catch (const cli::exception& e)
- {
- error (false) << e;
- }
-
- cerr.close ();
- return r;
- }
- catch (const std::exception&)
- {
- return 1;
- }
-
- // Make a copy of a file at the specified path, preserving permissions,
- // and registering a cleanup for a newly created file. The file paths
- // must be absolute. Fail if an exception is thrown by the underlying
- // copy operation.
- //
- static void
- cpfile (scope& sp,
- const path& from, const path& to,
- bool overwrite,
- bool attrs,
- bool cleanup,
- const function<error_record()>& fail)
- {
- try
- {
- bool exists (file_exists (to));
-
- cpflags f (
- overwrite
- ? cpflags::overwrite_permissions | cpflags::overwrite_content
- : cpflags::none);
-
- if (attrs)
- f |= cpflags::overwrite_permissions | cpflags::copy_timestamps;
-
- cpfile (from, to, f);
-
- if (!exists && cleanup)
- sp.clean ({cleanup_type::always, to}, true /* implicit */);
- }
- catch (const system_error& e)
- {
- fail () << "unable to copy file '" << from << "' to '" << to
- << "': " << e;
- }
- }
-
- // Make a copy of a directory at the specified path, registering a
- // cleanup for the created directory. The directory paths must be
- // absolute. Fail if the destination directory already exists or
- // an exception is thrown by the underlying copy operation.
- //
- static void
- cpdir (scope& sp,
- const dir_path& from, const dir_path& to,
- bool attrs,
- bool cleanup,
- const function<error_record()>& fail)
- {
- try
- {
- if (try_mkdir (to) == mkdir_status::already_exists)
- throw_generic_error (EEXIST);
-
- if (cleanup)
- sp.clean ({cleanup_type::always, to}, true /* implicit */);
-
- for (const auto& de: dir_iterator (from,
- false /* ignore_dangling */))
- {
- path f (from / de.path ());
- path t (to / de.path ());
-
- if (de.type () == entry_type::directory)
- cpdir (sp,
- path_cast<dir_path> (move (f)),
- path_cast<dir_path> (move (t)),
- attrs,
- cleanup,
- fail);
- else
- cpfile (sp, f, t, false /* overwrite */, attrs, cleanup, fail);
- }
-
- // Note that it is essential to copy timestamps and permissions after
- // the directory content is copied.
- //
- if (attrs)
- {
- path_permissions (to, path_permissions (from));
- dir_time (to, dir_time (from));
- }
- }
- catch (const system_error& e)
- {
- fail () << "unable to copy directory '" << from << "' to '" << to
- << "': " << e;
- }
- }
-
- // cp [-p|--preserve] [--no-cleanup] <src-file> <dst-file>
- // cp [-p|--preserve] [--no-cleanup] -R|-r|--recursive <src-dir> <dst-dir>
- // cp [-p|--preserve] [--no-cleanup] <src-file>... <dst-dir>/
- // cp [-p|--preserve] [--no-cleanup] -R|-r|--recursive <src-path>... <dst-dir>/
- //
- // Note: can be executed synchronously.
- //
- static uint8_t
- cp (scope& sp,
- const strings& args,
- auto_fd in, auto_fd out, auto_fd err) noexcept
- try
- {
- uint8_t r (1);
- ofdstream cerr (move (err));
-
- auto error = [&cerr] (bool fail = true)
- {
- return error_record (cerr, fail, "cp");
- };
-
- try
- {
- in.close ();
- out.close ();
-
- // Parse arguments.
- //
- cli::vector_scanner scan (args);
- cp_options ops (scan);
-
- // Copy files or directories.
- //
- if (!scan.more ())
- error () << "missing arguments";
-
- // Note that the arguments semantics depends on the last argument,
- // so we read out and cache them.
- //
- small_vector<string, 2> args;
- while (scan.more ())
- args.push_back (scan.next ());
-
- const dir_path& wd (sp.wd_path);
-
- auto i (args.begin ());
- auto j (args.rbegin ());
- path dst (parse_path (move (*j++), wd));
- auto e (j.base ());
-
- if (i == e)
- error () << "missing source path";
-
- auto fail = [&error] () {return error (true);};
-
- bool cleanup (!ops.no_cleanup ());
-
- // If destination is not a directory path (no trailing separator)
- // then make a copy of the filesystem entry at the specified path
- // (the only source path is allowed in such a case). Otherwise copy
- // the source filesystem entries into the destination directory.
- //
- if (!dst.to_directory ())
- {
- path src (parse_path (move (*i++), wd));
-
- // If there are multiple sources but no trailing separator for the
- // destination, then, most likelly, it is missing.
- //
- if (i != e)
- error () << "multiple source paths without trailing separator "
- << "for destination directory";
-
- if (!ops.recursive ())
- // Synopsis 1: make a file copy at the specified path.
- //
- cpfile (sp,
- src,
- dst,
- true /* overwrite */,
- ops.preserve (),
- cleanup,
- fail);
- else
- // Synopsis 2: make a directory copy at the specified path.
- //
- cpdir (sp,
- path_cast<dir_path> (src), path_cast<dir_path> (dst),
- ops.preserve (),
- cleanup,
- fail);
- }
- else
- {
- for (; i != e; ++i)
- {
- path src (parse_path (move (*i), wd));
-
- if (ops.recursive () && dir_exists (src))
- // Synopsis 4: copy a filesystem entry into the specified
- // directory. Note that we handle only source directories here.
- // Source files are handled below.
- //
- cpdir (sp,
- path_cast<dir_path> (src),
- path_cast<dir_path> (dst / src.leaf ()),
- ops.preserve (),
- cleanup,
- fail);
- else
- // Synopsis 3: copy a file into the specified directory. Also,
- // here we cover synopsis 4 for the source path being a file.
- //
- cpfile (sp,
- src,
- dst / src.leaf (),
- true /* overwrite */,
- ops.preserve (),
- cleanup,
- fail);
- }
- }
-
- r = 0;
- }
- catch (const invalid_path& e)
- {
- error (false) << "invalid path '" << e.path << "'";
- }
- // Can be thrown while closing in, out or writing to cerr.
- //
- catch (const io_error& e)
- {
- error (false) << e;
- }
- catch (const failed&)
- {
- // Diagnostics has already been issued.
- }
- catch (const cli::exception& e)
- {
- error (false) << e;
- }
-
- cerr.close ();
- return r;
- }
- catch (const std::exception&)
- {
- return 1;
- }
-
- // echo <string>...
- //
- // Note: must be executed asynchronously.
- //
- static uint8_t
- echo (scope&,
- const strings& args,
- auto_fd in, auto_fd out, auto_fd err) noexcept
- try
- {
- uint8_t r (1);
- ofdstream cerr (move (err));
-
- try
- {
- in.close ();
- ofdstream cout (move (out));
-
- for (auto b (args.begin ()), i (b), e (args.end ()); i != e; ++i)
- cout << (i != b ? " " : "") << *i;
-
- cout << '\n';
- cout.close ();
- r = 0;
- }
- catch (const std::exception& e)
- {
- cerr << "echo: " << e << endl;
- }
-
- cerr.close ();
- return r;
- }
- catch (const std::exception&)
- {
- return 1;
- }
-
- // false
- //
- // Failure to close the file descriptors is silently ignored.
- //
- // Note: can be executed synchronously.
- //
- static builtin
- false_ (scope&, uint8_t& r, const strings&, auto_fd, auto_fd, auto_fd)
- {
- return builtin (r = 1);
- }
-
- // true
- //
- // Failure to close the file descriptors is silently ignored.
- //
- // Note: can be executed synchronously.
- //
- static builtin
- true_ (scope&, uint8_t& r, const strings&, auto_fd, auto_fd, auto_fd)
- {
- return builtin (r = 0);
- }
-
- // Create a symlink to a file or directory at the specified path. The
- // paths must be absolute. Fall back to creating a hardlink, if symlink
- // creation is not supported for the link path. If hardlink creation is
- // not supported either, then fall back to copies. If requested, created
- // filesystem entries are registered for cleanup. Fail if the target
- // filesystem entry doesn't exist or an exception is thrown by the
- // underlying filesystem operation (specifically for an already existing
- // filesystem entry at the link path).
- //
- // Note that supporting optional removal of an existing filesystem entry
- // at the link path (the -f option) tends to get hairy. As soon as an
- // existing and the resulting filesystem entries could be of different
- // types, we would end up with canceling an old cleanup and registering
- // the new one. Also removing non-empty directories doesn't look very
- // natural, but would be required if we want the behavior on POSIX and
- // Windows to be consistent.
- //
- static void
- mksymlink (scope& sp,
- const path& target, const path& link,
- bool cleanup,
- const function<error_record()>& fail)
- {
- // Determine the target type, fail if the target doesn't exist.
- //
- bool dir (false);
-
- try
- {
- pair<bool, entry_stat> pe (path_entry (target));
-
- if (!pe.first)
- fail () << "unable to create symlink to '" << target << "': "
- << "no such file or directory";
-
- dir = pe.second.type == entry_type::directory;
- }
- catch (const system_error& e)
- {
- fail () << "unable to stat '" << target << "': " << e;
- }
-
- // First we try to create a symlink. If that fails (e.g., "Windows
- // happens"), then we resort to hard links. If that doesn't work out
- // either (e.g., not on the same filesystem), then we fall back to
- // copies. So things are going to get a bit nested.
- //
- // Note: similar to mkanylink() but with support for directories.
- //
- try
- {
- mksymlink (target, link, dir);
-
- if (cleanup)
- sp.clean ({cleanup_type::always, link}, true /* implicit */);
- }
- catch (const system_error& e)
- {
- // Note that we are not guaranteed (here and below) that the
- // system_error exception is of the generic category.
- //
- int c (e.code ().value ());
- if (!(e.code ().category () == generic_category () &&
- (c == ENOSYS || // Not implemented.
- c == EPERM))) // Not supported by the filesystem(s).
- fail () << "unable to create symlink '" << link << "' to '"
- << target << "': " << e;
-
- try
- {
- mkhardlink (target, link, dir);
-
- if (cleanup)
- sp.clean ({cleanup_type::always, link}, true /* implicit */);
- }
- catch (const system_error& e)
- {
- c = e.code ().value ();
- if (!(e.code ().category () == generic_category () &&
- (c == ENOSYS || // Not implemented.
- c == EPERM || // Not supported by the filesystem(s).
- c == EXDEV))) // On different filesystems.
- fail () << "unable to create hardlink '" << link << "' to '"
- << target << "': " << e;
-
- if (dir)
- cpdir (sp,
- path_cast<dir_path> (target), path_cast<dir_path> (link),
- false,
- cleanup,
- fail);
- else
- cpfile (sp,
- target,
- link,
- false /* overwrite */,
- true /* attrs */,
- cleanup,
- fail);
- }
- }
- }
-
- // ln [--no-cleanup] -s|--symbolic <target-path> <link-path>
- // ln [--no-cleanup] -s|--symbolic <target-path>... <link-dir>/
- //
- // Note: can be executed synchronously.
- //
- static uint8_t
- ln (scope& sp,
- const strings& args,
- auto_fd in, auto_fd out, auto_fd err) noexcept
- try
- {
- uint8_t r (1);
- ofdstream cerr (move (err));
-
- auto error = [&cerr] (bool fail = true)
- {
- return error_record (cerr, fail, "ln");
- };
-
- try
- {
- in.close ();
- out.close ();
-
- // Parse arguments.
- //
- cli::vector_scanner scan (args);
- ln_options ops (scan);
-
- if (!ops.symbolic ())
- error () << "missing -s|--symbolic option";
-
- // Create file or directory symlinks.
- //
- if (!scan.more ())
- error () << "missing arguments";
-
- // Note that the arguments semantics depends on the last argument,
- // so we read out and cache them.
- //
- small_vector<string, 2> args;
- while (scan.more ())
- args.push_back (scan.next ());
-
- const dir_path& wd (sp.wd_path);
-
- auto i (args.begin ());
- auto j (args.rbegin ());
- path link (parse_path (move (*j++), wd));
- auto e (j.base ());
-
- if (i == e)
- error () << "missing target path";
-
- auto fail = [&error] () {return error (true);};
-
- bool cleanup (!ops.no_cleanup ());
-
- // If link is not a directory path (no trailing separator), then
- // create a symlink to the target path at the specified link path
- // (the only target path is allowed in such a case). Otherwise create
- // links to the target paths inside the specified directory.
- //
- if (!link.to_directory ())
- {
- path target (parse_path (move (*i++), wd));
-
- // If there are multiple targets but no trailing separator for the
- // link, then, most likelly, it is missing.
- //
- if (i != e)
- error () << "multiple target paths with non-directory link path";
-
- // Synopsis 1: create a target path symlink at the specified path.
- //
- mksymlink (sp, target, link, cleanup, fail);
- }
- else
- {
- for (; i != e; ++i)
- {
- path target (parse_path (move (*i), wd));
-
- // Synopsis 2: create a target path symlink in the specified
- // directory.
- //
- mksymlink (sp, target, link / target.leaf (), cleanup, fail);
- }
- }
-
- r = 0;
- }
- catch (const invalid_path& e)
- {
- error (false) << "invalid path '" << e.path << "'";
- }
- // Can be thrown while closing in, out or writing to cerr.
- //
- catch (const io_error& e)
- {
- error (false) << e;
- }
- catch (const failed&)
- {
- // Diagnostics has already been issued.
- }
- catch (const cli::exception& e)
- {
- error (false) << e;
- }
-
- cerr.close ();
- return r;
- }
- catch (const std::exception&)
- {
- return 1;
- }
-
- // Create a directory if not exist and its parent directories if
- // necessary. Throw system_error on failure. Register created
- // directories for cleanup. The directory path must be absolute.
- //
- static void
- mkdir_p (scope& sp, const dir_path& p, bool cleanup)
- {
- if (!dir_exists (p))
- {
- if (!p.root ())
- mkdir_p (sp, p.directory (), cleanup);
-
- try_mkdir (p); // Returns success or throws.
-
- if (cleanup)
- sp.clean ({cleanup_type::always, p}, true /* implicit */);
- }
- }
-
- // mkdir [--no-cleanup] [-p|--parents] <dir>...
- //
- // Note that POSIX doesn't specify if after a directory creation failure
- // the command should proceed with the rest of the arguments. The current
- // implementation exits immediatelly in such a case.
- //
- // Note: can be executed synchronously.
- //
- static uint8_t
- mkdir (scope& sp,
- const strings& args,
- auto_fd in, auto_fd out, auto_fd err) noexcept
- try
- {
- uint8_t r (1);
- ofdstream cerr (move (err));
-
- auto error = [&cerr] (bool fail = true)
- {
- return error_record (cerr, fail, "mkdir");
- };
-
- try
- {
- in.close ();
- out.close ();
-
- // Parse arguments.
- //
- cli::vector_scanner scan (args);
- mkdir_options ops (scan);
-
- // Create directories.
- //
- if (!scan.more ())
- error () << "missing directory";
-
- bool cleanup (!ops.no_cleanup ());
-
- while (scan.more ())
- {
- dir_path p (path_cast<dir_path> (parse_path (scan.next (),
- sp.wd_path)));
-
- try
- {
- if (ops.parents ())
- mkdir_p (sp, p, cleanup);
- else if (try_mkdir (p) == mkdir_status::success)
- {
- if (cleanup)
- sp.clean ({cleanup_type::always, p}, true /* implicit */);
- }
- else // == mkdir_status::already_exists
- throw_generic_error (EEXIST);
- }
- catch (const system_error& e)
- {
- error () << "unable to create directory '" << p << "': " << e;
- }
- }
-
- r = 0;
- }
- catch (const invalid_path& e)
- {
- error (false) << "invalid path '" << e.path << "'";
- }
- // Can be thrown while closing in, out or writing to cerr.
- //
- catch (const io_error& e)
- {
- error (false) << e;
- }
- catch (const failed&)
- {
- // Diagnostics has already been issued.
- }
- catch (const cli::exception& e)
- {
- error (false) << e;
- }
-
- cerr.close ();
- return r;
- }
- catch (const std::exception&)
- {
- return 1;
- }
-
- // mv [--no-cleanup] [-f|--force] <src-path> <dst-path>
- // mv [--no-cleanup] [-f|--force] <src-path>... <dst-dir>/
- //
- // Note: can be executed synchronously.
- //
- static uint8_t
- mv (scope& sp,
- const strings& args,
- auto_fd in, auto_fd out, auto_fd err) noexcept
- try
- {
- uint8_t r (1);
- ofdstream cerr (move (err));
-
- auto error = [&cerr] (bool fail = true)
- {
- return error_record (cerr, fail, "mv");
- };
-
- try
- {
- in.close ();
- out.close ();
-
- // Parse arguments.
- //
- cli::vector_scanner scan (args);
- mv_options ops (scan);
-
- // Move filesystem entries.
- //
- if (!scan.more ())
- error () << "missing arguments";
-
- // Note that the arguments semantics depends on the last argument,
- // so we read out and cache them.
- //
- small_vector<string, 2> args;
- while (scan.more ())
- args.push_back (scan.next ());
-
- const dir_path& wd (sp.wd_path);
-
- auto i (args.begin ());
- auto j (args.rbegin ());
- path dst (parse_path (move (*j++), wd));
- auto e (j.base ());
-
- if (i == e)
- error () << "missing source path";
-
- auto mv = [ops, &wd, &sp, &error] (const path& from, const path& to)
- {
- const dir_path& rwd (sp.root.wd_path);
-
- if (!from.sub (rwd) && !ops.force ())
- error () << "'" << from << "' is out of working directory '"
- << rwd << "'";
-
- try
- {
- auto check_wd = [&wd, &error] (const path& p)
- {
- if (wd.sub (path_cast<dir_path> (p)))
- error () << "'" << p << "' contains test working directory '"
- << wd << "'";
- };
-
- check_wd (from);
- check_wd (to);
-
- bool exists (butl::entry_exists (to));
-
- // Fail if the source and destination paths are the same.
- //
- // Note that for mventry() function (that is based on the POSIX
- // rename() function) this is a noop.
- //
- if (exists && to == from)
- error () << "unable to move entity '" << from << "' to itself";
-
- // Rename/move the filesystem entry, replacing an existing one.
- //
- mventry (from,
- to,
- cpflags::overwrite_permissions |
- cpflags::overwrite_content);
-
- // Unless suppressed, adjust the cleanups that are sub-paths of
- // the source path.
- //
- if (!ops.no_cleanup ())
- {
- // "Move" the matching cleanup if the destination path doesn't
- // exist and is a sub-path of the working directory. Otherwise
- // just remove it.
- //
- // Note that it's not enough to just change the cleanup paths.
- // We also need to make sure that these cleanups happen before
- // the destination directory (or any of its parents) cleanup,
- // that is potentially registered. To achieve that we can just
- // relocate these cleanup entries to the end of the list,
- // preserving their mutual order. Remember that cleanups in
- // the list are executed in the reversed order.
- //
- bool mv_cleanups (!exists && to.sub (rwd));
- cleanups cs;
-
- // Remove the source path sub-path cleanups from the list,
- // adjusting/caching them if required (see above).
- //
- for (auto i (sp.cleanups.begin ()); i != sp.cleanups.end (); )
- {
- cleanup& c (*i);
- path& p (c.path);
-
- if (p.sub (from))
- {
- if (mv_cleanups)
- {
- // Note that we need to preserve the cleanup path
- // trailing separator which indicates the removal
- // method. Also note that leaf(), in particular, does
- // that.
- //
- p = p != from
- ? to / p.leaf (path_cast<dir_path> (from))
- : p.to_directory ()
- ? path_cast<dir_path> (to)
- : to;
-
- cs.push_back (move (c));
- }
-
- i = sp.cleanups.erase (i);
- }
- else
- ++i;
- }
-
- // Re-insert the adjusted cleanups at the end of the list.
- //
- sp.cleanups.insert (sp.cleanups.end (),
- make_move_iterator (cs.begin ()),
- make_move_iterator (cs.end ()));
- }
- }
- catch (const system_error& e)
- {
- error () << "unable to move entity '" << from << "' to '" << to
- << "': " << e;
- }
- };
-
- // If destination is not a directory path (no trailing separator)
- // then move the filesystem entry to the specified path (the only
- // source path is allowed in such a case). Otherwise move the source
- // filesystem entries into the destination directory.
- //
- if (!dst.to_directory ())
- {
- path src (parse_path (move (*i++), wd));
-
- // If there are multiple sources but no trailing separator for the
- // destination, then, most likelly, it is missing.
- //
- if (i != e)
- error () << "multiple source paths without trailing separator "
- << "for destination directory";
-
- // Synopsis 1: move an entity to the specified path.
- //
- mv (src, dst);
- }
- else
- {
- // Synopsis 2: move entities into the specified directory.
- //
- for (; i != e; ++i)
- {
- path src (parse_path (move (*i), wd));
- mv (src, dst / src.leaf ());
- }
- }
-
- r = 0;
- }
- catch (const invalid_path& e)
- {
- error (false) << "invalid path '" << e.path << "'";
- }
- // Can be thrown while closing in, out or writing to cerr.
- //
- catch (const io_error& e)
- {
- error (false) << e;
- }
- catch (const failed&)
- {
- // Diagnostics has already been issued.
- }
- catch (const cli::exception& e)
- {
- error (false) << e;
- }
-
- cerr.close ();
- return r;
- }
- catch (const std::exception&)
- {
- return 1;
- }
-
- // rm [-r|--recursive] [-f|--force] <path>...
- //
- // The implementation deviates from POSIX in a number of ways. It doesn't
- // interact with a user and fails immediatelly if unable to process an
- // argument. It doesn't check for dots containment in the path, and
- // doesn't consider files and directory permissions in any way just
- // trying to remove a filesystem entry. Always fails if empty path is
- // specified.
- //
- // Note: can be executed synchronously.
- //
- static uint8_t
- rm (scope& sp,
- const strings& args,
- auto_fd in, auto_fd out, auto_fd err) noexcept
- try
- {
- uint8_t r (1);
- ofdstream cerr (move (err));
-
- auto error = [&cerr] (bool fail = true)
- {
- return error_record (cerr, fail, "rm");
- };
-
- try
- {
- in.close ();
- out.close ();
-
- // Parse arguments.
- //
- cli::vector_scanner scan (args);
- rm_options ops (scan);
-
- // Remove entries.
- //
- if (!scan.more () && !ops.force ())
- error () << "missing file";
-
- const dir_path& wd (sp.wd_path);
- const dir_path& rwd (sp.root.wd_path);
-
- while (scan.more ())
- {
- path p (parse_path (scan.next (), wd));
-
- if (!p.sub (rwd) && !ops.force ())
- error () << "'" << p << "' is out of working directory '" << rwd
- << "'";
-
- try
- {
- dir_path d (path_cast<dir_path> (p));
-
- if (dir_exists (d))
- {
- if (!ops.recursive ())
- error () << "'" << p << "' is a directory";
-
- if (wd.sub (d))
- error () << "'" << p << "' contains test working directory '"
- << wd << "'";
-
- // The call can result in rmdir_status::not_exist. That's not
- // very likelly but there is also nothing bad about it.
- //
- try_rmdir_r (d);
- }
- else if (try_rmfile (p) == rmfile_status::not_exist &&
- !ops.force ())
- throw_generic_error (ENOENT);
- }
- catch (const system_error& e)
- {
- error () << "unable to remove '" << p << "': " << e;
- }
- }
-
- r = 0;
- }
- catch (const invalid_path& e)
- {
- error (false) << "invalid path '" << e.path << "'";
- }
- // Can be thrown while closing in, out or writing to cerr.
- //
- catch (const io_error& e)
- {
- error (false) << e;
- }
- catch (const failed&)
- {
- // Diagnostics has already been issued.
- }
- catch (const cli::exception& e)
- {
- error (false) << e;
- }
-
- cerr.close ();
- return r;
- }
- catch (const std::exception&)
- {
- return 1;
- }
-
- // rmdir [-f|--force] <path>...
- //
- // Note: can be executed synchronously.
- //
- static uint8_t
- rmdir (scope& sp,
- const strings& args,
- auto_fd in, auto_fd out, auto_fd err) noexcept
- try
- {
- uint8_t r (1);
- ofdstream cerr (move (err));
-
- auto error = [&cerr] (bool fail = true)
- {
- return error_record (cerr, fail, "rmdir");
- };
-
- try
- {
- in.close ();
- out.close ();
-
- // Parse arguments.
- //
- cli::vector_scanner scan (args);
- rmdir_options ops (scan);
-
- // Remove directories.
- //
- if (!scan.more () && !ops.force ())
- error () << "missing directory";
-
- const dir_path& wd (sp.wd_path);
- const dir_path& rwd (sp.root.wd_path);
-
- while (scan.more ())
- {
- dir_path p (path_cast<dir_path> (parse_path (scan.next (), wd)));
-
- if (wd.sub (p))
- error () << "'" << p << "' contains test working directory '"
- << wd << "'";
-
- if (!p.sub (rwd) && !ops.force ())
- error () << "'" << p << "' is out of working directory '"
- << rwd << "'";
-
- try
- {
- rmdir_status s (try_rmdir (p));
-
- if (s == rmdir_status::not_empty)
- throw_generic_error (ENOTEMPTY);
- else if (s == rmdir_status::not_exist && !ops.force ())
- throw_generic_error (ENOENT);
- }
- catch (const system_error& e)
- {
- error () << "unable to remove '" << p << "': " << e;
- }
- }
-
- r = 0;
- }
- catch (const invalid_path& e)
- {
- error (false) << "invalid path '" << e.path << "'";
- }
- // Can be thrown while closing in, out or writing to cerr.
- //
- catch (const io_error& e)
- {
- error (false) << e;
- }
- catch (const failed&)
- {
- // Diagnostics has already been issued.
- }
- catch (const cli::exception& e)
- {
- error (false) << e;
- }
-
- cerr.close ();
- return r;
- }
- catch (const std::exception&)
- {
- return 1;
- }
-
- // sed [-n|--quiet] [-i|--in-place] -e|--expression <script> [<file>]
- //
- // Note: must be executed asynchronously.
- //
- static uint8_t
- sed (scope& sp,
- const strings& args,
- auto_fd in, auto_fd out, auto_fd err) noexcept
- try
- {
- uint8_t r (1);
- ofdstream cerr (move (err));
-
- auto error = [&cerr] (bool fail = true)
- {
- return error_record (cerr, fail, "sed");
- };
-
- try
- {
- // Automatically remove a temporary file (used for in place editing)
- // on failure.
- //
- auto_rmfile rm;
-
- // Do not throw when failbit is set (getline() failed to extract any
- // character).
- //
- ifdstream cin (move (in), ifdstream::badbit);
- ofdstream cout (move (out));
-
- // Parse arguments.
- //
- cli::vector_scanner scan (args);
- sed_options ops (scan);
-
- if (ops.expression ().empty ())
- error () << "missing script";
-
- // Only a single script is supported.
- //
- if (ops.expression ().size () != 1)
- error () << "multiple scripts";
-
- struct
- {
- string regex;
- string replacement;
- bool icase = false;
- bool global = false;
- bool print = false;
- } subst;
-
- {
- const string& v (ops.expression ()[0]);
- if (v.empty ())
- error () << "empty script";
-
- if (v[0] != 's')
- error () << "only 's' command supported";
-
- // Parse the substitute command.
- //
- if (v.size () < 2)
- error () << "no delimiter for 's' command";
-
- char delim (v[1]);
- if (delim == '\\' || delim == '\n')
- error () << "invalid delimiter for 's' command";
-
- size_t p (v.find (delim, 2));
- if (p == string::npos)
- error () << "unterminated 's' command regex";
-
- subst.regex.assign (v, 2, p - 2);
-
- // Empty regex matches nothing, so not of much use.
- //
- if (subst.regex.empty ())
- error () << "empty regex in 's' command";
-
- size_t b (p + 1);
- p = v.find (delim, b);
- if (p == string::npos)
- error () << "unterminated 's' command replacement";
-
- subst.replacement.assign (v, b, p - b);
-
- // Parse the substitute command flags.
- //
- char c;
- for (++p; (c = v[p]) != '\0'; ++p)
- {
- switch (c)
- {
- case 'i': subst.icase = true; break;
- case 'g': subst.global = true; break;
- case 'p': subst.print = true; break;
- default:
- {
- error () << "invalid 's' command flag '" << c << "'";
- }
- }
- }
- }
-
- // Path of a file to edit. An empty path represents stdin.
- //
- path p;
- if (scan.more ())
- {
- string f (scan.next ());
-
- if (f != "-")
- p = parse_path (move (f), sp.wd_path);
- }
-
- if (scan.more ())
- error () << "unexpected argument '" << scan.next () << "'";
-
- // Edit file.
- //
- // If we edit file in place make sure that the file path is specified
- // and obtain a temporary file path. We will be writing to the
- // temporary file (rather than to stdout) and will move it to the
- // original file path afterwards.
- //
- path tp;
- if (ops.in_place ())
- {
- if (p.empty ())
- error () << "-i|--in-place option specified while reading from "
- << "stdin";
-
- try
- {
- tp = path::temp_path ("build2-sed");
-
- cout.close (); // Flush and close.
-
- cout.open (
- fdopen (tp,
- fdopen_mode::out | fdopen_mode::truncate |
- fdopen_mode::create,
- path_permissions (p)));
- }
- catch (const io_error& e)
- {
- error_record d (error ());
- d << "unable to open '" << tp << "': " << e;
- }
- catch (const system_error& e)
- {
- error_record d (error ());
- d << "unable to obtain temporary file: " << e;
- }
-
- rm = auto_rmfile (tp);
- }
-
- // Note that ECMAScript is implied if no grammar flag is specified.
- //
- regex re (subst.regex,
- subst.icase ? regex::icase : regex::ECMAScript);
-
- // Edit a file or STDIN.
- //
- try
- {
- // Open a file if specified.
- //
- if (!p.empty ())
- {
- cin.close (); // Flush and close.
- cin.open (p);
- }
-
- // Read until failbit is set (throw on badbit).
- //
- string s;
- while (getline (cin, s))
- {
- auto r (regex_replace_search (
- s,
- re,
- subst.replacement,
- subst.global
- ? regex_constants::format_default
- : regex_constants::format_first_only));
-
- // Add newline regardless whether the source line is newline-
- // terminated or not (in accordance with POSIX).
- //
- if (!ops.quiet () || (r.second && subst.print))
- cout << r.first << '\n';
- }
-
- cin.close ();
- cout.close ();
-
- if (ops.in_place ())
- {
- mvfile (
- tp, p,
- cpflags::overwrite_content | cpflags::overwrite_permissions);
-
- rm.cancel ();
- }
-
- r = 0;
- }
- catch (const io_error& e)
- {
- error_record d (error ());
- d << "unable to edit ";
-
- if (p.empty ())
- d << "stdin";
- else
- d << "'" << p << "'";
-
- d << ": " << e;
- }
- }
- catch (const regex_error& e)
- {
- // Print regex_error description if meaningful (no space).
- //
- error (false) << "invalid regex" << e;
- }
- catch (const invalid_path& e)
- {
- error (false) << "invalid path '" << e.path << "'";
- }
- // Can be thrown while creating cin, cout or writing to cerr.
- //
- catch (const io_error& e)
- {
- error (false) << e;
- }
- catch (const system_error& e)
- {
- error (false) << e;
- }
- catch (const failed&)
- {
- // Diagnostics has already been issued.
- }
- catch (const cli::exception& e)
- {
- error (false) << e;
- }
-
- cerr.close ();
- return r;
- }
- catch (const std::exception&)
- {
- return 1;
- }
-
- // sleep <seconds>
- //
- // Note: can be executed synchronously.
- //
- static uint8_t
- sleep (scope& s,
- const strings& args,
- auto_fd in, auto_fd out, auto_fd err) noexcept
- try
- {
- uint8_t r (1);
- ofdstream cerr (move (err));
-
- auto error = [&cerr] (bool fail = true)
- {
- return error_record (cerr, fail, "sleep");
- };
-
- try
- {
- in.close ();
- out.close ();
-
- // Parse arguments.
- //
- cli::vector_scanner scan (args);
- sleep_options ops (scan); // Makes sure no options passed.
-
- if (!scan.more ())
- error () << "missing time interval";
-
- uint64_t n;
-
- for (;;) // Breakout loop.
- {
- string a (scan.next ());
-
- // Note: strtoull() allows these.
- //
- if (!a.empty () && a[0] != '-' && a[0] != '+')
- {
- char* e (nullptr);
- n = strtoull (a.c_str (), &e, 10); // Can't throw.
-
- if (errno != ERANGE && e == a.c_str () + a.size ())
- break;
- }
-
- error () << "invalid time interval '" << a << "'";
- }
-
- if (scan.more ())
- error () << "unexpected argument '" << scan.next () << "'";
-
- // Sleep.
- //
- // If/when required we could probably support the precise sleep mode
- // (e.g., via an option).
- //
- s.root.test_target.ctx.sched.sleep (chrono::seconds (n));
-
- r = 0;
- }
- // Can be thrown while closing in, out or writing to cerr.
- //
- catch (const io_error& e)
- {
- error (false) << e;
- }
- catch (const failed&)
- {
- // Diagnostics has already been issued.
- }
- catch (const cli::exception& e)
- {
- error (false) << e;
- }
-
- cerr.close ();
- return r;
- }
- catch (const std::exception&)
- {
- return 1;
- }
-
- // test (-f|--file)|(-d|--directory) <path>
- //
- // Note: can be executed synchronously.
- //
- static uint8_t
- test (scope& sp,
- const strings& args,
- auto_fd in, auto_fd out, auto_fd err) noexcept
- try
- {
- uint8_t r (2);
- ofdstream cerr (move (err));
-
- auto error = [&cerr] (bool fail = true)
- {
- return error_record (cerr, fail, "test");
- };
-
- try
- {
- in.close ();
- out.close ();
-
- // Parse arguments.
- //
- cli::vector_scanner scan (args);
- test_options ops (scan); // Makes sure no options passed.
-
- if (!ops.file () && !ops.directory ())
- error () << "either -f|--file or -d|--directory must be specified";
-
- if (ops.file () && ops.directory ())
- error () << "both -f|--file and -d|--directory specified";
-
- if (!scan.more ())
- error () << "missing path";
-
- path p (parse_path (scan.next (), sp.wd_path));
-
- if (scan.more ())
- error () << "unexpected argument '" << scan.next () << "'";
-
- try
- {
- r = (ops.file () ? file_exists (p) : dir_exists (p)) ? 0 : 1;
- }
- catch (const system_error& e)
- {
- error () << "cannot test '" << p << "': " << e;
- }
- }
- catch (const invalid_path& e)
- {
- error (false) << "invalid path '" << e.path << "'";
- }
- // Can be thrown while closing in, out or writing to cerr.
- //
- catch (const io_error& e)
- {
- error (false) << e;
- }
- catch (const failed&)
- {
- // Diagnostics has already been issued.
- }
- catch (const cli::exception& e)
- {
- error (false) << e;
- }
-
- cerr.close ();
- return r;
- }
- catch (const std::exception&)
- {
- return 2;
- }
-
- // touch [--no-cleanup] [--after <ref-file>] <file>...
- //
- // Note that POSIX doesn't specify the behavior for touching an entry
- // other than file.
- //
- // Also note that POSIX doesn't specify if after a file touch failure the
- // command should proceed with the rest of the arguments. The current
- // implementation exits immediatelly in such a case.
- //
- // Note: can be executed synchronously.
- //
- static uint8_t
- touch (scope& sp,
- const strings& args,
- auto_fd in, auto_fd out, auto_fd err) noexcept
- try
- {
- uint8_t r (1);
- ofdstream cerr (move (err));
-
- auto error = [&cerr] (bool fail = true)
- {
- return error_record (cerr, fail, "touch");
- };
-
- try
- {
- in.close ();
- out.close ();
-
- // Parse arguments.
- //
- cli::vector_scanner scan (args);
- touch_options ops (scan);
-
- auto mtime = [&error] (const path& p) -> timestamp
- {
- try
- {
- timestamp t (file_mtime (p));
-
- if (t == timestamp_nonexistent)
- throw_generic_error (ENOENT);
-
- return t;
- }
- catch (const system_error& e)
- {
- error () << "cannot obtain file '" << p
- << "' modification time: " << e;
- }
- assert (false); // Can't be here.
- return timestamp ();
- };
-
- optional<timestamp> after;
- if (ops.after_specified ())
- after = mtime (parse_path (ops.after (), sp.wd_path));
-
- if (!scan.more ())
- error () << "missing file";
-
- // Create files.
- //
- while (scan.more ())
- {
- path p (parse_path (scan.next (), sp.wd_path));
-
- try
- {
- // Note that we don't register (implicit) cleanup for an
- // existing path.
- //
- if (touch_file (p) && !ops.no_cleanup ())
- sp.clean ({cleanup_type::always, p}, true /* implicit */);
-
- if (after)
- {
- while (mtime (p) <= *after)
- touch_file (p, false /* create */);
- }
- }
- catch (const system_error& e)
- {
- error () << "cannot create/update '" << p << "': " << e;
- }
- }
-
- r = 0;
- }
- catch (const invalid_path& e)
- {
- error (false) << "invalid path '" << e.path << "'";
- }
- // Can be thrown while closing in, out or writing to cerr.
- //
- catch (const io_error& e)
- {
- error (false) << e;
- }
- catch (const failed&)
- {
- // Diagnostics has already been issued.
- }
- catch (const cli::exception& e)
- {
- error (false) << e;
- }
-
- cerr.close ();
- return r;
- }
- catch (const std::exception&)
- {
- return 1;
- }
-
- // Run builtin implementation asynchronously.
- //
- static builtin
- async_impl (builtin_impl* fn,
- scope& sp,
- uint8_t& r,
- const strings& args,
- auto_fd in, auto_fd out, auto_fd err)
- {
- return builtin (
- r,
- thread ([fn, &sp, &r, &args,
- in = move (in),
- out = move (out),
- err = move (err)] () mutable noexcept
- {
- r = fn (sp, args, move (in), move (out), move (err));
- }));
- }
-
- template <builtin_impl fn>
- static builtin
- async_impl (scope& sp,
- uint8_t& r,
- const strings& args,
- auto_fd in, auto_fd out, auto_fd err)
- {
- return async_impl (fn, sp, r, args, move (in), move (out), move (err));
- }
-
- // Run builtin implementation synchronously.
- //
- template <builtin_impl fn>
- static builtin
- sync_impl (scope& sp,
- uint8_t& r,
- const strings& args,
- auto_fd in, auto_fd out, auto_fd err)
- {
- r = fn (sp, args, move (in), move (out), move (err));
- return builtin (r, thread ());
- }
-
- const builtin_map builtins
- {
- {"cat", &async_impl<&cat>},
- {"cp", &sync_impl<&cp>},
- {"echo", &async_impl<&echo>},
- {"false", &false_},
- {"ln", &sync_impl<&ln>},
- {"mkdir", &sync_impl<&mkdir>},
- {"mv", &sync_impl<&mv>},
- {"rm", &sync_impl<&rm>},
- {"rmdir", &sync_impl<&rmdir>},
- {"sed", &async_impl<&sed>},
- {"sleep", &sync_impl<&sleep>},
- {"test", &sync_impl<&test>},
- {"touch", &sync_impl<&touch>},
- {"true", &true_}
- };
- }
- }
-}
diff --git a/libbuild2/test/script/builtin.hxx b/libbuild2/test/script/builtin.hxx
deleted file mode 100644
index b340335..0000000
--- a/libbuild2/test/script/builtin.hxx
+++ /dev/null
@@ -1,74 +0,0 @@
-// file : libbuild2/test/script/builtin.hxx -*- C++ -*-
-// copyright : Copyright (c) 2014-2019 Code Synthesis Ltd
-// license : MIT; see accompanying LICENSE file
-
-#ifndef LIBBUILD2_TEST_SCRIPT_BUILTIN_HXX
-#define LIBBUILD2_TEST_SCRIPT_BUILTIN_HXX
-
-#include <map>
-
-#include <libbuild2/types.hxx>
-#include <libbuild2/utility.hxx>
-
-namespace build2
-{
- namespace test
- {
- namespace script
- {
- class scope;
-
- // A process/thread-like object representing a running builtin.
- //
- // For now, instead of allocating the result storage dynamically, we
- // expect it to be provided by the caller.
- //
- class builtin
- {
- public:
- uint8_t
- wait () {if (t_.joinable ()) t_.join (); return r_;}
-
- ~builtin () {wait ();}
-
- public:
- builtin (uint8_t& r, thread&& t = thread ()): r_ (r), t_ (move (t)) {}
-
- builtin (builtin&&) = default;
-
- private:
- uint8_t& r_;
- thread t_;
- };
-
- // Start builtin command. Throw system_error on failure.
- //
- // Note that unlike argc/argv, our args don't include the program name.
- //
- using builtin_func = builtin (scope&,
- uint8_t& result,
- const strings& args,
- auto_fd in, auto_fd out, auto_fd err);
-
- class builtin_map: public std::map<string, builtin_func*>
- {
- public:
- using base = std::map<string, builtin_func*>;
- using base::base;
-
- // Return NULL if not a builtin.
- //
- builtin_func*
- find (const string& n) const
- {
- auto i (base::find (n));
- return i != end () ? i->second : nullptr;
- }
- };
-
- extern const builtin_map builtins;
- }
- }
-}
-
-#endif // LIBBUILD2_TEST_SCRIPT_BUILTIN_HXX
diff --git a/libbuild2/test/script/runner.cxx b/libbuild2/test/script/runner.cxx
index 53f6741..630d4c2 100644
--- a/libbuild2/test/script/runner.cxx
+++ b/libbuild2/test/script/runner.cxx
@@ -4,10 +4,10 @@
#include <libbuild2/test/script/runner.hxx>
-#include <set>
#include <ios> // streamsize
#include <libbutl/regex.mxx>
+#include <libbutl/builtin.mxx>
#include <libbutl/fdstream.mxx> // fdopen_mode, fdnull(), fddup()
#include <libbuild2/variable.hxx>
@@ -18,7 +18,6 @@
#include <libbuild2/test/script/regex.hxx>
#include <libbuild2/test/script/parser.hxx>
-#include <libbuild2/test/script/builtin.hxx>
#include <libbuild2/test/script/builtin-options.hxx>
using namespace std;
@@ -928,7 +927,8 @@ namespace build2
? rmdir_buildignore (
ctx,
d,
- sp.root.target_scope.root_scope ()->root_extra->buildignore_file,
+ sp.root.target_scope.root_scope ()->root_extra->
+ buildignore_file,
v)
: rmdir (ctx, d, v)));
@@ -1145,6 +1145,21 @@ namespace build2
}
}
+ // Sorted array of builtins that support filesystem entries cleanup.
+ //
+ static const char* cleanup_builtins[] = {
+ "cp", "ln", "mkdir", "mv", "touch"};
+
+ static inline bool
+ cleanup_builtin (const string& name)
+ {
+ return binary_search (
+ cleanup_builtins,
+ cleanup_builtins +
+ sizeof (cleanup_builtins) / sizeof (*cleanup_builtins),
+ name);
+ }
+
static bool
run_pipe (scope& sp,
command_pipe::const_iterator bc,
@@ -1205,6 +1220,8 @@ namespace build2
command_pipe::const_iterator nc (bc + 1);
bool last (nc == ec);
+ const string& program (c.program.string ());
+
// Prior to opening file descriptors for command input/output
// redirects let's check if the command is the exit builtin. Being a
// builtin syntactically it differs from the regular ones in a number
@@ -1217,7 +1234,7 @@ namespace build2
// specify any redirects or exit code check sounds like a right thing
// to do.
//
- if (c.program.string () == "exit")
+ if (program == "exit")
{
// In case the builtin is erroneously pipelined from the other
// command, we will close stdin gracefully (reading out the stream
@@ -1240,7 +1257,7 @@ namespace build2
if (err.type != redirect_type::none)
fail (ll) << "exit builtin stderr cannot be redirected";
- // We can't make sure that there is not exit code check. Let's, at
+ // We can't make sure that there is no exit code check. Let's, at
// least, check that non-zero code is not expected.
//
if (eq != (c.exit.code == 0))
@@ -1391,7 +1408,7 @@ namespace build2
// that. Checking that the user didn't specify any meaningless
// redirects or exit code check sounds as a right thing to do.
//
- if (c.program.string () == "set")
+ if (program == "set")
{
if (!last)
fail (ll) << "set builtin must be the last pipe command";
@@ -1583,7 +1600,7 @@ namespace build2
assert (ofd.out.get () != -1 && efd.get () != -1);
optional<process_exit> exit;
- builtin_func* bf (builtins.find (c.program.string ()));
+ builtin_function* bf (builtins.find (program));
bool success;
@@ -1605,11 +1622,226 @@ namespace build2
if (verb >= 2)
print_process (process_args ());
+ // Some of the testscript builtins (cp, mkdir, etc) extend libbutl
+ // builtins (via callbacks) registering/moving cleanups for the
+ // filesystem entries they create/move, unless explicitly requested
+ // not to do so via the --no-cleanup option.
+ //
+ // Let's "wrap up" the cleanup-related flags into the single object
+ // to rely on "small function object" optimization.
+ //
+ struct cleanup
+ {
+ // Whether the cleanups are enabled for the builtin. Can be set to
+ // false by the parse_option callback if --no-cleanup is
+ // encountered.
+ //
+ bool enabled = true;
+
+ // Whether to register cleanup for a filesystem entry being
+ // created/updated depending on its existence. Calculated by the
+ // create pre-hook and used by the subsequent post-hook.
+ //
+ bool add;
+
+ // Whether to move existing cleanups for the filesystem entry
+ // being moved, rather than to erase them. Calculated by the move
+ // pre-hook and used by the subsequent post-hook.
+ //
+ bool move;
+ };
+
+ // nullopt if the builtin doesn't support cleanups.
+ //
+ optional<cleanup> cln;
+
+ if (cleanup_builtin (program))
+ cln = cleanup ();
+
+ builtin_callbacks bcs {
+
+ // create
+ //
+ // Unless cleanups are suppressed, test that the filesystem entry
+ // doesn't exist (pre-hook) and, if that's the case, register the
+ // cleanup for the newly created filesystem entry (post-hook).
+ //
+ [&sp, &cln] (const path& p, bool pre)
+ {
+ // Cleanups must be supported by a filesystem entry-creating
+ // builtin.
+ //
+ assert (cln);
+
+ if (cln->enabled)
+ {
+ if (pre)
+ cln->add = !butl::entry_exists (p);
+ else if (cln->add)
+ sp.clean ({cleanup_type::always, p}, true /* implicit */);
+ }
+ },
+
+ // move
+ //
+ // Validate the source and destination paths (pre-hook) and,
+ // unless suppressed, adjust the cleanups that are sub-paths of
+ // the source path (post-hook).
+ //
+ [&sp, &cln]
+ (const path& from, const path& to, bool force, bool pre)
+ {
+ // Cleanups must be supported by a filesystem entry-moving
+ // builtin.
+ //
+ assert (cln);
+
+ if (pre)
+ {
+ const dir_path& wd (sp.wd_path);
+ const dir_path& rwd (sp.root.wd_path);
+
+ auto fail = [] (const string& d) {throw runtime_error (d);};
+
+ if (!from.sub (rwd) && !force)
+ fail ("'" + from.representation () +
+ "' is out of working directory '" + rwd.string () +
+ "'");
+
+ auto check_wd = [&wd, fail] (const path& p)
+ {
+ if (wd.sub (path_cast<dir_path> (p)))
+ fail ("'" + p.string () +
+ "' contains test working directory '" +
+ wd.string () + "'");
+ };
+
+ check_wd (from);
+ check_wd (to);
+
+ // Unless cleanups are disabled, "move" the matching cleanups
+ // if the destination path doesn't exist and it is a sub-path
+ // of the working directory and just remove them otherwise.
+ //
+ if (cln->enabled)
+ cln->move = !butl::entry_exists (to) && to.sub (rwd);
+ }
+ else if (cln->enabled)
+ {
+ // Move or remove the matching cleanups (see above).
+ //
+ // Note that it's not enough to just change the cleanup paths.
+ // We also need to make sure that these cleanups happen before
+ // the destination directory (or any of its parents) cleanup,
+ // that is potentially registered. To achieve that we can just
+ // relocate these cleanup entries to the end of the list,
+ // preserving their mutual order. Remember that cleanups in
+ // the list are executed in the reversed order.
+ //
+ cleanups cs;
+
+ // Remove the source path sub-path cleanups from the list,
+ // adjusting/caching them if required (see above).
+ //
+ for (auto i (sp.cleanups.begin ()); i != sp.cleanups.end (); )
+ {
+ build2::test::script::cleanup& c (*i);
+ path& p (c.path);
+
+ if (p.sub (from))
+ {
+ if (cln->move)
+ {
+ // Note that we need to preserve the cleanup path
+ // trailing separator which indicates the removal
+ // method. Also note that leaf(), in particular, does
+ // that.
+ //
+ p = p != from
+ ? to / p.leaf (path_cast<dir_path> (from))
+ : p.to_directory ()
+ ? path_cast<dir_path> (to)
+ : to;
+
+ cs.push_back (move (c));
+ }
+
+ i = sp.cleanups.erase (i);
+ }
+ else
+ ++i;
+ }
+
+ // Re-insert the adjusted cleanups at the end of the list.
+ //
+ sp.cleanups.insert (sp.cleanups.end (),
+ make_move_iterator (cs.begin ()),
+ make_move_iterator (cs.end ()));
+
+ }
+ },
+
+ // remove
+ //
+ // Validate the filesystem entry path (pre-hook).
+ //
+ [&sp] (const path& p, bool force, bool pre)
+ {
+ if (pre)
+ {
+ const dir_path& wd (sp.wd_path);
+ const dir_path& rwd (sp.root.wd_path);
+
+ auto fail = [] (const string& d) {throw runtime_error (d);};
+
+ if (!p.sub (rwd) && !force)
+ fail ("'" + p.representation () +
+ "' is out of working directory '" + rwd.string () +
+ "'");
+
+ if (wd.sub (path_cast<dir_path> (p)))
+ fail ("'" + p.string () +
+ "' contains test working directory '" + wd.string () +
+ "'");
+ }
+ },
+
+ // parse_option
+ //
+ [&cln] (const strings& args, size_t i)
+ {
+ // Parse --no-cleanup, if it is supported by the builtin.
+ //
+ if (cln && args[i] == "--no-cleanup")
+ {
+ cln->enabled = false;
+ return 1;
+ }
+
+ return 0;
+ },
+
+ // sleep
+ //
+ // Deactivate the thread before going to sleep.
+ //
+ [&sp] (const duration& d)
+ {
+ // If/when required we could probably support the precise sleep
+ // mode (e.g., via an option).
+ //
+ sp.root.test_target.ctx.sched.sleep (d);
+ }
+ };
+
try
{
uint8_t r; // Storage.
- builtin b (
- bf (sp, r, c.arguments, move (ifd), move (ofd.out), move (efd)));
+ builtin b (bf (r,
+ c.arguments,
+ move (ifd), move (ofd.out), move (efd),
+ sp.wd_path,
+ bcs));
success = run_pipe (sp,
nc,