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