aboutsummaryrefslogtreecommitdiff
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
parent6e84c0f9c5e4d7d98d2a352eec6bc19de0d75d28 (diff)
Move testscript builtins to libbutl
-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
-rw-r--r--tests/test/script/builtin/buildfile2
-rw-r--r--tests/test/script/builtin/cat.testscript90
-rw-r--r--tests/test/script/builtin/cp-dir/cp-file0
-rw-r--r--tests/test/script/builtin/cp.testscript367
-rw-r--r--tests/test/script/builtin/echo.testscript27
-rw-r--r--tests/test/script/builtin/ln.testscript180
-rw-r--r--tests/test/script/builtin/mkdir.testscript95
-rw-r--r--tests/test/script/builtin/mv.testscript231
-rw-r--r--tests/test/script/builtin/rm.testscript93
-rw-r--r--tests/test/script/builtin/rmdir.testscript82
-rw-r--r--tests/test/script/builtin/sed.testscript355
-rw-r--r--tests/test/script/builtin/sleep.testscript28
-rw-r--r--tests/test/script/builtin/test.testscript85
-rw-r--r--tests/test/script/builtin/touch.testscript97
21 files changed, 443 insertions, 7525 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,
diff --git a/tests/test/script/builtin/buildfile b/tests/test/script/builtin/buildfile
index ca594ff..f5b719d 100644
--- a/tests/test/script/builtin/buildfile
+++ b/tests/test/script/builtin/buildfile
@@ -2,4 +2,4 @@
# copyright : Copyright (c) 2014-2019 Code Synthesis Ltd
# license : MIT; see accompanying LICENSE file
-./: testscript{*} file{cp-dir/cp-file} $b
+./: testscript{*} $b
diff --git a/tests/test/script/builtin/cat.testscript b/tests/test/script/builtin/cat.testscript
deleted file mode 100644
index b23efcf..0000000
--- a/tests/test/script/builtin/cat.testscript
+++ /dev/null
@@ -1,90 +0,0 @@
-# file : tests/test/script/builtin/cat.testscript
-# copyright : Copyright (c) 2014-2019 Code Synthesis Ltd
-# license : MIT; see accompanying LICENSE file
-
-.include ../common.testscript
-
-: unknown-option
-:
-$c <<EOI && $b
-cat -u 2>"cat: unknown option '-u'" == 1
-EOI
-
-: in
-:
-$c <<EOI && $b
-cat <<EOF >>EOO
-foo
-bar
-EOF
-foo
-bar
-EOO
-EOI
-
-: dash
-:
-$c <<EOI && $b
-cat - <<EOF >>EOO
-foo
-bar
-EOF
-foo
-bar
-EOO
-EOI
-
-: file
-:
-$c <<EOI && $b
-cat <<EOF >=out;
-foo
-bar
-EOF
-cat out >>EOO
-foo
-bar
-EOO
-EOI
-
-: in-repeat
-:
-$c <<EOI && $b
-cat - <<EOF >>EOO
-foo
-bar
-EOF
-foo
-bar
-EOO
-EOI
-
-: non-existent
-:
-$c <<EOI && $b
-cat in 2>>/~%EOE% != 0
-%cat: unable to print '.+/test/cat/non-existent/test/1/in': .+%
-EOE
-EOI
-
-: empty-path
-:
-: Cat an empty path.
-:
-$c <<EOI && $b
-cat '' 2>"cat: invalid path ''" == 1
-EOI
-
-: big
-:
-: Cat a big file (about 100K) to test that the builtin is asynchronous.
-:
-{
- $c <<EOI && $b
- s="--------------------------------"
- s="$s$s$s$s$s$s$s$s$s$s$s$s$s$s$s$s"
- s="$s$s$s$s$s$s$s$s$s$s$s$s$s$s$s$s"
- s="$s$s$s$s$s$s$s$s$s$s$s$s$s$s$s$s"
- cat <"$s" | cat >"$s"
- EOI
-}
diff --git a/tests/test/script/builtin/cp-dir/cp-file b/tests/test/script/builtin/cp-dir/cp-file
deleted file mode 100644
index e69de29..0000000
--- a/tests/test/script/builtin/cp-dir/cp-file
+++ /dev/null
diff --git a/tests/test/script/builtin/cp.testscript b/tests/test/script/builtin/cp.testscript
index 60497b1..802cfee 100644
--- a/tests/test/script/builtin/cp.testscript
+++ b/tests/test/script/builtin/cp.testscript
@@ -4,109 +4,29 @@
.include ../common.testscript
-: unknown-option
-:
-$c <<EOI && $b
-cp -u 2>"cp: unknown option '-u'" == 1
-EOI
-
-: args
-:
-{
- : none
- :
- $c <'cp 2>"cp: missing arguments" == 1' && $b
-
- : no-source
- :
- $c <'cp -R a 2>"cp: missing source path" == 1' && $b
-
- : no-trailing-sep
- :
- $c <<EOI && $b
- cp a b c 2>"cp: multiple source paths without trailing separator for destination directory" == 1
- EOI
-
- : empty
- :
- {
- : dest
- :
- $c <<EOI && $b
- cp '' 2>"cp: invalid path ''" == 1
- EOI
-
- : src1
- :
- $c <<EOI && $b
- cp '' a 2>"cp: invalid path ''" == 1
- EOI
-
- : src2
- :
- $c <<EOI && $b
- cp '' a b/ 2>"cp: invalid path ''" == 1
- EOI
- }
-}
-
: file
:
: Test synopsis 1: make a file copy at the specified path.
:
{
- : existing
+ : cleanup
:
{
- : to-non-existing
- :
- $c <<EOI && $b
- touch a;
- cp a b && test -f b
- EOI
-
- : to-existing
+ : enabled
:
$c <<EOI && $b
- touch a b;
- cp a b
- EOI
+ touch a;
+ cp a b
+ EOI
- : to-dir
+ : disabled
:
$c <<EOI && $b
- touch a;
- mkdir b;
- cp a b 2>>/~%EOE% != 0
- %cp: unable to copy file '.+/a' to '.+/b': .+%
- EOE
- EOI
- }
-
- : non-existing
- :
- {
- $c <<EOI && $b
- cp a b 2>>/~%EOE% != 0
- %cp: unable to copy file '.+/a' to '.+/b': .+%
- EOE
- EOI
- }
-
- : non-file
- :
- {
- $c <<EOI && $b
- mkdir a;
- cp a b 2>>/~%EOE% != 0
- %cp: unable to copy file '.+/a' to '.+/b': .+%
- EOE
- EOI
- }
+ touch a;
+ cp --no-cleanup a b;
+ rm b
+ EOI
- : cleanup
- :
- {
: existing
:
: Test that copy over an existing file does not register cleanup. If it
@@ -114,12 +34,12 @@ EOI
: and so the cleanup registered by the outer touch would fail.
:
$c <<EOI && $b
- +touch b
- {
- touch a;
- cp a ../b
- }
- EOI
+ +touch b
+ {
+ touch a;
+ cp a ../b
+ }
+ EOI
}
}
@@ -128,66 +48,22 @@ EOI
: Test synopsis 2: make a directory copy at the specified path.
:
{
- : existing
+ : cleanup
:
- {
- : to-non-existing
- :
- $c <<EOI && $b
- mkdir a;
- cp -r a b && test -d b
- EOI
-
- : to-existing
- :
- $c <<EOI && $b
- mkdir a b;
- cp -R a b 2>>/~%EOE% != 0
- %cp: unable to copy directory '.+/a' to '.+/b': .+%
- EOE
- EOI
-
- : to-file
- :
- $c <<EOI && $b
+ $c <<EOI && $b
mkdir a;
- touch b;
- cp -r a b 2>>/~%EOE% != 0
- %cp: unable to copy directory '.+/a' to '.+/b': .+%
- EOE
- EOI
-
- : recursively
- :
- {
- $c <<EOI && $b
- mkdir -p a/b/c;
- touch a/x a/b/y;
- cp -r a d && test -d d/b/c && test -f d/x && test -f d/b/y
- EOI
- }
- }
-
- : non-existing
- :
- {
- $c <<EOI && $b
- cp -r a b 2>>/~%EOE% != 0
- %cp: unable to copy directory '.+/a' to '.+/b': .+%
- EOE
+ touch a/b;
+ cp -r a b
EOI
- }
- : non-dir
+ : no-cleanup
:
- {
- $c <<EOI && $b
- touch a;
- cp -r a b 2>>/~%EOE% != 0
- %cp: unable to copy directory '.+/a' to '.+/b': .+%
- EOE
+ $c <<EOI && $b
+ mkdir a;
+ touch a/b;
+ cp --no-cleanup -r a b;
+ rm -r b
EOI
- }
}
: files
@@ -195,83 +71,22 @@ EOI
: Test synopsis 3: copy files into the specified directory.
:
{
- : existing
+ : cleanup
:
- {
- : into-dir
- :
- {
- : over-non-existing
- :
- $c <<EOI && $b
- mkdir b;
- touch a;
- cp a b/ && test -f b/a
- EOI
-
- : over-dir
- :
- $c <<EOI && $b
- mkdir -p b/a;
- touch a;
- cp a b/ 2>>/~%EOE% != 0
- %cp: unable to copy file '.+/a' to '.+/b/a': .+%
- EOE
- EOI
-
- : multiple
- :
- $c <<EOI && $b
+ $c <<EOI && $b
touch a b;
mkdir c;
- cp a b c/ && test -f c/a && test -f c/b
- EOI
- }
-
- : into-non-existing-dir
- :
- {
- $c <<EOI && $b
- touch a;
- cp a b/ 2>>/~%EOE% != 0
- %cp: unable to copy file '.+/a' to '.+/b/a': .+%
- EOE
+ cp a b c/
EOI
- }
- : into-non-dir
- :
- {
- $c <<EOI && $b
- touch a b;
- cp a b/ 2>>/~%EOE% != 0
- %cp: unable to copy file '.+/a' to '.+/b/a': .+%
- EOE
- EOI
- }
- }
-
- : non-existing
- :
- {
- $c <<EOI && $b
- mkdir b;
- cp a b/ 2>>/~%EOE% != 0
- %cp: unable to copy file '.+/a' to '.+/b/a': .+%
- EOE
- EOI
- }
-
- : non-file
+ : no-cleanup
:
- {
$c <<EOI && $b
- mkdir a b;
- cp a b/ 2>>/~%EOE% != 0
- %cp: unable to copy file '.+/a' to '.+/b/a': .+%
- EOE
- EOI
- }
+ touch a b;
+ mkdir c;
+ cp --no-cleanup a b c/;
+ rm c/a c/b
+ EOI
}
: filesystem-entries
@@ -279,112 +94,20 @@ EOI
: Test synopsis 4: copy filesystem entries into the specified directory.
:
{
- : file
+ : cleanup
:
- {
- $c <<EOI && $b
- mkdir b;
- touch a;
- cp -R a b/ && test -f b/a
+ $c <<EOI && $b
+ mkdir a b;
+ touch c a/c;
+ cp -R a c b/
EOI
- }
- : dir
+ : no-cleanup
:
- {
- : over-non-existing
- :
- $c <<EOI && $b
+ $c <<EOI && $b
mkdir a b;
- touch a/c;
- cp -R a b/ && test -f b/a/c
- EOI
-
- : over-existing
- :
- $c <<EOI && $b
- mkdir -p a b/a;
- cp -R a b/ 2>>/~%EOE% != 0
- %cp: unable to copy directory '.+/a' to '.+/b/a': .+%
- EOE
+ touch c a/c;
+ cp --no-cleanup -R a c b/;
+ rm -r b/a/ b/c
EOI
- }
-}
-
-: attrs
-:
-if ($cxx.target.class != 'windows')
-{
- fs = 's/.+ (\S+\s+\S+\s+\S+)\s+cp-file/\1/p'
- ds = 's/.+ (\S+\s+\S+\s+\S+)\s+cp-dir/\1/p'
-
- : copy
- :
- {
- : file
- :
- {
- $c <<"EOI" && $b
- ls -l $src_base/cp-dir | sed -n -e '$fs' | \
- set t;
-
- cp -p $src_base/cp-dir/cp-file ./;
- ls -l | sed -n -e '$fs' >"\$t"
- EOI
- }
-
- : dir
- :
- {
- $c <<"EOI" && $b
- ls -l $src_base | sed -n -e '$ds' | \
- set t;
-
- cp -pr $src_base/cp-dir ./;
- ls -l | sed -n -e '$ds' >"\$t"
- EOI
- }
- }
-
- : no-copy
- :
- {
- : file
- :
- {
- $c <<"EOI" && $b 2>>~%EOE% != 0
- ls -l $src_base/cp-dir | sed -n -e '$fs' | \
- set t;
-
- cp $src_base/cp-dir/cp-file ./;
- ls -l | sed -n -e '$fs' >"\$t"
- EOI
- %.+ error: sed stdout doesn't match expected%
- %.+
- EOE
- }
-
- : dir
- :
- : Note that the `ls -l` command by default displays the filesystem entry
- : modification time with the minute resolution and the build2 dist
- : meta-operation (involved when we fetch from the git repository
- : location) doesn't preserve the directory modification time. That's why
- : we also pass --full-time and enable the test for only platforms where ls
- : supports this option.
- :
- if ($cxx.target.class == 'linux')
- {
- $c <<"EOI" && $b 2>>~%EOE% != 0
- ls -l --full-time $src_base | sed -n -e '$ds' | \
- set t;
-
- cp -r $src_base/cp-dir ./;
- ls -l --full-time | sed -n -e '$ds' >"\$t"
- EOI
- %.+ error: sed stdout doesn't match expected%
- %.+
- EOE
- }
- }
}
diff --git a/tests/test/script/builtin/echo.testscript b/tests/test/script/builtin/echo.testscript
deleted file mode 100644
index 3227e89..0000000
--- a/tests/test/script/builtin/echo.testscript
+++ /dev/null
@@ -1,27 +0,0 @@
-# file : tests/test/script/builtin/echo.testscript
-# copyright : Copyright (c) 2014-2019 Code Synthesis Ltd
-# license : MIT; see accompanying LICENSE file
-
-.include ../common.testscript
-
-: string
-:
-$c <'echo foo >foo' && $b
-
-: strings
-:
-$c <'echo foo bar >"foo bar"' && $b
-
-: big
-:
-: Echo a big string (about 100K) to test that the builtin is asynchronous.
-:
-{
- $c <<EOI && $b
- s="--------------------------------"
- s="$s$s$s$s$s$s$s$s$s$s$s$s$s$s$s$s"
- s="$s$s$s$s$s$s$s$s$s$s$s$s$s$s$s$s"
- s="$s$s$s$s$s$s$s$s$s$s$s$s$s$s$s$s"
- echo "$s" | cat >"$s"
- EOI
-}
diff --git a/tests/test/script/builtin/ln.testscript b/tests/test/script/builtin/ln.testscript
index 072c197..456126a 100644
--- a/tests/test/script/builtin/ln.testscript
+++ b/tests/test/script/builtin/ln.testscript
@@ -4,119 +4,25 @@
.include ../common.testscript
-: unknown-option
-:
-$c <<EOI && $b
-ln -u 2>"ln: unknown option '-u'" == 1
-EOI
-
-: args
-:
-{
- : -s-option
- :
- $c <'ln 2>"ln: missing -s|--symbolic option" == 1' && $b
-
- : none
- :
- $c <'ln -s 2>"ln: missing arguments" == 1' && $b
-
- : no-target
- :
- $c <'ln -s a 2>"ln: missing target path" == 1' && $b
-
- : no-trailing-sep
- :
- $c <<EOI && $b
- ln -s a b c 2>"ln: multiple target paths with non-directory link path" == 1
- EOI
-
- : empty
- :
- {
- : link
- :
- $c <<EOI && $b
- ln -s '' 2>"ln: invalid path ''" == 1
- EOI
-
- : target1
- :
- $c <<EOI && $b
- ln -s '' a 2>"ln: invalid path ''" == 1
- EOI
-
- : target2
- :
- $c <<EOI && $b
- ln -s '' a b/ 2>"ln: invalid path ''" == 1
- EOI
- }
-}
-
: file
:
: Test creating a file symlink.
:
{
- : non-existing-link-path
+ : cleanup
:
$c <<EOI && $b
- touch a;
- ln -s a b && test -f b
- EOI
-
- : existing-link
- :
- {
- : file
- :
- $c <<EOI && $b
- touch a b;
- ln -s a b 2>>/~%EOE% != 0
- %(
- %ln: unable to create .+link '.+/b' to '.+/a': .+%|
- %ln: unable to copy file '.+/a' to '.+/b': .+%
- %)
- EOE
- EOI
-
- : dir
- :
- $c <<EOI && $b
touch a;
- mkdir b;
- ln -s a b 2>>/~%EOE% != 0
- %(
- %ln: unable to create .+link '.+/b' to '.+/a': .+%|
- %ln: unable to copy file '.+/a' to '.+/b': .+%
- %)
- EOE
- EOI
- }
-
- : non-existing
- {
- : target
- :
- $c <<EOI && $b
- ln -s a b 2>>/~%EOE% != 0
- %ln: unable to create symlink to '.+/a': no such file or directory%
- EOE
+ ln -s a b
EOI
- : link-dir
- :
- $c <<EOI && $b
+ : no-cleanup
+ :
+ $c <<EOI && $b
touch a;
- ln -s a b/c 2>>/~%EOE% != 0
- %(
- %ln: unable to create .+link '.+/b/c' to '.+/a': .+%|
- %ln: unable to copy file '.+/a' to '.+/b/c': .+%
- %)
- EOE
+ ln -s --no-cleanup a b;
+ rm b
EOI
- }
}
: dir
@@ -124,57 +30,22 @@ EOI
: Test creating a directory symlink.
:
{
- : non-existing-link-path
+ : cleanup
:
$c <<EOI && $b
- mkdir a;
- touch a/b;
- ln -s a c && test -f c/b
- EOI
-
- : existing-link
- :
- {
- : dir
- :
- $c <<EOI && $b
- mkdir a b;
- ln -s a b 2>>/~%EOE% != 0
- %(
- %ln: unable to create .+link '.+/b' to '.+/a': .+%|
- %ln: unable to copy directory '.+/a' to '.+/b': .+%
- %)
- EOE
- EOI
-
- : file
- :
- $c <<EOI && $b
mkdir a;
- touch b;
- ln -s a b 2>>/~%EOE% != 0
- %(
- %ln: unable to create .+link '.+/b' to '.+/a': .+%|
- %ln: unable to copy directory '.+/a' to '.+/b': .+%
- %)
- EOE
+ touch a/b;
+ ln -s a c
EOI
- }
- : non-existing
- {
- : link-dir
- :
- $c <<EOI && $b
+ : no-cleanup
+ :
+ $c <<EOI && $b
mkdir a;
- ln -s a b/c 2>>/~%EOE% != 0
- %(
- %ln: unable to create .+link '.+/b/c' to '.+/a': .+%|
- %ln: unable to copy directory '.+/a' to '.+/b/c': .+%
- %)
- EOE
+ touch a/b;
+ ln -s --no-cleanup a c;
+ rm -r c
EOI
- }
}
: multiple-targets
@@ -182,9 +53,20 @@ EOI
: Test creating links for multiple targets in the specified directory.
:
{
+ : cleanup
+ :
$c <<EOI && $b
- touch a;
- mkdir b c;
- ln -s a b c/ && test -f c/a && test -d c/b
- EOI
+ mkdir b c;
+ touch a b/c;
+ ln -s a b c/
+ EOI
+
+ : no-cleanup
+ :
+ $c <<EOI && $b
+ mkdir b c;
+ touch a b/c;
+ ln -s --no-cleanup a b c/;
+ rm -r c/a c/b
+ EOI
}
diff --git a/tests/test/script/builtin/mkdir.testscript b/tests/test/script/builtin/mkdir.testscript
index d1a3b4a..00fc5cf 100644
--- a/tests/test/script/builtin/mkdir.testscript
+++ b/tests/test/script/builtin/mkdir.testscript
@@ -4,69 +4,38 @@
.include ../common.testscript
-: unknown-option
-:
-$c <<EOI && $b
-mkdir -u 2>"mkdir: unknown option '-u'" == 1
-EOI
-
-: dirs
-:
-$c <<EOI && $b
-mkdir a b;
-touch a/a b/b
-EOI
+: dir
+:
+{
+ : cleanup
+ :
+ $c <<EOI && $b
+ mkdir a b
+ EOI
+
+ : no-cleanup
+ :
+ : Also test that `--` is handled properly.
+ :
+ $c <<EOI && $b
+ mkdir --no-cleanup -- --no-cleanup;
+ rmdir -- --no-cleanup
+ EOI
+}
: parent
:
-$c <<EOI && $b
-mkdir -p a/b;
-touch a/a a/b/b
-EOI
-
-: exists
-:
-$c <'mkdir -p a a a/b a/b' && $b
-
-: double-dash
-:
-: Make sure '-p' directory is created.
-:
-$c <<EOI && $b
-mkdir -p -- -p;
-touch -- -p/a
-EOI
-
-: no-args
-:
-: Test passing no arguments.
-:
-$c <'mkdir 2>"mkdir: missing directory" == 1' && $b
-
-: empty-path
-:
-: Test creation of empty directory path.
-:
-$c <<EOI && $b
-mkdir '' 2>"mkdir: invalid path ''" == 1
-EOI
-
-: already-exists
-:
-: Test creation of an existing directory.
-:
-$c <<EOI && $b
-mkdir a a 2>>/~%EOE% == 1
-%mkdir: unable to create directory '.+/test/mkdir/already-exists/test/1/a': .+%
-EOE
-EOI
-
-: not-exists
-:
-: Test creation of a directory with non-existent parent.
-:
-$c <<EOI && $b
-mkdir a/b 2>>/~%EOE% == 1
-%mkdir: unable to create directory '.+/test/mkdir/not-exists/test/1/a/b': .+%
-EOE
-EOI
+{
+ : cleanup
+ :
+ $c <<EOI && $b
+ mkdir -p a/b
+ EOI
+
+ : no-cleanup
+ :
+ $c <<EOI && $b
+ mkdir -p --no-cleanup a/b;
+ rm -r a
+ EOI
+}
diff --git a/tests/test/script/builtin/mv.testscript b/tests/test/script/builtin/mv.testscript
index eb4860e..d703faf 100644
--- a/tests/test/script/builtin/mv.testscript
+++ b/tests/test/script/builtin/mv.testscript
@@ -4,52 +4,6 @@
.include ../common.testscript
-: unknown-option
-:
-$c <<EOI && $b
-mv -u 2>"mv: unknown option '-u'" == 1
-EOI
-
-: args
-:
-{
- : none
- :
- $c <'mv 2>"mv: missing arguments" == 1' && $b
-
- : no-source
- :
- $c <'mv a 2>"mv: missing source path" == 1' && $b
-
- : no-trailing-sep
- :
- $c <<EOI && $b
- mv a b c 2>"mv: multiple source paths without trailing separator for destination directory" == 1
- EOI
-
- : empty
- :
- {
- : dest
- :
- $c <<EOI && $b
- mv '' 2>"mv: invalid path ''" == 1
- EOI
-
- : src1
- :
- $c <<EOI && $b
- mv '' a 2>"mv: invalid path ''" == 1
- EOI
-
- : src2
- :
- $c <<EOI && $b
- mv '' a b/ 2>"mv: invalid path ''" == 1
- EOI
- }
-}
-
: synopsis-1
:
: Move an entity to the specified path.
@@ -58,43 +12,6 @@ EOI
: file
:
{
- : existing
- :
- {
- : to-non-existing
- :
- $c <<EOI && $b
- touch a;
- mv a b && test -f b && test -f a == 1
- EOI
-
- : to-existing
- :
- $c <<EOI && $b
- touch a b;
- mv a b && test -f b && test -f a == 1
- EOI
-
- : to-self
- :
- $c <<EOI && $b
- touch a;
- mv a a 2>>/~%EOE% != 0
- %mv: unable to move entity '.+/a' to itself%
- EOE
- EOI
-
- : to-dir
- :
- $c <<EOI && $b
- touch a;
- mkdir b;
- mv a b 2>>/~%EOE% != 0
- %mv: unable to move entity '.+/a' to '.+/b': .+%
- EOE
- EOI
- }
-
: outside-scope
:
: Need to use a path that unlikely exists (not to remove something useful).
@@ -105,10 +22,10 @@ EOI
: Moving path outside the testscript working directory fails.
:
$c <<EOI && $b
- mv ../../a/b/c ./c 2>>/~%EOE% == 1
- %mv: '.+/fail/a/b/c' is out of working directory '.+/fail/test'%
- EOE
- EOI
+ mv ../../a/b/c ./c 2>>/~%EOE% == 1
+ %mv: '.+/fail/a/b/c' is out of working directory '.+/fail/test'%
+ EOE
+ EOI
: force
:
@@ -117,15 +34,30 @@ EOI
: exist.
:
$c <<EOI && $b
- mv -f ../../a/b/c ./c 2>>/~%EOE% == 1
- %mv: unable to move entity '.+/force/a/b/c' to '.+/c': .+%
- EOE
- EOI
+ mv -f ../../a/b/c ./c 2>>/~%EOE% == 1
+ %mv: unable to move entity '.+/force/a/b/c' to '.+/c': .+%
+ EOE
+ EOI
}
: cleanup
:
{
+ : enabled
+ :
+ $c <<EOI && $b
+ touch a;
+ mv a b
+ EOI
+
+ : disabled
+ :
+ $c <<EOI && $b
+ touch a;
+ mv --no-cleanup a b &!a;
+ rm b
+ EOI
+
: existing
:
: Test that moving over an existing file does not move the cleanup. If
@@ -135,91 +67,60 @@ EOI
: fail.
:
$c <<EOI && $b
- +touch b
- {
- touch a;
- mv a ../b
- }
- EOI
+ +touch b
+ {
+ touch a;
+ mv a ../b
+ }
+ EOI
}
}
: dir
:
{
- : existing
+ : working-dir
:
{
- : to-non-existing
- :
- : Note the here we also test that b path is cleaned up as a directory.
- :
- $c <<EOI && $b
- mkdir a;
- mv a b && test -d b && test -d a == 1
- EOI
-
- : to-non-empty
+ : src
:
$c <<EOI && $b
- mkdir a b;
- touch b/c;
- mv a b 2>>/~%EOE% != 0
- %mv: unable to move entity '.+/a' to '.+/b': .+%
- EOE
- EOI
+ mv $~ b 2>"mv: '$~' contains test working directory '$~'" != 0
+ EOI
- : to-non-dir
+ : dst
:
$c <<EOI && $b
- mkdir a;
- touch b;
- mv a b 2>>/~%EOE% != 0
- %mv: unable to move entity '.+/a' to '.+/b': .+%
- EOE
- EOI
+ mkdir a;
+ mv a "$~" 2>"mv: '$~' contains test working directory '$~'" != 0
+ EOI
}
- : working-dir
+ : cleanup
:
{
- : src
+ : enabled
:
- {
- $c <<EOI && $b
- mv $~ b 2>"mv: '([string] $~)' contains test working directory '$~'" != 0
+ $c <<EOI && $b
+ mkdir a;
+ mv a b
EOI
- }
- : dst
+ : disabled
:
- {
- $c <<EOI && $b
+ $c <<EOI && $b
mkdir a;
- mv a "$~" 2>"mv: '$~' contains test working directory '$~'" != 0
+ mv --no-cleanup a b &!a/;
+ rm -r b
EOI
- }
- }
-
- : overlap
- :
- $c <<EOI && $b
- mkdir a;
- mv a a/b 2>>/~%EOE% != 0
- %mv: unable to move entity '.+/a' to '.+/a/b': .+%
- EOE
- EOI
- : cleanup
- :
- {
: sub-entry
:
- {
+ $c <<EOI && $b
mkdir a;
touch a/b;
mv a c
- }
+ EOI
: reorder
:
@@ -227,21 +128,11 @@ EOI
: it, get removed before b/ after being renamed to b/c.
:
$c <<EOI && $b
- mkdir a b;
- mv a b/c
- EOI
+ mkdir a b;
+ mv a b/c
+ EOI
}
}
-
- : non-existing
- :
- {
- $c <<EOI && $b
- mv a b 2>>/~%EOE% != 0
- %mv: unable to move entity '.+/a' to '.+/b': .+%
- EOE
- EOI
- }
}
: synopsis-2
@@ -249,10 +140,20 @@ EOI
: Move entities into the specified directory.
:
{
+ : cleanup
+ :
$c <<EOI && $b
- mkdir a c;
- touch a/b b;
- mv a b c/;
- test -d c/a && test -f c/a/b && test -f c/b
- EOI
+ mkdir a c;
+ touch a/b b;
+ mv a b c/
+ EOI
+
+ : no-cleanup
+ :
+ $c <<EOI && $b
+ mkdir a c;
+ touch a/b b;
+ mv --no-cleanup a b c/ &!a/ &!a/b &!b;
+ rm -r c/a/ c/b
+ EOI
}
diff --git a/tests/test/script/builtin/rm.testscript b/tests/test/script/builtin/rm.testscript
index 46ed566..7160c73 100644
--- a/tests/test/script/builtin/rm.testscript
+++ b/tests/test/script/builtin/rm.testscript
@@ -4,102 +4,21 @@
.include ../common.testscript
-: unknown-option
-:
-$c <<EOI && $b
-rm -u 2>"rm: unknown option '-u'" == 1
-EOI
-
-: no-args
-:
-{
- : fail
- :
- : Removing with no arguments fails.
- :
- $c <'rm 2>"rm: missing file" == 1' && $b
-
- : force
- :
- : Removing with no arguments succeeds with -f option.
- :
- $c <'rm -f' && $b
-}
-
-: file
-:
-{
- : exists
- :
- : Removing existing file succeeds.
- :
- $c <<EOI && $b
- touch a &!a;
- rm a
- EOI
-
- : not-exists
- :
- {
- : fail
- :
- : Removing non-existing file fails.
- :
- $c <<EOI && $b
- rm a 2>>/~%EOE% == 1
- %rm: unable to remove '.+/file/not-exists/fail/test/1/a': .+%
- EOE
- EOI
-
- : force
- :
- : Removing non-existing file succeeds with -f option.
- :
- $c <'rm -f a' && $b
- }
-}
-
: dir
:
{
- : default
- :
- : Removing directory fails by default.
- :
- $c <<EOI && $b
- mkdir a;
- rm a 2>"rm: '$normalize([path] $~/a)' is a directory" == 1
- EOI
-
- : recursive
- :
- : Removing directory succeeds with -r option.
- :
- $c <<EOI && $b
- mkdir -p a/b &!a &!a/b;
- rm -r a
- EOI
-
: scope
:
: Removing scope directory fails.
:
$c <<EOI && $b
- rm -r ./ 2>"rm: '([string] $~)' contains test working directory '$~'" == 1
- EOI
+ rm -r ./ 2>"rm: '$~' contains test working directory '$~'" == 1
+ EOI
}
: path
:
{
- : empty
- :
- : Removing an empty path fails.
- :
- $c <<EOI && $b
- rm '' 2>"rm: invalid path ''" == 1
- EOI
-
: outside-scope
:
: Need to use a path that unlikely exists (not to remove something useful).
@@ -110,10 +29,10 @@ EOI
: Removing path outside the testscript working directory fails.
:
$c <<EOI && $b
- rm ../../a/b/c 2>>/~%EOE% == 1
- %rm: '.+/path/outside-scope/fail/a/b/c' is out of working directory '.+/path/outside-scope/fail/test'%
- EOE
- EOI
+ rm ../../a/b/c 2>>/~%EOE% == 1
+ %rm: '.+/path/outside-scope/fail/a/b/c' is out of working directory '.+/path/outside-scope/fail/test'%
+ EOE
+ EOI
: force
:
diff --git a/tests/test/script/builtin/rmdir.testscript b/tests/test/script/builtin/rmdir.testscript
index 9f0c945..897b5f4 100644
--- a/tests/test/script/builtin/rmdir.testscript
+++ b/tests/test/script/builtin/rmdir.testscript
@@ -4,39 +4,9 @@
.include ../common.testscript
-: unknown-option
-:
-$c <<EOI && $b
-rmdir -u 2>"rmdir: unknown option '-u'" == 1
-EOI
-
-: no-args
-:
-{
- : fail
- :
- : Removing with no arguments fails.
- :
- $c <'rmdir 2>"rmdir: missing directory" == 1' && $b
-
- : force
- :
- : Removing with no arguments succeeds with -f option.
- :
- $c <'rmdir -f' && $b
-}
-
: dir
:
{
- : empty-path
- :
- : Removing an empty path fails.
- :
- $c <<EOI && $b
- rmdir '' 2>"rmdir: invalid path ''" == 1
- EOI
-
: test-scope
:
: Removing scope directory fails.
@@ -56,7 +26,7 @@ EOI
:
$c <<EOI && $b
rmdir ../../a/b/c 2>>/~%EOE% == 1
- %rmdir: '.+/dir/outside-scope/fail/a/b/c' is out of working directory '.+/dir/outside-scope/fail/test'%
+ %rmdir: '.+/dir/outside-scope/fail/a/b/c/' is out of working directory '.+/dir/outside-scope/fail/test'%
EOE
EOI
@@ -67,54 +37,4 @@ EOI
:
$c <'rmdir -f ../../a/b/c' && $b
}
-
- : exists
- :
- : Removing existing directory succeeds.
- :
- $c <<EOI && $b
- mkdir a &!a;
- rmdir a
- EOI
-
- : not-exists
- :
- {
- : fail
- : Removing non-existing directory fails.
- :
- $c <<EOI && $b
- rmdir a 2>>/~%EOE% == 1
- %rmdir: unable to remove '.+/dir/not-exists/fail/test/1/a': .+%
- EOE
- EOI
-
- : force
- :
- : Removing non-existing directory succeeds with -f option.
- :
- $c <'rmdir -f a' && $b
- }
-
- : not-empty
- :
- : Removing non-empty directory fails.
- :
- $c <<EOI && $b
- mkdir -p a/b;
- rmdir a 2>>/~%EOE% == 1
- %rmdir: unable to remove '.+/dir/not-empty/test/1/a': .+%
- EOE
- EOI
-
- : not-dir
- :
- : Removing not a directory path fails.
- :
- $c <<EOI && $b
- touch a;
- rmdir a 2>>/~%EOE% == 1
- %rmdir: unable to remove '.+/dir/not-dir/test/1/a': .+%
- EOE
- EOI
}
diff --git a/tests/test/script/builtin/sed.testscript b/tests/test/script/builtin/sed.testscript
deleted file mode 100644
index 4a79fe3..0000000
--- a/tests/test/script/builtin/sed.testscript
+++ /dev/null
@@ -1,355 +0,0 @@
-# file : tests/test/script/builtin/sed.testscript
-# copyright : Copyright (c) 2014-2019 Code Synthesis Ltd
-# license : MIT; see accompanying LICENSE file
-
-.include ../common.testscript
-
-: unknown-option
-:
-$c <<EOI && $b
-sed -u 2>"sed: unknown option '-u'" == 1
-EOI
-
-: arg
-:
-{
- : auto-prn
- :
- {
- $c <"sed -n -e 's/fox/bar/' <'foo' " && $b : on
- $c <"sed -e 's/fox/bar/' <'foo' >'foo'" && $b : off
- }
-
- : script
- :
- {
- : missed
- :
- $c <'sed' && $b 2>>/EOE != 0
- testscript:1:1: error: sed exit code 1 != 0
- info: stderr: test/1/stderr
- sed: missing script
- info: test id: 1
- EOE
-
- : missed-val
- :
- $c <'sed -e' && $b 2>>/EOE != 0
- testscript:1:1: error: sed exit code 1 != 0
- info: stderr: test/1/stderr
- sed: missing value for option '-e'
- info: test id: 1
- EOE
-
- : empty
- :
- $c <"sed -e ''" && $b 2>>/EOE != 0
- testscript:1:1: error: sed exit code 1 != 0
- info: stderr: test/1/stderr
- sed: empty script
- info: test id: 1
- EOE
-
- : multiple
- :
- $c <"sed -e 's/a//' -e 's/a//'" && $b 2>>/EOE != 0
- testscript:1:1: error: sed exit code 1 != 0
- info: stderr: test/1/stderr
- sed: multiple scripts
- info: test id: 1
- EOE
-
- : invalid
- :
- $c <"sed -e 'z'" && $b 2>>/EOE != 0
- testscript:1:1: error: sed exit code 1 != 0
- info: stderr: test/1/stderr
- sed: only 's' command supported
- info: test id: 1
- EOE
- }
-
- : file
- :
- {
- : exist
- :
- $c <<EOI && $b
- cat <'foo' >=f;
- sed -e 's/foo/bar/' f >'bar'
- EOI
-
- : none
- :
- $c <<EOI && $b
- sed -e 's/foo/bar/' <'foo' >'bar'
- EOI
-
- : dash
- :
- $c <<EOI && $b
- sed -e 's/foo/bar/' - <'foo' >'bar'
- EOI
-
- : not-exist
- :
- $c <"sed -e 's/foo/bar/' f" && $b 2>>/~%EOE% != 0
- testscript:1:1: error: sed exit code 1 != 0
- info: stderr: test/1/stderr
- %sed: unable to edit '.+/1/f': .+%
- info: test id: 1
- EOE
-
- : empty
- :
- $c <"sed -e 's/foo/bar/' ''" && $b 2>>/EOE != 0
- testscript:1:1: error: sed exit code 1 != 0
- info: stderr: test/1/stderr
- sed: invalid path ''
- info: test id: 1
- EOE
- }
-
- : unexpected
- :
- $c <"sed -e 's/a//' a b" && $b 2>>/EOE != 0
- testscript:1:1: error: sed exit code 1 != 0
- info: stderr: test/1/stderr
- sed: unexpected argument 'b'
- info: test id: 1
- EOE
-}
-
-: command
-:
-{
- : subst
- :
- {
- : parsing
- :
- {
- : delim
- :
- {
- : none
- :
- $c <"sed -e 's'" && $b 2>>/EOE != 0
- testscript:1:1: error: sed exit code 1 != 0
- info: stderr: test/1/stderr
- sed: no delimiter for 's' command
- info: test id: 1
- EOE
-
- : invalid
- :
- $c <"sed -e 's\\'" && $b 2>>/EOE != 0
- testscript:1:1: error: sed exit code 1 != 0
- info: stderr: test/1/stderr
- sed: invalid delimiter for 's' command
- info: test id: 1
- EOE
- }
-
- : regex
- :
- {
- : unterminated
- :
- $c <"sed -e 's/foo'" && $b 2>>/EOE != 0
- testscript:1:1: error: sed exit code 1 != 0
- info: stderr: test/1/stderr
- sed: unterminated 's' command regex
- info: test id: 1
- EOE
-
- : empty
- :
- $c <"sed -e 's///'" && $b 2>>/EOE != 0
- testscript:1:1: error: sed exit code 1 != 0
- info: stderr: test/1/stderr
- sed: empty regex in 's' command
- info: test id: 1
- EOE
-
- : invalid
- :
- : Note that old versions of libc++ (for example 1.1) do not detect some
- : regex errors. For example '*' is parsed successfully.
- :
- $c <"sed -e 's/foo[/bar/'" && $b 2>>/~%EOE% != 0
- testscript:1:1: error: sed exit code 1 != 0
- info: stderr: test/1/stderr
- %sed: invalid regex.*%
- info: test id: 1
- EOE
- }
-
- : unterminated-replacement
- :
- $c <"sed -e 's/foo/bar'" && $b 2>>/EOE != 0
- testscript:1:1: error: sed exit code 1 != 0
- info: stderr: test/1/stderr
- sed: unterminated 's' command replacement
- info: test id: 1
- EOE
-
- : invalid-flags
- :
- $c <"sed -e 's/foo/bar/a'" && $b 2>>/EOE != 0
- testscript:1:1: error: sed exit code 1 != 0
- info: stderr: test/1/stderr
- sed: invalid 's' command flag 'a'
- info: test id: 1
- EOE
- }
-
- : exec
- :
- {
- : flags
- :
- {
- : global
- :
- {
- $c <"sed -e 's/o/a/g' <'foo' >'faa'" && $b : on
- $c <"sed -e 's/o/a/' <'foo' >'fao'" && $b : off
- }
-
- : icase
- :
- {
- $c <"sed -e 's/O/a/i' <'foo' >'fao'" && $b : on
- $c <"sed -e 's/O/a/' <'foo' >'foo'" && $b : off
- }
-
- : print
- :
- {
- $c <"sed -n -e 's/o/a/p' <'foo' >'fao'" && $b : on-match
- $c <"sed -n -e 's/o/a/' <'foo' " && $b : off-match
- $c <"sed -n -e 's/u/a/p' <'foo' " && $b : on-no-match
- }
- }
-
- : search
- {
- : anchor
- :
- {
- $c <"sed -n -e 's/^o/a/gp' <'oof' >'aof'" && $b : begin
- $c <"sed -n -e 's/o\$/a/gp' <'foo' >'foa'" && $b : end
- }
-
- : match
- : Match corner cases
- :
- {
- $c <"sed -n -e 's/a/b/p' <'a' >'b' " && $b : full
- $c <"sed -n -e 's/a/b/p' <'ac' >'bc' " && $b : left
- $c <"sed -n -e 's/a/b/p' <'ca' >'cb' " && $b : right
- $c <"sed -n -e 's/a/b/pg' <'xaax' >'xbbx'" && $b : adjacent
- }
- }
-
- : replacement
- :
- {
- : ecma-escape
- :
- {
- $c <"sed <'xay' -e 's/a/\$b/' >'x\$by'" && $b : none
- $c <"sed <'xay' -e 's/a/\$/' >'x\$y' " && $b : none-term
- $c <"sed <'xay' -e 's/a/\$\$/' >'x\$y' " && $b : self
- $c <"sed <'xay' -e 's/a/b\$&c/' >'xbacy'" && $b : match
- $c <"sed <'xay' -e 's/a/b\$`c/' >'xbxcy'" && $b : match-precede
- $c <"sed <'xay' -e \"s/a/b\\\$'c/\" >'xbycy'" && $b : match-follow
-
- : capture
- :
- $c <<EOI && $b
- sed <'abcdefghij' -e 's/(a)(b)(c)(d)(e)(f)(g)(h)(i)(j)/$1$10/' >'aj'
- EOI
- }
-
- : perl-escape
- :
- {
- $c <"sed <'xay' -e 's/a/\\b/' >'xby' " && $b : none
- $c <"sed <'xay' -e 's/a/\\/' >'xy' " && $b : none-term
- $c <"sed <'xay' -e 's/a/\\\\/' >'x\\y'" && $b : self
-
- : capture
- :
- $c <<EOI && $b
- sed <'abcdefghij' -e 's/(a)(b)(c)(d)(e)(f)(g)(h)(i)(j)/\1\10/' >'aa0'
- EOI
-
- : upper
- :
- {
- $c <"sed <'xay' -e 's/a/\\U/' >'xy' " && $b : none
- $c <"sed <'xay' -e 's/a/\\Uvz/' >'xVZy'" && $b : repl
- $c <"sed <'xay' -e 's/a/\\Uv\\Ez/' >'xVzy'" && $b : end
- $c <"sed <'aa' -e 's/a/v\\Uz/g' >'vZvZ'" && $b : locality
- $c <"sed <'xay' -e 's/\(a\)/\\U\\1/' >'xAy' " && $b : capt
- $c <"sed <'x-y' -e 's/\(a?\)-/\\U\\1z/' >'xZy' " && $b : capt-empty
- $c <"sed <'xay' -e 's/a/\\uvz/' >'xVzy'" && $b : once
- }
-
- : lower
- :
- {
- $c <"sed <'xay' -e 's/a/\\lVZ/' >'xvZy'" && $b : once
- }
- }
- }
-
- $c <"sed -e 's/a//' <:'b' >'b'" && $b : no-newline
- $c <"sed -e 's/a//' <:'' " && $b : empty-stdin
-
- : empty-file
- :
- $c <<EOI && $b
- touch f;
- sed -e 's/a//' f
- EOI
- }
- }
-}
-
-: in-place
-:
-{
- : no-file
- :
- $c <"sed -i -e 's/a/b/'" && $b 2>>/EOE != 0
- testscript:1:1: error: sed exit code 1 != 0
- info: stderr: test/1/stderr
- sed: -i|--in-place option specified while reading from stdin
- info: test id: 1
- EOE
-
- : edit
- :
- $c <<EOI && $b
- cat <'foo' >=f;
- sed -i -e 's/foo/bar/' f;
- cat f >'bar'
- EOI
-}
-
-: big
-:
-: Sed a big file (about 100K) to test that the builtin is asynchronous.
-:
-{
- $c <<EOI && $b
- s="--------------------------------"
- s="$s$s$s$s$s$s$s$s$s$s$s$s$s$s$s$s"
- s="$s$s$s$s$s$s$s$s$s$s$s$s$s$s$s$s"
- s="$s$s$s$s$s$s$s$s$s$s$s$s$s$s$s$s"
- cat <"$s" | sed -e 's/^x//' | cat >"$s"
- EOI
-}
diff --git a/tests/test/script/builtin/sleep.testscript b/tests/test/script/builtin/sleep.testscript
index 7d39548..6ba7e38 100644
--- a/tests/test/script/builtin/sleep.testscript
+++ b/tests/test/script/builtin/sleep.testscript
@@ -4,34 +4,6 @@
.include ../common.testscript
-: unknown-option
-:
-$c <<EOI && $b
-sleep -u 2>"sleep: unknown option '-u'" == 1
-EOI
-
: success
:
$c <'sleep 1' && $b
-
-: no-time
-:
-: Test passing no time interval.
-:
-$c <'sleep 2>"sleep: missing time interval" != 0' && $b
-
-: invalid-time
-:
-: Test passing invalid time interval.
-:
-$c <<EOI && $b
-sleep 1a 2>"sleep: invalid time interval '1a'" != 0
-EOI
-
-: unexpected-arg
-:
-: Test passing extra argument.
-:
-$c <<EOI && $b
-sleep 1 1 2>"sleep: unexpected argument '1'" != 0
-EOI
diff --git a/tests/test/script/builtin/test.testscript b/tests/test/script/builtin/test.testscript
deleted file mode 100644
index 9fde142..0000000
--- a/tests/test/script/builtin/test.testscript
+++ /dev/null
@@ -1,85 +0,0 @@
-# file : tests/test/script/builtin/test.testscript
-# copyright : Copyright (c) 2014-2019 Code Synthesis Ltd
-# license : MIT; see accompanying LICENSE file
-
-.include ../common.testscript
-
-: file
-:
-{
- : exists
- :
- $c <<EOI && $b
- touch a;
- test -f a
- EOI
-
- : not-exists
- :
- $c <'test -f a == 1' && $b
-
- : not-file
- :
- $c <'test -f . == 1' && $b
-}
-
-: dir
-:
-{
- : exists
- :
- $c <'test -d .' && $b
-
- : not-exists
- :
- $c <'test -d a == 1' && $b
-
- : not-dir
- :
- $c <<EOI && $b
- touch a;
- test -d a == 1
- EOI
-}
-
-: options
-:
-{
- : unknown
- :
- $c <<EOI && $b
- test -u 2>"test: unknown option '-u'" == 2
- EOI
-
- : none
- :
- $c <<EOI && $b
- test 2>"test: either -f|--file or -d|--directory must be specified" == 2
- EOI
-
- : both-file-dir
- :
- $c <<EOI && $b
- test -fd 2>"test: both -f|--file and -d|--directory specified" == 2
- EOI
-}
-
-: args
-:
-{
- : none
- :
- $c <'test -f 2>"test: missing path" == 2' && $b
-
- : unexpected
- :
- $c <<EOI && $b
- test -f a b 2>"test: unexpected argument 'b'" == 2
- EOI
-
- : empty-path
- :
- $c <<EOI && $b
- test -d '' 2>"test: invalid path ''" == 2
- EOI
-}
diff --git a/tests/test/script/builtin/touch.testscript b/tests/test/script/builtin/touch.testscript
index 731f023..e9549d2 100644
--- a/tests/test/script/builtin/touch.testscript
+++ b/tests/test/script/builtin/touch.testscript
@@ -4,91 +4,32 @@
.include ../common.testscript
-: file
-:
-$c <'touch a' && $b
-
-: file-create
-:
-: Test that file is created. If it didn't then 'rm' would fail.
-:
-$c <<EOI && $b
-touch a &!a;
-rm a
-EOI
-
-: file-update
-:
-: Test that existing file touch doesn't fail.
-:
-$c <<EOI && $b
-cat <'' >=a;
-touch a
-EOI
-
-: no-cleanup
-:
-: Test that touching an existing file does not register cleanup. If it does
-: then the file would be removed while leaving the embedded scope, and so the
-: cleanup registered by the first touch would fail.
-:
-$c <<EOI && $b
-{
- +touch a
- {
- touch ../a
- }
-}
-EOI
-
-: unknown-option
-:
-$c <<EOI && $b
-touch -u 2>"touch: unknown option '-u'" == 1
-EOI
-
-: no-args
-:
-: Test passing no arguments.
-:
-$c <'touch --no-cleanup 2>"touch: missing file" != 0' && $b
-
-: empty-path
-:
-: Test touching an empty path.
-:
-$c <<EOI && $b
-touch '' 2>"touch: invalid path ''" != 0
-EOI
-
-: dir-update
-:
-: Test touching an existing directory.
-:
-$c <<EOI && $b
-mkdir a;
-touch a 2>~'%touch: cannot create/update .+: .+%' != 0
-EOI
-
-: after
+: cleanup
:
{
- : success
+ : enabled
:
- $c <<EOI && $b
- touch a;
- touch --after a b
- EOI
+ $c <'touch a' && $b
- : no-value
+ : disabled
:
$c <<EOI && $b
- touch --after 2>"touch: missing value for option '--after'" != 0
- EOI
+ touch --no-cleanup a;
+ rm a
+ EOI
- : not-exists
+ : existing
+ :
+ : Test that touching an existing file does not register cleanup. If it does
+ : then the file would be removed while leaving the embedded scope, and so
+ : the cleanup registered by the first touch would fail.
:
$c <<EOI && $b
- touch --after a b 2>~"%touch: cannot obtain file '.+a' modification time: .+%" != 0
- EOI
+ {
+ +touch a
+ {
+ touch ../a
+ }
+ }
+ EOI
}