ALib C++ Library
Library Version: 2511 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;
19 import ALib.Characters.Functions;
20 import ALib.Strings;
21 import ALib.Strings.Tokenizer;
22 import ALib.EnumRecords.Bootstrap;
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 Tokenizer tknzr( record.parameters , '/' );
40 while( tknzr.Next().IsNotEmpty() ) {
41ALIB_DBG( bool found= false; )
42
43 for( auto* paramDecl : CmdLine.ParameterDecls )
44 if( paramDecl->Name().StartsWith<CHK, lang::Case::Ignore>( tknzr.Actual ) ) {
45 Parameters.push_back( paramDecl );
46 ALIB_DBG(found= true; )
47 break;
48 }
49
50 ALIB_ASSERT_ERROR( found, "CLI",
51 "Parameter named \"{}\" not found while loading resources of command \"{}\".",
52 tknzr.Actual, Identifier() )
53} }
54
56 for( auto* param : Parameters )
57 if( param->Name().Equals<NC>( name ) )
58 return param;
59
60 return nullptr;
61}
62
63
64bool Option::Read( OptionDecl& decl, String& argProbablyReplaced, const integer argNo ) {
65 String identifier = decl.Identifier();
66 character identifierC = decl.IdentifierChar();
67 auto argsExpected= decl.QtyExpectedArgsFollowing();
68 auto argsLeft = CmdLine->ArgsLeft.size() -1;
69
70 // read single/double hyphen options once
71 Substring arg= argProbablyReplaced;
72 Substring inArgArgument;
73 auto valueSeparator= arg.IndexOf<CHK, lang::Case::Sensitive>( decl.ValueSeparator() );
74 if( valueSeparator > 0 )
75 arg.Split<NC>( valueSeparator, inArgArgument, decl.ValueSeparator().Length() );
76
77 bool potentialIllegalContinuation= false;
78 if ( !( ( identifier.IsNotEmpty()
79 && arg.ConsumeString(A_CHAR("--"))
80 && arg.Length() >= decl.MinimumRecognitionLength()
81 && ( identifier.StartsWith<CHK, lang::Case::Ignore>( arg )
82 || true == (potentialIllegalContinuation= arg.StartsWith<CHK,lang::Case::Ignore>( identifier )) )
83
84 )
85
86 || ( arg.ConsumeChar('-')
87 && arg.ConsumeChar(identifierC) )
88 )
89 )
90 return false;
91
92 // Throw if the identifier was fully matched, but the argument continues with a
93 // non-alphanumerical value.
94 // (This is only allowed if separator was set in resource. But in this case, the flag will
95 // never match, because of the code above...)
96 if( potentialIllegalContinuation ) {
97 auto nextChar= arg.CharAt<NC>( identifier.Length() );
98 if( !isalnum( nextChar ) )
100 identifier, argNo, CmdLine->GetArg(argNo) );
101 return false;
102 }
103
104 Declaration= &decl;
105 Position= argNo;
106
108
109
110 // store in-arg argument
111 if( valueSeparator > 0) {
112 Args.push_back( inArgArgument );
113 if(argsExpected > 0 )
114 --argsExpected;
115 }
116
117
118 // error: not enough params
119 if ( argsExpected > integer(argsLeft) )
121 decl.Identifier(), argNo, CmdLine->GetArg(argNo),
122 argsExpected, argsLeft );
123
124 // store arg strings
125 for( integer i= 0; i < argsExpected; ++i )
126 Args.push_back( CmdLine->GetArg(argNo + 1 + i) );
127 ConsumedArguments+= argsExpected;
128
129 return true;
130}
131
133 auto& identifier= decl.Identifier();
134 String arg = CmdLine->PeekArg();
135
136 if ( arg.Length() < decl.MinimumRecognitionLength()
137 || !identifier.StartsWith<CHK,lang::Case::Ignore>( arg ) )
138 return false;
139
140 Declaration= &decl;
141 Position= CmdLine->ArgsLeft[0];
142 CmdLine->PopArg();
144
145 if( decl.Parameters.size() == 0 )
146 return true;
147
148 auto paramDeclIt= decl.Parameters.begin();
149 while( paramDeclIt != decl.Parameters.end() ) {
150 Parameter param( CmdLine );
151 bool continueReading= param.Read( **paramDeclIt );
152 if( param.ConsumedArguments ) {
154 Parameter* paramFound= CmdLine->allocator().New<Parameter>(param);
155 if ( (*paramDeclIt)->IsOptional() )
156 ParametersOptional.push_back( paramFound );
157 else
158 ParametersMandatory.push_back( paramFound );
159
160 // start from the beginning
161 paramDeclIt= decl.Parameters.begin();
162 }
163 else
164 ++paramDeclIt;
165
166 // stop here if parameter read signaled this
167 if( !continueReading )
168 return false;
169 }
170
171 return true;
172}
173
175 #if ALIB_DEBUG
176 bool found= false;
177 for( auto* paramDecl : Declaration->Parameters )
178 if( paramDecl->Name().Equals<NC>(name) ) {
179 found = true;
180 break;
181 }
182 ALIB_ASSERT_ERROR( found, "CLI", "Requested parameter \"{}\" not defined.", name )
183 #endif
184
185 for( auto* param : ParametersMandatory )
186 if( param->Declaration->Name().Equals<NC>( name ) )
187 return param;
188
189 for( auto* param : ParametersOptional )
190 if( param->Declaration->Name().Equals<NC>( name ) )
191 return param;
192
193 return nullptr;
194}
195
197 Parameter* param= GetParsedParameter( name );
198 return param && param->Args.IsNotEmpty() ? param->Args.front()
199 : NULL_STRING;
200}
201
202
204 Substring arg= CmdLine->PeekArg();
205 if( arg.IsNull() )
206 return false;
207
208 auto& identifier= decl.Identifier();
209 if ( identifier.IsEmpty() && decl.IsOptional() )
210 return false;
211
212 auto valueSeparator= arg.IndexOf<CHK, lang::Case::Sensitive>( decl.ValueSeparator() );
213 Substring inArgArgument;
214 if( valueSeparator > 0 )
215 arg.Split<NC>( valueSeparator, inArgArgument, decl.ValueSeparator().Length() );
216
217 if ( identifier.IsEmpty()
218 || ( arg.Length() >= decl.MinimumRecognitionLength()
219 && identifier.StartsWith<CHK,lang::Case::Ignore>( arg ) ) )
220 {
222 Declaration= &decl;
223 Position= CmdLine->ArgsLeft[0];
224 CmdLine->PopArg();
225 int argsExpected= decl.QtyExpectedArgsFollowing();
226
227 if( decl.Identifier().IsEmpty() ) {
228 Args.push_back( arg );
229 } else {
230 if( inArgArgument.IsNotEmpty() ) {
231 Args.push_back( inArgArgument );
232 --argsExpected;
233 } }
234
235 // stop command?
236 if( argsExpected < 0 )
237 return false;
238
239 // error: not enough params
240 if ( argsExpected > integer(CmdLine->ArgsLeft.size()) )
242 decl.Name(), Position, CmdLine->GetArg(Position),
243 argsExpected, CmdLine->ArgsLeft.size() );
244
245 // store arg strings
246 for( size_t i= 0; i < size_t( argsExpected ); ++i ) {
247 Args.push_back( CmdLine->GetArg(*CmdLine->ArgsLeft.begin()) );
248 CmdLine->ArgsLeft.erase( CmdLine->ArgsLeft.begin() );
249 }
250 ConsumedArguments+= size_t( argsExpected );
251 }
252
253
254 return true;
255}
256
257void ERCommandDecl ::Parse() {
258 enumrecords::bootstrap::EnumRecordParser::Get( ERSerializable::EnumElementName );
259 enumrecords::bootstrap::EnumRecordParser::Get( ERSerializable::MinimumRecognitionLength );
261}
262
271
281
282void ERExitCodeDecl ::Parse() {
283 enumrecords::bootstrap::EnumRecordParser::Get( ERSerializable::EnumElementName );
284 ERSerializable::MinimumRecognitionLength = 0;
286}
287
288}} // namespace alib::cli
ERCommandDecl record
A copy (!) of the enum record.
ListMA< ParameterDecl * > Parameters
Command parameters.
CommandLine & CmdLine
The command line instance we belong to.
ALIB_DLL ParameterDecl * GetParameterDecl(const String &name)
Definition arguments.cpp:55
const String & Identifier()
ALIB_DLL void addParamDecls()
Definition arguments.cpp:38
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:316
constexpr bool IsEmpty() const
Definition string.inl:365
integer IndexOf(TChar needle, integer startIdx=0) const
Definition string.inl:815
TChar CharAt(integer idx) const
Definition string.inl:415
constexpr bool IsNotEmpty() const
Definition string.inl:369
constexpr bool IsNull() const
Definition string.inl:350
bool StartsWith(const TString &needle) const
Definition string.inl:751
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:67
#define ALIB_CALLER_NULLED
Definition alib.inl:1027
#define A_CHAR(STR)
#define ALIB_DBG(...)
Definition alib.inl:853
#define ALIB_ASSERT_ERROR(cond, domain,...)
Definition alib.inl:1066
constexpr String NULL_STRING
A nulled string of the default character type.
Definition string.inl:2271
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:2189
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.
ListMA< Parameter *, Recycling::Shared > ParametersMandatory
Mandatory parameters parsed.
ListMA< Parameter *, Recycling::Shared > ParametersOptional
Optional 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:54
bool isOptional
Denotes if this is an optional parameter.
Definition arguments.inl:72
OptionDecl * Declaration
The declaration struct.
ALIB_DLL bool Read(OptionDecl &decl, String &arg, const integer argNo)
Definition arguments.cpp:64
ListMA< String, Recycling::Shared > Args
Arguments belonging to this option.
A declaration for a cli::Parameter.
ListMA< String, Recycling::Shared > Args
Arguments belonging to us.
ParameterDecl * Declaration
The underlying declaration.
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)