ALib C++ Library
Library Version: 2402 R1
Documentation generated by doxygen
Loading...
Searching...
No Matches
arguments.cpp
1// #################################################################################################
2// ALib C++ Library
3//
4// Copyright 2013-2024 A-Worx GmbH, Germany
5// Published under 'Boost Software License' (a free software license, see LICENSE.txt)
6// #################################################################################################
8
9#if !defined(ALIB_DOX)
10# if !defined (HPP_ALIB_CLI_CLI)
11# include "alib/cli/arguments.hpp"
12# endif
13# if !defined (HPP_ALIB_CLI_COMMANDLINE)
15# endif
16# if !defined (HPP_ALIB_STRINGS_UTIL_TOKENIZER)
18# endif
19# if !defined (HPP_ALIB_ENUMS_RECORDPARSER)
21# endif
22# if !defined(HPP_ALIB_CAMP_MESSAGE_REPORT)
24# endif
25#endif // !defined(ALIB_DOX)
26
27
28// ##########################################################################################
29// ### Tuple loaders
30// ##########################################################################################
31
32namespace alib { namespace cli {
33
34// ##########################################################################################
35// ### Methods of Command, Option, etc.
36// ##########################################################################################
37
39{
40 Tokenizer tknzr( record.parameters , '/' );
41 while( tknzr.Next().IsNotEmpty() )
42 {
43ALIB_DBG( bool found= false; )
44
45 for( auto* paramDecl : CmdLine.ParameterDecls )
46 if( paramDecl->Name().StartsWith<true, lang::Case::Ignore>( tknzr.Actual ) )
47 {
48 Parameters.PushBack( paramDecl );
49 ALIB_DBG(found= true; )
50 break;
51 }
52
53 ALIB_ASSERT_ERROR( found, "CLI",
54 "Parameter named {!Q} not found while loading resources of command {!Q}.",
55 tknzr.Actual, Identifier() )
56 }
57}
58
60{
61 for( auto* param : Parameters )
62 if( param->Name().Equals<false>( name ) )
63 return param;
64
65 return nullptr;
66}
67
68
69bool Option::Read( OptionDecl& decl, String& argProbablyReplaced, const integer argNo )
70{
71 String identifier = decl.Identifier();
72 character identifierC = decl.IdentifierChar();
73 auto qtyArgsExpected= decl.QtyExpectedArgsFollowing();
74 auto qtyArgsLeft = CmdLine->ArgsLeft.size() -1;
75
76 // read single/double hyphen options once
77 Substring arg= argProbablyReplaced;
78 Substring inArgArgument;
79 auto valueSeparator= arg.IndexOf<false, lang::Case::Sensitive>( decl.ValueSeparator() );
80 if( valueSeparator > 0 )
81 arg.Split<false>( valueSeparator, inArgArgument, decl.ValueSeparator().Length() );
82
83 bool potentialIllegalContinuation= false;
84 if ( !( ( identifier.IsNotEmpty()
85 && arg.ConsumeString(A_CHAR("--"))
86 && arg.Length() >= decl.MinimumRecognitionLength()
87 && ( identifier.StartsWith<true, lang::Case::Ignore>( arg )
88 || true == (potentialIllegalContinuation= arg.StartsWith<true,lang::Case::Ignore>( identifier )) )
89
90 )
91
92 || ( arg.ConsumeChar('-')
93 && arg.ConsumeChar(identifierC) )
94 )
95 )
96 return false;
97
98 // Throw if the identifier was fully matched, but the argument continues with a
99 // non-alphanumerical value.
100 // (This is only allowed if separator was set in resource. But in this case, the flag will
101 // never match, because of the code above...)
102 if( potentialIllegalContinuation )
103 {
104 auto nextChar= arg.CharAt<false>( identifier.Length() );
105 if( !isalnum( nextChar ) )
107 identifier, argNo, CmdLine->GetArg(argNo) );
108 return false;
109 }
110
111 Declaration= &decl;
112 Position= argNo;
113
115
116
117 // store in-arg argument
118 if( valueSeparator > 0)
119 {
120 Args.PushBack( inArgArgument );
121 if(qtyArgsExpected > 0 )
122 --qtyArgsExpected;
123 }
124
125
126 // error: not enough params
127 if ( qtyArgsExpected > integer(qtyArgsLeft) )
129 decl.Identifier(), argNo, CmdLine->GetArg(argNo),
130 qtyArgsExpected, qtyArgsLeft );
131
132 // store arg strings
133 for( integer i= 0; i < qtyArgsExpected; ++i )
134 Args.PushBack( CmdLine->GetArg(argNo + 1 + i) );
135 QtyArgsConsumed+= qtyArgsExpected;
136
137 return true;
138}
139
141{
142 auto& identifier= decl.Identifier();
143 String arg = CmdLine->PeekArg();
144
145 if ( arg.Length() < decl.MinimumRecognitionLength()
146 || !identifier.StartsWith<true,lang::Case::Ignore>( arg ) )
147 return false;
148
149 Declaration= &decl;
151 CmdLine->PopArg();
153
154 if( decl.Parameters.Size() == 0 )
155 return true;
156
157 auto paramDeclIt= decl.Parameters.begin();
158 while( paramDeclIt != decl.Parameters.end() )
159 {
160 Parameter param( CmdLine );
161 bool continueReading= param.Read( **paramDeclIt );
162 if( param.QtyArgsConsumed )
163 {
165 Parameter* paramFound= CmdLine->allocator.Emplace<Parameter>( param );
166 if ( (*paramDeclIt)->IsOptional() )
167 ParametersOptional.PushBack( paramFound );
168 else
169 ParametersMandatory.PushBack( paramFound );
170
171 // start from the beginning
172 paramDeclIt= decl.Parameters.begin();
173 }
174 else
175 ++paramDeclIt;
176
177 // stop here if parameter read signaled this
178 if( !continueReading )
179 return false;
180 }
181
182 return true;
183}
184
186{
187 #if ALIB_DEBUG
188 bool found= false;
189 for( auto* paramDecl : Declaration->Parameters )
190 if( paramDecl->Name().Equals<false>(name) )
191 {
192 found = true;
193 break;
194 }
195 ALIB_ASSERT_ERROR( found, "CLI", "Requested parameter {!Q} not defined.", name )
196 #endif
197
198 for( auto* param : ParametersMandatory )
199 if( param->Declaration->Name().Equals<false>( name ) )
200 return param;
201
202 for( auto* param : ParametersOptional )
203 if( param->Declaration->Name().Equals<false>( name ) )
204 return param;
205
206 return nullptr;
207}
208
210{
211 Parameter* param= GetParsedParameter( name );
212 return param && param->Args.IsNotEmpty() ? param->Args.Front()
213 : NullString();
214}
215
216
218{
219 Substring arg= CmdLine->PeekArg();
220 if( arg.IsNull() )
221 return false;
222
223 auto& identifier= decl.Identifier();
224 if ( identifier.IsEmpty() && decl.IsOptional() )
225 return false;
226
227 auto valueSeparator= arg.IndexOf<false, lang::Case::Sensitive>( decl.ValueSeparator() );
228 Substring inArgArgument;
229 if( valueSeparator > 0 )
230 arg.Split<false>( valueSeparator, inArgArgument, decl.ValueSeparator().Length() );
231
232 if ( identifier.IsEmpty()
233 || ( arg.Length() >= decl.MinimumRecognitionLength()
234 && identifier.StartsWith<true,lang::Case::Ignore>( arg ) ) )
235 {
237 Declaration= &decl;
239 CmdLine->PopArg();
240 int qtyArgsExpected= decl.QtyExpectedArgsFollowing();
241
242 if( decl.Identifier().IsEmpty() )
243 {
244 Args.PushBack( arg );
245 }
246 else
247 {
248 if( inArgArgument.IsNotEmpty() )
249 {
250 Args.PushBack( inArgArgument );
251 --qtyArgsExpected;
252 }
253 }
254
255 // stop command?
256 if( qtyArgsExpected < 0 )
257 return false;
258
259 // error: not enough params
260 if ( qtyArgsExpected > static_cast<integer>(CmdLine->ArgsLeft.size()) )
263 qtyArgsExpected, CmdLine->ArgsLeft.size() );
264
265 // store arg strings
266 for( size_t i= 0; i < static_cast<size_t>( qtyArgsExpected ); ++i )
267 {
268 Args.PushBack( CmdLine->GetArg(*CmdLine->ArgsLeft.begin()) );
269 CmdLine->ArgsLeft.erase( CmdLine->ArgsLeft.begin() );
270 }
271 QtyArgsConsumed+= static_cast<size_t>( qtyArgsExpected );
272 }
273
274
275 return true;
276}
277
278void ERCommandDecl ::Parse()
279{
280 enums::EnumRecordParser::Get( ERSerializable::EnumElementName );
281 enums::EnumRecordParser::Get( ERSerializable::MinimumRecognitionLength );
282 enums::EnumRecordParser::Get( parameters , true );
283}
284
285void EROptionDecl ::Parse()
286{
287 enums::EnumRecordParser::Get( ERSerializable::EnumElementName );
288 enums::EnumRecordParser::Get( ERSerializable::MinimumRecognitionLength );
289 enums::EnumRecordParser::Get( identifierChar );
290 enums::EnumRecordParser::Get( valueSeparator );
291 enums::EnumRecordParser::Get( qtyExpectedArgsFollowing );
292 enums::EnumRecordParser::Get( shortcutReplacementString , true );
293}
294
305
306void ERExitCodeDecl ::Parse()
307{
308 enums::EnumRecordParser::Get( ERSerializable::EnumElementName );
309 ERSerializable::MinimumRecognitionLength = 0;
310 enums::EnumRecordParser::Get( associatedCLIException , true );
311}
312
313}} // namespace alib::cli
ALIB_API void addParamDecls()
Definition arguments.cpp:38
CommandLine & CmdLine
const String & Identifier()
List< ParameterDecl * > Parameters
ALIB_API ParameterDecl * GetParameterDecl(const String &name)
Definition arguments.cpp:59
List< ParameterDecl * > ParameterDecls
virtual String GetArg(integer idx)
MonoAllocator allocator
virtual String PeekArg()
virtual ALIB_API String PopArg()
std::vector< integer, StdContMA< integer > > ArgsLeft
const String & Identifier()
const String & ValueSeparator()
character IdentifierChar()
integer QtyExpectedArgsFollowing()
const String & Identifier()
const String & ValueSeparator()
const String & Name()
ALIB_FORCE_INLINE T * Emplace(TArgs &&... args)
constexpr bool IsNull() const
Definition string.hpp:395
integer IndexOf(TChar needle, integer startIdx=0) const
Definition string.hpp:889
constexpr bool IsEmpty() const
Definition string.hpp:414
TChar CharAt(integer idx) const
Definition string.hpp:437
constexpr bool IsNotEmpty() const
Definition string.hpp:420
constexpr integer Length() const
Definition string.hpp:357
bool StartsWith(const TString &needle) const
Definition string.hpp:813
bool ConsumeString(const TString< TChar > &consumable)
TSubstring & Split(integer position, TSubstring &target, integer separatorWidth=0, bool trim=false)
ALIB_API TSubstring< TChar > & Next(lang::Whitespaces trimming=lang::Whitespaces::Trim, TChar newDelim='\0')
Definition tokenizer.cpp:18
TSubstring< TChar > Actual
Definition tokenizer.hpp:84
#define ALIB_CALLER_NULLED
Definition alib.hpp:846
#define A_CHAR(STR)
#define ALIB_ASSERT_ERROR(cond,...)
Definition alib.hpp:984
#define ALIB_DBG(...)
Definition alib.hpp:457
Definition alib.cpp:57
lang::Exception Exception
Type alias in namespace alib.
constexpr String NullString()
Definition string.hpp:2498
characters::character character
Type alias in namespace alib.
lang::integer integer
Type alias in namespace alib.
Definition integers.hpp:286
List< Parameter *, Recycling::Shared > ParametersOptional
ALIB_API Parameter * GetParsedParameter(const String &name)
List< Parameter *, Recycling::Shared > ParametersMandatory
ALIB_API bool Read(CommandDecl &decl)
ALIB_API String GetParsedParameterArg(const String &name)
CommandDecl * Declaration
OptionDecl * Declaration
ALIB_API bool Read(OptionDecl &decl, String &arg, const integer argNo)
Definition arguments.cpp:69
List< String, Recycling::Shared > Args
ALIB_API bool Read(ParameterDecl &decl)
List< String, Recycling::Shared > Args
ParameterDecl * Declaration
CommandLine * CmdLine
Definition arguments.hpp:41
integer QtyArgsConsumed
Definition arguments.hpp:50
static ALIB_API void Get(String &result, bool isLastField=false)