ALib C++ Framework
by
Library Version: 2511 R0
Documentation generated by doxygen
Loading...
Searching...
No Matches
shellcommand.inl
Go to the documentation of this file.
1//==================================================================================================
2/// \file
3/// This header-file is part of module \alib_system of the \aliblong.
4///
5/// \emoji :copyright: 2013-2025 A-Worx GmbH, Germany.
6/// Published under #"mainpage_license".
7//==================================================================================================
8ALIB_EXPORT namespace alib { namespace system {
9
10//==================================================================================================
11/// \b %TShellCommand provides a lightweight interface for executing external shell commands and
12/// capturing their output. It reads from the command’s standard output stream and accumulates
13/// the text in a buffer.
14/// The captured output is split into individual lines and stored in the class’s underlying
15/// #"TStringVector";StringVector".
16///
17/// \par Usage options:
18/// - Pure static usage: Call the static #"Run(strings::TAString)" method with a target buffer
19/// and an optional vector for collecting lines.
20/// The new output is appended to the provided buffer; if a vector is
21/// supplied, the newly captured portion is tokenized into lines and added to it.
22/// - Instance-based usage: Create an instance and call its non-static #"Run(lang::CurrentData)"
23/// method.
24/// By default, this clears the instance’s buffer and line vector before executing.
25/// To preserve the current content and append new output, pass
26/// #"CurrentData::Keep".
27///
28/// Method #"Run(lang::CurrentData)" can be sequentially invoked multiple times to aggregate the
29/// output of several shell commands.
30/// With the static #"Run(strings::TAString)" variant, the same buffer and vector is to be passed
31/// to continue appending.
32/// With the non-static #"Run(lang::CurrentData)", parameter \p{keepCurrent} controls whether
33/// existing content is retained or not.
34///
35/// @see This is a very simple wrapper type. For example, no blocking or timely shell commands
36/// can be handled. While simple, relient commands can be invoked with this class, more
37/// complicated cases should be handled with alternatives, as:
38/// - \https{boost.process,www.boost.org/doc/libs/latest/libs/process/doc/html/index.html}
39/// - \https{POCO Process,docs.pocoproject.org/current/Poco.Process.html}, or
40/// - \https{cpp-subprocess,github.com/arun11299/cpp-subprocess}.
41//==================================================================================================
42template<typename TAllocator= lang::HeapAllocator>
43class TShellCommand : public strings::util::TStringVector<nchar, TAllocator>
44{
45 public:
46 /// The allocator type that \p{TAllocator} specifies.
47 using AllocatorType = TAllocator;
48
49 /// The base type of this class.
51
52 /// The input buffer, collecting the output of the invoked shell command(s).
54
55 /// Default constructor. Usable with type #"HeapAllocator".
57
58 /// Constructor taking an allocator.
59 /// @param ma The allocator to use.
63
64
65 /// Executes the given command-line by invoking the static variant of this method
66 /// passing member #"ReadBuffer" and the inherited string vector (<c>*this</c>).
67 /// @param cmd The command to execute.
68 /// @param keepData Denotes whether any prior results are kept or not.
69 /// @return The exit-code of the command. If -1 errno is set.
71 if ( keepData == lang::CurrentData::Clear ) {
72 ReadBuffer.Reset();
73 this->clear();
74 }
75 return Run( cmd, ReadBuffer, this );
76 }
77
78 /// Executes the given command-line.<br>
79 /// The given \p{readBuffer} and vector \p{lines} are \b not reset. Instead the command result
80 /// is appended to both. If this is not wanted, methods \b Reset and \c clear have to be
81 /// invoked prior to calling this method.
82 /// @param cmd The command to execute.
83 /// @param readBuffer A string buffer to receive the command's output.
84 /// @param lines An optional pointer to a vector of strings, which receives the lines
85 /// of the output text.
86 /// @return The exit-code of the command. If -1 errno is set.
87 static int Run( const NCString& cmd,
89 StringVector* lines= nullptr ) {
90
91 constexpr int initialBufferSize = 4096;
92 constexpr int readSize = 1024 - 1;
93
94 integer origBufferLen= readBuffer.Length();
95
96 #if !defined(_WIN32) // true posix
97 FILE* pipe= popen(cmd, "r");
98 #elif defined (_WIN32)
99 FILE* pipe= _popen(cmd, "r");
100 #else
101 #pragma message ("Unknown Platform in file: " __FILE__ )
102 #endif
103 if (!pipe)
104 return -1;
105
106 readBuffer.EnsureRemainingCapacity(initialBufferSize);
107 for (;;) {
108 readBuffer.EnsureRemainingCapacity(readSize);
109 if (!fgets(readBuffer.VBuffer()+readBuffer.Length(), readSize, pipe))
110 break;
111 integer len= readBuffer.Length();
112 len= readBuffer.DetectLength(len);
113 readBuffer.TrimEnd("\r\n"); // remove also '\r' in case different platform
114 if ( readBuffer.Length() < len )
115 readBuffer.Append(NNEW_LINE);
116 }
117
118 #if !defined(_WIN32) // true posix
119 int resultCode = pclose(pipe);
120 if (resultCode != -1) {
121 // 0..255
122 if (WIFEXITED(resultCode)) resultCode= WEXITSTATUS(resultCode);
123
124 // Conventional shell-style encoding: 128 + signal number
125 else if (WIFSIGNALED(resultCode)) resultCode= 128 + WTERMSIG(resultCode);
126 }
127 #elif defined (_WIN32) // win posix
128 int resultCode = _pclose(pipe);
129 #else
130 #pragma message ("Unknown Platform in file: " __FILE__ )
131 #endif
132
133 // prevent tokenizer to add an empty line. If after TimEnd() below, the string is emtpy,
134 // one empty line will be added.
135 if ( readBuffer.IsEmpty() )
136 return resultCode;
137
138 // trim whitespace/newlines
139 readBuffer.TrimEnd();
140
141 // Split to lines
142 if (lines) {
143 TokenizerN tknzr(NString(readBuffer.Buffer() + origBufferLen,
144 readBuffer.Length() - origBufferLen ) , '\n');
145 while (tknzr.HasNext())
146 lines->Add(tknzr.Next(lang::Whitespaces::Keep).TrimEnd());
147 }
148 return resultCode;
149 }
150}; // class ShellCommand
151
152#if !DOXYGEN
154 const NCString&,
157
158#if ALIB_MONOMEM
160 const NCString&,
163#endif
164#endif // !DOXYGEN
165
166} // namespace [ system]
167
168/// Type alias in namespace \b alib.
170
171#if ALIB_MONOMEM
172/// Type alias in namespace \b alib.
174#endif
175
176} // namespace [alib]
#define ALIB_DLL
Definition alib.inl:573
#define ALIB_EXPORT
Definition alib.inl:562
integer DetectLength(integer offset=0)
Definition tastring.inl:720
TChar * VBuffer() const
Definition tastring.inl:637
TAString & Append(const TCharSrc *src, integer srcLength)
Definition tastring.inl:788
void EnsureRemainingCapacity(integer spaceNeeded)
Definition tastring.inl:561
TAString & TrimEnd(const TCString< TChar > &trimChars=CStringConstantsTraits< TChar >::DefaultWhitespaces())
constexpr integer Length() const
Definition string.inl:304
constexpr bool IsEmpty() const
Definition string.inl:353
constexpr const TChar * Buffer() const
Definition string.inl:299
TSubstring & TrimEnd(const TCString< TChar > &whiteSpaces=CStringConstantsTraits< TChar >::DefaultWhitespaces())
Definition substring.inl:90
TSubstring< TChar > & Next(lang::Whitespaces trimming=lang::Whitespaces::Trim, TChar newDelim='\0')
Definition tokenizer.cpp:26
strings::TAString< nchar, AllocatorType > ReadBuffer
int Run(const NCString &cmd, lang::CurrentData keepData=lang::CurrentData::Clear)
TShellCommand()
Default constructor. Usable with type #"HeapAllocator".
strings::util::TStringVector< nchar, TAllocator > StringVector
The base type of this class.
static int Run(const NCString &cmd, strings::TAString< nchar, AllocatorType > &readBuffer, StringVector *lines=nullptr)
TAllocator AllocatorType
The allocator type that TAllocator specifies.
TShellCommand(AllocatorType &ma)
@ Clear
Chooses to clear existing data.
@ Keep
Keep whitespaces in string.
strings::TString< nchar > NString
Type alias in namespace alib.
Definition string.inl:2181
strings::TCString< nchar > NCString
Type alias in namespace alib.
Definition cstring.inl:408
system::TShellCommand< MonoAllocator > ShellCommandMA
Type alias in namespace alib.
lang::integer integer
Type alias in namespace alib.
Definition integers.inl:149
system::TShellCommand< lang::HeapAllocator > ShellCommand
Type alias in namespace alib.
constexpr NCString NNEW_LINE
A zero-terminated string containing the new-line character sequence.
Definition cstring.inl:549
strings::util::TTokenizer< nchar > TokenizerN
Type alias in namespace alib.