-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
5d3f081
commit f793041
Showing
11 changed files
with
458 additions
and
29 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,32 +1,23 @@ | ||
# Prerequisites | ||
*.d | ||
# Ignore cmake generated directories and files. | ||
build/ | ||
out/ | ||
/CMakeSettings.json | ||
|
||
# Compiled Object files | ||
*.slo | ||
*.lo | ||
*.o | ||
*.obj | ||
# Visual Studio files | ||
.vs | ||
*.suo | ||
*.user | ||
|
||
# Precompiled Headers | ||
*.gch | ||
*.pch | ||
# VSCode files | ||
.vscode/ | ||
.cache/ | ||
cmake-variants.yaml | ||
|
||
# Compiled Dynamic libraries | ||
*.so | ||
*.dylib | ||
*.dll | ||
# macOS files | ||
.DS_Store | ||
|
||
# Fortran module files | ||
*.mod | ||
*.smod | ||
# Idea files | ||
.idea/ | ||
|
||
# Compiled Static libraries | ||
*.lai | ||
*.la | ||
*.a | ||
*.lib | ||
|
||
# Executables | ||
*.exe | ||
*.out | ||
*.app | ||
# python | ||
*.pyc |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,23 @@ | ||
cmake_minimum_required(VERSION 3.19) | ||
project(cmdout.sln VERSION 0.0) | ||
|
||
#set(CMAKE_CXX_STANDARD 11) | ||
#set(CMAKE_CXX_STANDARD 14) | ||
set(CMAKE_CXX_STANDARD 17) | ||
#set(CMAKE_CXX_STANDARD 20) | ||
#set(CMAKE_CXX_STANDARD 23) | ||
set(CMAKE_CXX_STANDARD_REQUIRED ON) | ||
if(NOT CYGWIN AND NOT MSYS AND NOT ${CMAKE_SYSTEM_NAME} STREQUAL QNX) | ||
set(CMAKE_CXX_EXTENSIONS OFF) | ||
endif() | ||
|
||
include(CMakeDependentOption) | ||
include(GNUInstallDirs) | ||
|
||
option(BUILD_DEMO "Builds the demo subproject" ON) | ||
option(INSTALL_CMDOUT "Enable installation of cmdout. (Projects embedding cmdout may want to turn this OFF.)" ON) | ||
|
||
add_subdirectory(cmdout) | ||
if(BUILD_DEMO) | ||
add_subdirectory(demo) | ||
endif() |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,2 +1,47 @@ | ||
# cmdout | ||
To execute a command and get its output: stdout, stderr, status (exit code) | ||
To execute a shell command and get its output, including stdout, stderr, status (exit code). | ||
|
||
There are 3 overloads: | ||
``` | ||
cmdout system(const char *cmd); | ||
cmdout system(const char *cmd, unsigned timeout_ms); | ||
cmdout system(const char *cmd, std::chrono::milliseconds timeout_ms); | ||
``` | ||
- All of them will return a result or a timeout error, both are wrapped in a `cmdout` object. | ||
- Each of them will wait for the result to become available until specified timeout has elapsed. | ||
- The default value of timeout is **10 seconds**, if the `timeout_ms` argument is 0 or unspecified. | ||
|
||
### Todo list | ||
- By now, it works well on Linux; but it should work on more platforms. | ||
|
||
## Getting Started | ||
### CMake file | ||
``` | ||
FetchContent_Declare( | ||
cmdout | ||
GIT_REPOSITORY https://github.com/myvas/cmdout.git | ||
GIT_TAG 0.0.1 # release-0.0.1 | ||
) | ||
FetchContent_MakeAvailable(cmdout) | ||
#target_link_libraries(<your_target> PRIVATE cmdout) | ||
``` | ||
### Include the header file | ||
``` | ||
#include <cmdout.hpp> | ||
``` | ||
|
||
## Demo | ||
### C++17 on GNU/Linux Debian 11 (bullseye) | ||
``` | ||
#include <cmdout_ext.hpp> | ||
#include <iostream> | ||
int main() { | ||
auto result22 = myvas::system("ls not-exist 2>&1"); | ||
std::cout << result22 << std::endl; | ||
auto result42 = myvas::system("ls / -l", std::chrono::milliseconds(4)); | ||
std::cout << result42 << std::endl; | ||
} | ||
``` |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,11 @@ | ||
find_package(Threads) | ||
|
||
add_library(cmdout) | ||
target_include_directories(cmdout PUBLIC include) | ||
target_sources(cmdout PRIVATE src/cmdout.cpp "src/system.cpp") | ||
target_link_libraries(cmdout PRIVATE ${CMAKE_THREAD_LIBS_INIT}) | ||
#set_target_properties(cmdout PROPERTIES COMPILE_FLAGS "-pthread" LINK_FLAGS "-pthread") | ||
|
||
if(INSTALL_CMDOUT) | ||
install(TARGETS cmdout) | ||
endif() |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,125 @@ | ||
/** | ||
* Copyright (c) 2023 Myvas Foundation | ||
* SPDX-License-Identifier: MIT | ||
* | ||
* @file cmdout.hpp | ||
* @brief `myvas::system()` is used to invoke a shell command and get its output, within timeout feature. | ||
* | ||
* @see {std::system()} | ||
*/ | ||
#pragma once | ||
|
||
#include <string> | ||
#include <string_view> | ||
#include <chrono> | ||
#include <cstdlib> | ||
#include <cerrno> | ||
|
||
namespace myvas { | ||
|
||
/** | ||
* @brief Executor to execute a shell command and get its output. | ||
*/ | ||
class cmdout | ||
{ | ||
int status_; | ||
std::string out_; | ||
std::string cmd_; | ||
|
||
public: | ||
/** | ||
* @brief Gets the exit code after `exec` returned. | ||
* | ||
* The value is one of the following: | ||
* - If `cmd` is empty, then a nonzero value if a shell is available, or 0 if | ||
* no shell is available. | ||
* - If a child process in `cmd` could not be created, or its status could not | ||
* be retrieved, the return value is -1 and `errno` is set to indicate the | ||
* error. | ||
* - If a shell could not be executed, then the return value is 127. | ||
* - If all system call succeed, then the return value is the status of the | ||
* last command in `cmd`. | ||
*/ | ||
int status() const; | ||
|
||
void status(int value); | ||
|
||
/** | ||
* @brief Gets the content of `stdout` (file descriptor 1). | ||
*/ | ||
std::string_view out() const; | ||
|
||
void out(std::string_view value); | ||
|
||
/** | ||
* @brief Gets the shell command line. | ||
*/ | ||
std::string_view cmd() const; | ||
|
||
void cmd(std::string_view value); | ||
|
||
/** | ||
* @brief Default to cmdout(ENOTSUP, "Not supported"). | ||
*/ | ||
cmdout(); | ||
|
||
cmdout(std::string_view cmd); | ||
|
||
/** | ||
* @brief Constructs an output. | ||
* | ||
* @param [in] status EXIT_SUCCESS, EXIT_FAILURE or errno | ||
* @see `cerrno` and `cstdlib`. | ||
*/ | ||
explicit cmdout(int status, std::string_view out, std::string_view cmd); | ||
|
||
cmdout(const cmdout&); | ||
cmdout& operator=(const cmdout&); | ||
cmdout(cmdout&&); | ||
cmdout& operator=(cmdout&&); | ||
|
||
virtual ~cmdout(); | ||
}; | ||
|
||
/** | ||
* @brief Execute a shell command specified in `cmd`, waiting for the result until specified timeout (10 seconds) has elapsed. | ||
* NOTE: A shell command with a tail of `2>&1` will catch both stdout and stderr, otherwise stdout only. | ||
* | ||
* @param [in] cmd The `cmd` argument is a pointer to a null-terminated string | ||
* containing a shell command. | ||
* | ||
* @return The return value is a `cmdout` object, in which wraps the status code | ||
* and output string of the shell command. | ||
*/ | ||
cmdout system(const char* cmd); | ||
|
||
/** | ||
* @brief Execute a shell command specified in `cmd`, waiting for the result until specified timeout has elapsed. | ||
* NOTE: A shell command with a tail of `2>&1` will catch both stdout and | ||
* stderr, otherwise stdout only. | ||
* | ||
* @param [in] cmd The `cmd` argument is a pointer to a null-terminated string | ||
* containing a shell command. | ||
* | ||
* @param [in] timeout_ms timeout in milliseconds. (If zero, defaults to 10 seconds) | ||
* | ||
* @return The return value is a `cmdout` object, in which wraps the status code | ||
* and output string of the shell command. | ||
*/ | ||
cmdout system(const char* cmd, unsigned timeout_ms); | ||
|
||
/** | ||
* @brief Execute a shell command specified in `cmd`, waiting for the result until specified timeout has elapsed. | ||
* NOTE: A shell command with a tail of `2>&1` will catch both stdout and stderr, otherwise stdout only. | ||
* | ||
* @param [in] cmd The `cmd` argument is a pointer to a null-terminated string | ||
* containing a shell command. | ||
* | ||
* @param [in] timeout_ms timeout in milliseconds. (If zero, defaults to 10 seconds) | ||
* | ||
* @return The return value is a `cmdout` object, in which wraps the status code | ||
* and output string of the shell command. | ||
*/ | ||
cmdout system(const char* cmd, std::chrono::milliseconds timeout_ms); | ||
|
||
} // namespace myvas |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,22 @@ | ||
/** | ||
* Copyright (c) 2023 Myvas Foundation | ||
* SPDX-License-Identifier: MIT | ||
* | ||
* @file cmdout_ext.hpp | ||
* @brief Helpers for `cmdout`. | ||
*/ | ||
#pragma once | ||
|
||
#include "cmdout.hpp" | ||
|
||
#include <ostream> | ||
|
||
/** | ||
* @brief Helper for printing a cmdout object. | ||
*/ | ||
std::ostream& operator<<(std::ostream& os, const myvas::cmdout& value) | ||
{ | ||
os << "cmdout {" << value.cmd() << "} return " << value.status() | ||
<< " length " << value.out().length() << "\n" << value.out(); | ||
return os; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,50 @@ | ||
/** | ||
* Copyright (c) 2023 Myvas Foundation | ||
* SPDX-License-Identifier: MIT | ||
* | ||
* @file cmdout.cpp | ||
* @brief Implementation of class `cmdout`. | ||
*/ | ||
#include "cmdout.hpp" | ||
|
||
#include <array> | ||
#include <cstdio> | ||
#include <cstring> | ||
#include <stdexcept> | ||
|
||
namespace myvas { | ||
|
||
int cmdout::status() const { return status_; } | ||
|
||
void cmdout::status(int value) { status_ = value; } | ||
|
||
std::string_view cmdout::out() const { return out_; } | ||
|
||
void cmdout::out(std::string_view value) { out_ = value; } | ||
|
||
std::string_view cmdout::cmd() const { return cmd_; } | ||
|
||
void cmdout::cmd(std::string_view value) { cmd_ = value; } | ||
|
||
cmdout::cmdout() | ||
: status_(ENOTSUP), out_("Not supported"), cmd_("") | ||
{ | ||
} | ||
|
||
cmdout::cmdout(std::string_view cmd) | ||
: status_(ENOTSUP), out_("Not supported"), cmd_(cmd) | ||
{ | ||
} | ||
|
||
cmdout::cmdout(int status, std::string_view out, std::string_view cmd) | ||
: status_(status), out_(out), cmd_(cmd) | ||
{ | ||
} | ||
|
||
cmdout::cmdout(const cmdout&) = default; | ||
cmdout& cmdout::operator=(const cmdout&) = default; | ||
cmdout::cmdout(cmdout&&) = default; | ||
cmdout& cmdout::operator=(cmdout&&) = default; | ||
cmdout::~cmdout() = default; | ||
|
||
} // namespace myvas |
Oops, something went wrong.