aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--libbutl/builtin.cxx29
-rw-r--r--libbutl/builtin.mxx27
-rw-r--r--libbutl/command.cxx20
-rw-r--r--tests/builtin/driver.cxx12
4 files changed, 57 insertions, 31 deletions
diff --git a/libbutl/builtin.cxx b/libbutl/builtin.cxx
index 9efa697..fe74b05 100644
--- a/libbutl/builtin.cxx
+++ b/libbutl/builtin.cxx
@@ -2109,19 +2109,20 @@ namespace butl
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_}
+ {"cat", {&async_impl<&cat>, 2}},
+ {"cp", {&sync_impl<&cp>, 2}},
+ {"diff", {nullptr, 2}},
+ {"echo", {&async_impl<&echo>, 2}},
+ {"false", {&false_, 0}},
+ {"ln", {&sync_impl<&ln>, 2}},
+ {"mkdir", {&sync_impl<&mkdir>, 2}},
+ {"mv", {&sync_impl<&mv>, 2}},
+ {"rm", {&sync_impl<&rm>, 1}},
+ {"rmdir", {&sync_impl<&rmdir>, 1}},
+ {"sed", {&async_impl<&sed>, 2}},
+ {"sleep", {&sync_impl<&sleep>, 1}},
+ {"test", {&sync_impl<&test>, 1}},
+ {"touch", {&sync_impl<&touch>, 2}},
+ {"true", {&true_, 0}}
};
}
diff --git a/libbutl/builtin.mxx b/libbutl/builtin.mxx
index 2be2f90..e4dd4f8 100644
--- a/libbutl/builtin.mxx
+++ b/libbutl/builtin.mxx
@@ -153,19 +153,38 @@ LIBBUTL_MODEXPORT namespace butl
const dir_path& cwd,
const builtin_callbacks&);
- class builtin_map: public std::map<std::string, builtin_function*>
+ // Builtin function and weight.
+ //
+ // The weight between 0 and 2 reflects the builtin's contribution to the
+ // containing script semantics with 0 being the lowest/ignore. Current
+ // mapping is as follows:
+ //
+ // 0 - non-contributing (true, false)
+ // 1 - non-creative (rm, rmdir, sleep, test)
+ // 2 - creative (any builtin that may produce output)
+ //
+ // If the function is NULL, then the builtin has an external implementation
+ // and should be executed by running the program with this name.
+ //
+ struct builtin_info
+ {
+ builtin_function* function;
+ uint8_t weight;
+ };
+
+ class builtin_map: public std::map<std::string, builtin_info>
{
public:
- using base = std::map<std::string, builtin_function*>;
+ using base = std::map<std::string, builtin_info>;
using base::base;
// Return NULL if not a builtin.
//
- builtin_function*
+ const builtin_info*
find (const std::string& n) const
{
auto i (base::find (n));
- return i != end () ? i->second : nullptr;
+ return i != end () ? &i->second : nullptr;
}
};
diff --git a/libbutl/command.cxx b/libbutl/command.cxx
index bb5287c..fadd617 100644
--- a/libbutl/command.cxx
+++ b/libbutl/command.cxx
@@ -227,9 +227,9 @@ namespace butl
msg.c_str ());
}
- builtin_function* bf (builtins.find (prog));
+ const builtin_info* bi (builtins.find (prog));
- if (bf != nullptr) // Execute the builtin.
+ if (bi != nullptr && bi->function != nullptr) // Execute the builtin.
{
if (callback)
{
@@ -259,17 +259,17 @@ namespace butl
uint8_t r; // Storage.
builtin_callbacks cb;
- builtin b (bf (r,
- args,
- nullfd /* stdin */,
- move (rd) /* stdout */,
- nullfd /* stderr */,
- cwd,
- cb));
+ builtin b (bi->function (r,
+ args,
+ nullfd /* stdin */,
+ move (rd) /* stdout */,
+ nullfd /* stderr */,
+ cwd,
+ cb));
return process_exit (b.wait ());
}
- else // Execute the program.
+ else // Execute the program.
{
// Strip the potential leading `^`, indicating that this is an external
// program rather than a builtin. Consider only simple paths and don't
diff --git a/tests/builtin/driver.cxx b/tests/builtin/driver.cxx
index 2583ba2..9fb6d6f 100644
--- a/tests/builtin/driver.cxx
+++ b/tests/builtin/driver.cxx
@@ -144,15 +144,21 @@ main (int argc, char* argv[])
// Execute the builtin.
//
- builtin_function* bf (builtins.find (name));
+ const builtin_info* bi (builtins.find (name));
- if (bf == nullptr)
+ if (bi == nullptr)
{
cerr << "unknown builtin '" << name << "'" << endl;
return 1;
}
+ if (bi->function == nullptr)
+ {
+ cerr << "external builtin '" << name << "'" << endl;
+ return 1;
+ }
+
uint8_t r; // Storage.
- builtin b (bf (r, args, nullfd, nullfd, nullfd, cwd, callbacks));
+ builtin b (bi->function (r, args, nullfd, nullfd, nullfd, cwd, callbacks));
return b.wait ();
}