ALib C++ Library
Library Version: 2510 R0
Documentation generated by doxygen
Loading...
Searching...
No Matches
arguments.cpp
1// #################################################################################################
2// ALib C++ Library
3//
4// Copyright 2013-2025 A-Worx GmbH, Germany
5// Published under 'Boost Software License' (a free software license, see LICENSE.txt)
6// #################################################################################################
7#include "alib_precompile.hpp"
8#if !defined(ALIB_C20_MODULES) || ((ALIB_C20_MODULES != 0) && (ALIB_C20_MODULES != 1))
9# error "Symbol ALIB_C20_MODULES has to be given to the compiler as either 0 or 1"
10#endif
11#if ALIB_C20_MODULES
12 module;
13#endif
14// ====================================== Global Fragment ======================================
15#include "alib/alib.inl"
16// =========================================== Module ==========================================
17#if ALIB_C20_MODULES
18 module ALib.CLI;
20 import ALib.Strings;
23#else
25# include "ALib.Strings.H"
28# include "ALib.CLI.H"
29#endif
30// ====================================== Implementation =======================================
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<CHK, lang::Case::Ignore>( tknzr.Actual ) )
47 {
48 Parameters.push_back( paramDecl );
49 ALIB_DBG(found= true; )
50 break;
51 }
52
53 ALIB_ASSERT_ERROR( found, "CLI",
54 "Parameter named \"{}\" not found while loading resources of command \"{}\".",
55 tknzr.Actual, Identifier() )
56 }
57}
58
60{
61 for( auto* param : Parameters )
62 if( param->Name().Equals<NC>( 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 argsExpected= decl.QtyExpectedArgsFollowing();
74 auto argsLeft = CmdLine->ArgsLeft.size() -1;
75
76 // read single/double hyphen options once
77 Substring arg= argProbablyReplaced;
78 Substring inArgArgument;
79 auto valueSeparator= arg.IndexOf<CHK, lang::Case::Sensitive>( decl.ValueSeparator() );
80 if( valueSeparator > 0 )
81 arg.Split<NC>( 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<CHK, lang::Case::Ignore>( arg )
88 || true == (potentialIllegalContinuation= arg.StartsWith<CHK,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<NC>( 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.push_back( inArgArgument );
121 if(argsExpected > 0 )
122 --argsExpected;
123 }
124
125
126 // error: not enough params
127 if ( argsExpected > integer(argsLeft) )
129 decl.Identifier(), argNo, CmdLine->GetArg(argNo),
130 argsExpected, argsLeft );
131
132 // store arg strings
133 for( integer i= 0; i < argsExpected; ++i )
134 Args.push_back( CmdLine->GetArg(argNo + 1 + i) );
135 ConsumedArguments+= argsExpected;
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<CHK,lang::Case::Ignore>( arg ) )
147 return false;
148
149 Declaration= &decl;
150 Position= CmdLine->ArgsLeft[0];
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.ConsumedArguments )
163 {
165 Parameter* paramFound= CmdLine->allocator().New<Parameter>(param);
166 if ( (*paramDeclIt)->IsOptional() )
167 ParametersOptional.push_back( paramFound );
168 else
169 ParametersMandatory.push_back( 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<NC>(name) )
191 {
192 found = true;
193 break;
194 }
195 ALIB_ASSERT_ERROR( found, "CLI", "Requested parameter \"{}\" not defined.", name )
196 #endif
197
198 for( auto* param : ParametersMandatory )
199 if( param->Declaration->Name().Equals<NC>( name ) )
200 return param;
201
202 for( auto* param : ParametersOptional )
203 if( param->Declaration->Name().Equals<NC>( 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 : NULL_STRING;
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<CHK, lang::Case::Sensitive>( decl.ValueSeparator() );
228 Substring inArgArgument;
229 if( valueSeparator > 0 )
230 arg.Split<NC>( valueSeparator, inArgArgument, decl.ValueSeparator().Length() );
231
232 if ( identifier.IsEmpty()
233 || ( arg.Length() >= decl.MinimumRecognitionLength()
234 && identifier.StartsWith<CHK,lang::Case::Ignore>( arg ) ) )
235 {
237 Declaration= &decl;
238 Position= CmdLine->ArgsLeft[0];
239 CmdLine->PopArg();
240 int argsExpected= decl.QtyExpectedArgsFollowing();
241
242 if( decl.Identifier().IsEmpty() )
243 {
244 Args.push_back( arg );
245 }
246 else
247 {
248 if( inArgArgument.IsNotEmpty() )
249 {
250 Args.push_back( inArgArgument );
251 --argsExpected;
252 }
253 }
254
255 // stop command?
256 if( argsExpected < 0 )
257 return false;
258
259 // error: not enough params
260 if ( argsExpected > integer(CmdLine->ArgsLeft.size()) )
262 decl.Name(), Position, CmdLine->GetArg(Position),
263 argsExpected, CmdLine->ArgsLeft.size() );
264
265 // store arg strings
266 for( size_t i= 0; i < size_t( argsExpected ); ++i )
267 {
268 Args.push_back( CmdLine->GetArg(*CmdLine->ArgsLeft.begin()) );
269 CmdLine->ArgsLeft.erase( CmdLine->ArgsLeft.begin() );
270 }
271 ConsumedArguments+= size_t( argsExpected );
272 }
273
274
275 return true;
276}
277
278void ERCommandDecl ::Parse()
279{
280 enumrecords::bootstrap::EnumRecordParser::Get( ERSerializable::EnumElementName );
281 enumrecords::bootstrap::EnumRecordParser::Get( ERSerializable::MinimumRecognitionLength );
283}
284
294
305
306void ERExitCodeDecl ::Parse()
307{
308 enumrecords::bootstrap::EnumRecordParser::Get( ERSerializable::EnumElementName );
309 ERSerializable::MinimumRecognitionLength = 0;
311}
312
313}} // namespace alib::cli
ERCommandDecl record
A copy (!) of the enum record.
CommandLine & CmdLine
The command line instance we belong to.
ALIB_DLL ParameterDecl * GetParameterDecl(const String &name)
Definition arguments.cpp:59
const String & Identifier()
ALIB_DLL void addParamDecls()
Definition arguments.cpp:38
List< MonoAllocator, ParameterDecl * > Parameters
Command parameters.
const String & ValueSeparator()
integer QtyExpectedArgsFollowing()
const String & Identifier()
character IdentifierChar()
const String & Identifier()
const String & Name()
const String & ValueSeparator()
constexpr integer Length() const
Definition string.inl:318
constexpr bool IsEmpty() const
Definition string.inl:367
integer IndexOf(TChar needle, integer startIdx=0) const
Definition string.inl:844
TChar CharAt(integer idx) const
Definition string.inl:421
constexpr bool IsNotEmpty() const
Definition string.inl:371
constexpr bool IsNull() const
Definition string.inl:352
bool StartsWith(const TString &needle) const
Definition string.inl:772
bool ConsumeString(const TString< TChar > &consumable)
TSubstring & Split(integer position, TSubstring &target, integer separatorWidth=0, bool trim=false)
ALIB_DLL TSubstring< TChar > & Next(lang::Whitespaces trimming=lang::Whitespaces::Trim, TChar newDelim='\0')
Definition tokenizer.cpp:26
TSubstring< TChar > Actual
Definition tokenizer.inl:66
#define ALIB_CALLER_NULLED
Definition alib.inl:1010
#define A_CHAR(STR)
#define ALIB_DBG(...)
Definition alib.inl:836
#define ALIB_ASSERT_ERROR(cond, domain,...)
Definition alib.inl:1049
constexpr String NULL_STRING
A nulled string of the default character type.
Definition string.inl:2463
strings::util::TTokenizer< character > Tokenizer
Type alias in namespace alib.
lang::integer integer
Type alias in namespace alib.
Definition integers.inl:149
exceptions::Exception Exception
Type alias in namespace alib.
strings::TString< character > String
Type alias in namespace alib.
Definition string.inl:2381
characters::character character
Type alias in namespace alib.
strings::TSubstring< character > Substring
Type alias in namespace alib.
See sibling type NC.
Definition chk_nc.inl:33
ALIB_DLL Parameter * GetParsedParameter(const String &name)
ALIB_DLL bool Read(CommandDecl &decl)
ALIB_DLL String GetParsedParameterArg(const String &name)
CommandDecl * Declaration
The underlying declaration.
List< MonoAllocator, Parameter *, Recycling::Shared > ParametersOptional
Optional parameters parsed.
List< MonoAllocator, Parameter *, Recycling::Shared > ParametersMandatory
Mandatory parameters parsed.
String parameters
List of parameters attached. Separated by '/'.
int associatedCLIException
The CLI module exception associated to this exit code.
ALIB_DLL void Parse()
Implementation of EnumRecordPrototype::Parse.
String identifier
The identifier of the parameter.
Definition arguments.inl:56
bool isOptional
Denotes if this is an optional parameter.
Definition arguments.inl:74
List< MonoAllocator, String, Recycling::Shared > Args
Arguments belonging to this option.
OptionDecl * Declaration
The declaration struct.
ALIB_DLL bool Read(OptionDecl &decl, String &arg, const integer argNo)
Definition arguments.cpp:69
A declaration for a cli::Parameter.
ParameterDecl * Declaration
The underlying declaration.
List< MonoAllocator, String, Recycling::Shared > Args
Arguments belonging to us.
ALIB_DLL bool Read(ParameterDecl &decl)
integer ConsumedArguments
Definition arguments.inl:35
CommandLine * CmdLine
The cli command line.
Definition arguments.inl:26
static ALIB_DLL void Get(String &result, bool isLastField=false)