diff --git a/functional.hpp b/functional.hpp index 891230a6ab7f145af80016d0cbaf844c8cb9a85f..8e6087142eeb272c1a58e7c7a1fc34bfa92af98e 100644 --- a/functional.hpp +++ b/functional.hpp @@ -9,6 +9,7 @@ #include <list> #include <functional> #include <chrono> +#include <future> #include <stdexcept> namespace rlib { @@ -44,7 +45,18 @@ namespace rlib { auto begin = std::chrono::high_resolution_clock::now(); f(std::forward<Args>(args) ...); auto end = std::chrono::high_resolution_clock::now(); - return ::std::chrono::duration<double>(end - begin).count(); + return std::chrono::duration<double>(end - begin).count(); + } + template <typename Func, typename... Args> + static inline auto timeout(int timeout_seconds, Func&& func, Args&&... args) { + using ReturnType = decltype(func(args...)); + auto future = std::async(std::launch::async, std::forward<Func>(func), std::forward<Args>(args)...); + + if (future.wait_for(std::chrono::seconds(timeout_seconds)) == std::future_status::timeout) { + return ReturnType {}; + } + + return future.get(); } template <class Func, typename... Args> diff --git a/sys/unix_handy.hpp b/sys/unix_handy.hpp index c65110bb6fac2704971822aa26f4fce9ab9737c4..faedefd51eaf6fb42d60d2fe6acbbeac2a537648 100644 --- a/sys/unix_handy.hpp +++ b/sys/unix_handy.hpp @@ -2,18 +2,18 @@ #define RLIB_UNIX_HANDY_HPP_ #include <unistd.h> - -#include <sys/socket.h> -#include <sys/types.h> -#include <netdb.h> -#include <rlib/scope_guard.hpp> -#include <rlib/string.hpp> +#include <string> +#include <stdexcept> +#include <vector> #include <rlib/sys/os.hpp> #if RLIB_OS_ID == OS_WINDOWS #error rlib/sys/unix_handy.hpp is not for Windows. #endif +// For shell_run +#include <sstream> + namespace rlib { // args DOES NOT contain the "$0". inline void execs(std::string path, std::vector<std::string> args) { @@ -28,10 +28,46 @@ namespace rlib { ::execv(path.c_str(), arr); } + + struct shell_result { + int status; + std::string stdout_; + }; + + // Execute command with shell and capture stdout. + // Note: stderr would be discarded. Use `2>&1` if needed. + shell_result shell_run(const std::string& command) { + char buffer[128]; + + FILE *pipe = popen(command.c_str(), "r"); + if (!pipe) { + return {-errno, ""}; + } + + shell_result res; + + while (fgets(buffer, sizeof(buffer), pipe) != nullptr) { + res.stdout_ += buffer; + } + + res.status = pclose(pipe); + res.status = WIFEXITED(res.status) ? WEXITSTATUS(res.status) : -errno; + + return res; + } + + auto get_shell_name() { + return shell_run("echo -n $0").stdout_; + } } // Deprecated. Use sys/sio.hpp #if 1+1 == 4 +#include <sys/socket.h> +#include <sys/types.h> +#include <netdb.h> +#include <rlib/scope_guard.hpp> +#include <rlib/string.hpp> namespace rlib { namespace impl { using rlib::literals::operator""_format;