ALib C++ Framework
by
Library Version: 2605 R0
Documentation generated by doxygen
Loading...
Searching...
No Matches
cliutil.cpp
1
2namespace alib::app {
3
4OptionDecl* CLIUtil::GetOptionDecl( CommandLine& cmdLine, const String& identString ) {
5 for( auto* decl : cmdLine.OptionDecls )
6 if ( ( identString.Length() == 1
7 && identString.CharAtStart<NC>() == decl->IdentifierChar() )
8 || ( identString.Length() >= decl->MinimumRecognitionLength()
9 && decl->Identifier().StartsWith<CHK,lang::Case::Ignore>( identString ) ) )
10 return decl;
11 return nullptr;
12}
13
14
15CommandDecl* CLIUtil::GetCommandDecl( CommandLine& cmdLine, const String& identString ) {
16 for( auto* decl : cmdLine.CommandDecls )
17 if ( identString.Length() >= decl->MinimumRecognitionLength()
18 && decl->Identifier().StartsWith<CHK,lang::Case::Ignore>( identString ) )
19 return decl;
20 return nullptr;
21}
22
24 for( auto* decl : cmdLine.ParameterDecls )
25 if ( decl->Name().StartsWith<CHK,lang::Case::Ignore>( identString ) )
26 return decl;
27 return nullptr;
28}
29
30
31
33 AString result;
34 result.EnsureRemainingCapacity(2048);
35 auto& appName= cmdLine.TryResource( "HlpCLIAppName" );
36 if( appName.IsNotEmpty() )
37 result << appName << ' ';
38 result << cmd.Identifier();
39
40 for( auto* param : cmd.Parameters ) {
41 result << ' ';
42 if( param->IsOptional() ) result << '[';
43
44 result << param->Name();
45 if ( param->ValueListSeparator() != '\0' ) {
46 result << '[' << param->ValueListSeparator() << param->Name() << "...]";
47 }
48
49 if( param->IsOptional() ) result << ']';
50
51 }
52 return result;
53}
54
56bool CLIUtil::GetHelp( CommandLine& cmdLine, Command* helpCmd, Paragraphs& text ) {
57 String topics= NULL_STRING;
58 if( helpCmd->ParametersOptional.IsNotEmpty() )
59 topics= helpCmd->ParametersOptional.front()->Args.front();
60 else if( cmdLine.ArgCount() > helpCmd->Position + 1 ) {
61 topics= cmdLine.GetArg(helpCmd->Position + 1);
62 if( cmdLine.RemoveArg( helpCmd->Position + 1 ) )
63 ++helpCmd->ConsumedArguments;
64 else
65 topics= NULL_STRING;
66 }
67 return GetHelp(cmdLine, topics, text);
68}
69
70bool CLIUtil::GetHelp( CommandLine& cmdLine, Option* helpOpt, Paragraphs& text ) {
71 String topics= NULL_STRING;
72 if( helpOpt->Args.IsNotEmpty() )
73 topics= helpOpt->Args.front();
74 else if( cmdLine.ArgCount() > helpOpt->Position + 1 ) {
75 topics= cmdLine.GetArg(helpOpt->Position + 1);
76 if(cmdLine.RemoveArg( helpOpt->Position + 1 ) )
77 ++helpOpt->ConsumedArguments;
78 else
79 topics= NULL_STRING;
80 helpOpt->Args.push_back( topics );
81 }
82
83 return GetHelp(cmdLine, topics, text);
84}
85
86
87bool CLIUtil::GetHelp( CommandLine& cmdLine, const String& topics, Paragraphs& text )
89 integer oldTextLength= text.Buffer.Length();
90 text.AddMarked( cmdLine.AppInfo );
91
92 if( topics.IsNotEmpty() ) {
93 int cntArgsRecognized= 0;
94
95 Tokenizer args( topics, ',' );
96 int cntTokens= 0;
97 while( args.HasNext() ) {
98 ++cntTokens;
99
100 String arg= args.Next();
101 int cntArgsRecognizedSoFar= cntArgsRecognized;
102
103 // command
104 {
105 CommandDecl* cmdDecl= CLIUtil::GetCommandDecl( cmdLine, arg );
106 if( cmdDecl ) {
107 ++cntArgsRecognized;
108
109 text.Add( cmdLine.GetResource( "HlpHdlTopic" ), "command", cmdDecl->Identifier() )
110 .PushIndent( 2 )
111 .Add( cmdLine.GetResource( "HlpHdlUsage" ), " ", GetCommandUsageFormat( cmdLine, *cmdDecl ) )
112
113 .Add( NEW_LINE, cmdLine.GetResource( "HlpHdlDscr" ) )
114 .PushIndent( 2 )
115 .AddMarked( cmdDecl->HelpTextLong(), NEW_LINE )
116 .PopIndent();
117
118 if(cmdDecl->Parameters.IsNotEmpty()) {
119 text.Add( NEW_LINE, cmdLine.GetResource( "HlpHdlPDscr" ) )
120 .PushIndent( 2 );
121 for( auto* param : cmdDecl->Parameters ) {
122 text.Add( "* ", param->Name() )
123 .PushIndent( 2 )
124 .AddMarked( param->GetHelpTextShort() )
125 .PopIndent()
126 .Add( NEW_LINE );
127 }
128 text.PopIndent();
129 }
130 text.PopIndent();
131 } }
132
133 // option?
134 if( cntArgsRecognizedSoFar == cntArgsRecognized ) {
135 OptionDecl* optDecl= CLIUtil::GetOptionDecl( cmdLine, arg );
136 if( optDecl ) {
137 ++cntArgsRecognized;
138 text.Add( cmdLine.GetResource( "HlpHdlTopic" ), "option", optDecl->Identifier() )
139 .PushIndent( 2 )
140 .Add( cmdLine.GetResource( "HlpHdlUsage" ), " ", optDecl->HelpUsageLine() )
141 .Add( NEW_LINE, cmdLine.GetResource( "HlpHdlDscr" ) )
142 .PushIndent( 2 )
143 .AddMarked( optDecl->HelpText(), NEW_LINE )
144 .PopIndent()
145 .PopIndent();
146 } }
147
148 // parameter?
149 if( cntArgsRecognizedSoFar == cntArgsRecognized ) {
150 ParameterDecl* paramDecl= CLIUtil::GetParameterDecl( cmdLine, arg );
151 if( paramDecl ) {
152 ++cntArgsRecognized;
153 text.Add( cmdLine.GetResource( "HlpHdlTopic" ), "parameter", paramDecl->Name() )
154 .PushIndent( 2 )
155 .AddMarked( paramDecl->GetHelpTextLong() )
156 .PopIndent();
157 } }
158
159 // special help topic?
160 if( cntArgsRecognizedSoFar == cntArgsRecognized ) {
161 auto& additionalHelpTopics= cmdLine.TryResource("HlpAddnlTopics");
162 if( additionalHelpTopics.IsNotEmpty() ) {
163 Tokenizer topicsTknzr(additionalHelpTopics, ',');
164 while(topicsTknzr.Next().IsNotEmpty()) {
165 if(topicsTknzr.Actual.StartsWith<CHK,lang::Case::Ignore>( arg ) ) {
166 ++cntArgsRecognized;
167 text.AddMarked( cmdLine.GetResource( NString64("HlpAddnl")._( topicsTknzr.Actual ) ) );
168 break;
169 } } } } }
170
171
172 // not peeked means "--help=arg" was given. In this case, the argument has to be recognized.
173 // Also in the case that more than one token was read but the recognized qty is smaller.
174 if ( ( cntArgsRecognized == 0 )
175 || ( cntTokens > 1 && cntArgsRecognized < cntTokens ) ) {
176 text.Buffer.ShortenTo(oldTextLength);
177 return false;
178 }
179
180 // consumed arg?
181 if( cntArgsRecognized > 0 )
182 return true;
183 }
184
185 // general help
186 text.AddMarked( cmdLine.GetResource( "HlpGeneral" ) );
187
188 text.Add( cmdLine.GetResource( "HlpHdlUsage" ) )
189 .PushIndent( 2 )
190 .Add( cmdLine.GetResource( "HlpUsage" ) )
191 .PopIndent();
192
193 text.Add( NEW_LINE, cmdLine.GetResource( "HlpHdlCmds" ) )
194 .PushIndent( 2 );
195 for( auto* decl : cmdLine.CommandDecls ) {
196 text.Add( "* ", GetCommandUsageFormat( cmdLine, *decl ), NEW_LINE )
197 .PushIndent( 2 )
198 .Add( decl->HelpTextShort(), NEW_LINE )
199 .PopIndent();
200 }
201 text.PopIndent();
202
203 text.Add( NEW_LINE, cmdLine.GetResource( "HlpHdlOpts" ) )
204 .PushIndent( 2 );
205 for( auto* decl : cmdLine.OptionDecls )
206 text.Add( decl->HelpUsageLine() );
207 text.PopIndent();
208
209
210 text.Add( cmdLine.GetResource( "HlpHdlExtCds") )
211 .PushIndent( 2 );
212 {
213 // sort the exit-codes by their number
214 auto snapshot= cmdLine.allocator.TakeSnapshot();
216 for( auto& declIt : cmdLine.ExitCodeDecls )
217 sortedExitCodes.emplace_back(declIt);
218 std::sort( sortedExitCodes.begin(), sortedExitCodes.end(),
219 []( std::pair<Enum, ExitCodeDecl *>& lhs,
220 std::pair<Enum, ExitCodeDecl *>& rhs)
221 {
222 return lhs.first.Integral() < rhs.first.Integral();
223 }
224 );
225
226 for( auto& declIt : sortedExitCodes )
227 text.Add( " {:>3}: {}\n {}", declIt.first.Integral(),
228 declIt.second->Name(),
229 declIt.second->FormatString() );
230 cmdLine.allocator.Reset(snapshot);
231 }
232 text.PopIndent();
233
234 return true;
235}
236
238 dump.Add( "COMMANDS:")
239 .PushIndent( 2 );
240 for( auto* decl : cmdLine.CommandDecls ) {
241 dump.Add( "- ({}) {}", decl->Element(), decl->Identifier())
242 .PushIndent( 2 );
243 String256 paramIDs;
244 for( auto& param : decl->Parameters )
245 paramIDs << param->Name() << ", ";
246 if( paramIDs.IsEmpty() )
247 paramIDs << "none";
248 else
249 paramIDs.DeleteEnd( 2 );
250 dump.Add( "Associated parameters: ", paramIDs )
251 .Add( decl->HelpTextShort())
252 .PopIndent()
253 .Add( NEW_LINE );
254 }
255 dump.PopIndent()
256
257
258 .Add( NEW_LINE )
259 .Add( "OPTIONS:")
260 .PushIndent( 2 );
261 for( auto* decl : cmdLine.OptionDecls ) {
262 dump.Add( decl->HelpUsageLine() )
263 .Add( decl->HelpText() )
264 .Add( NEW_LINE );
265 }
266 dump.PopIndent();
267
268
269
270 dump.Add( NEW_LINE )
271 .Add( "PARAMETERS:")
272 .PushIndent( 2 );
273 for( auto* decl : cmdLine.ParameterDecls ) {
274 dump.Add( "- ({}) {} Optional: {} Multi-Separator: {}" ,
275 decl->Element(),
276 decl->Name(),
277 decl->IsOptional(),
278 (decl->ValueListSeparator() ? Box(decl->ValueListSeparator()) : Box("-/-") ))
279 .Add( decl->GetHelpTextShort())
280 .Add( NEW_LINE );
281 }
282 dump.PopIndent()
283
284 .Add( NEW_LINE )
285 .Add( "EXIT-CODES:")
286 .PushIndent( 2 );
287 for( auto& declIt : cmdLine.ExitCodeDecls )
288 dump.Add( "{:>5} : {}", declIt.first, declIt.second->FormatString() );
289
290 dump.PopIndent();
291
292 return dump.Buffer;
293}
294
295
296//! @cond NO_DOX
297namespace
298{
299void dumpParsedOptions( CommandLine& app, ListMA<Option*>& optionsOriginal,
300 Paragraphs& dump ) {
301 std::vector<Option*> options;
302 std::vector<Option*> optionsOfActType;
303 auto overallSize= optionsOriginal.size();
304 options .reserve( size_t(overallSize) );
305 optionsOfActType.reserve( size_t(overallSize) );
306 for( auto* optionOrig : optionsOriginal )
307 options.push_back( optionOrig );
308
309 dump.PushIndent( 2 );
310 while( options.size() ) {
311 // collect all options of the same type in optionsOfActType
312 auto* decl= options.front()->Declaration;
313 optionsOfActType.clear();
314 size_t actIdx= 0;
315 while( actIdx < options.size() ) {
316 if( options[actIdx]->Declaration == decl ) {
317 optionsOfActType.push_back( options[actIdx] );
318 options.erase( options.begin() + integer(actIdx) );
319 }
320 else
321 ++actIdx;
322 }
323
324
325 dump.Add( "- \"-{},--{}\" ({}x)",
326 decl->IdentifierChar(), decl->Identifier(), optionsOfActType.size() )
327 .PushIndent( 2 );
328
329 for( actIdx= 0; actIdx < optionsOfActType.size() ; ++actIdx ) {
330 Option* actOption= optionsOfActType[actIdx];
331 dump.Add( "{}/{}: ArgStrings{!Q[]}= {!Q}, #arguments parsed: {}",
332 actIdx + 1, optionsOfActType.size(),
333 actOption->Position,
334 app.GetArg(actOption->Position),
335 actOption->Args.size() )
336 .PushIndent(5);
337
338 uinteger argNo= 0;
339 for( auto& arg : actOption->Args )
340 dump.Add( "Argument {}: {!Q}", ++argNo, arg );
341 dump.PopIndent();
342
343 }
344 dump.PopIndent()
345 .Add( NEW_LINE );
346 }
347 dump.PopIndent();
348}
349} // anon namespace
350//! @endcond
351
353 dump.Add( NEW_LINE )
354 .Add( "OPTIONS:");
355 dumpParsedOptions( cmdLine, cmdLine.Options, dump );
356
357 dump.Add( NEW_LINE )
358 .Add( "OPTION ARGUMENTS IGNORED (Usable with other libs):")
359 .PushIndent( 2 );
360 int cnt= 0;
361 for( auto& it : cmdLine.OptionArgsIgnored )
362 dump.Add( "{}: {!Q}", cnt++ + 1, it );
363 if (cnt == 0 )
364 dump.Add( "None" );
365 dump.PopIndent();
366
367 dump.Add( NEW_LINE )
368 .Add( "COMMANDS PARSED:")
369 .PushIndent( 2 );
370 cnt= 0;
371 for( auto& cmd : cmdLine.CommandsParsed ) {
372 ++cnt;
373 dump.Add( "- {:8}with argument #{}", cmd->Declaration->Identifier(), cmd->Position )
374 .PushIndent( 2 );
375 for( auto* param : cmd->ParametersMandatory ) {
376 dump.Add( "Parameter: {}", param->Declaration->Name() )
377 .PushIndent( 2 );
378 uinteger argNo= 0;
379 for( auto& arg : param->Args )
380 dump.Add( "Parameter argument {}: {!Q}", ++argNo, arg );
381 dump.PopIndent();
382
383 }
384 for( auto* param : cmd->ParametersOptional ) {
385 dump.Add( "Parameter: {}", param->Declaration->Name() )
386 .PushIndent( 2 );
387 uinteger argNo= 0;
388 for( auto& arg : param->Args )
389 dump.Add( "Parameter argument {}: {!Q}", ++argNo, arg );
390 dump.PopIndent();
391
392 }
393 dump.PopIndent()
394 .Add( NEW_LINE );
395 }
396 if (cnt == 0 )
397 dump.Add( "None" );
398 dump.PopIndent();
399
400
401
402 dump.Add( NEW_LINE )
403 .Add( "UNRECOGNIZED CLI ARGUMENTS:")
404 .PushIndent( 2 );
405 for( auto& it : cmdLine.ArgsLeft )
406 dump.Add( "{}: {!Q}", it, cmdLine.GetArg(it));
407
408 if (cmdLine.ArgsLeft.size() == 0 )
409 dump.Add( "None" );
410 dump.PopIndent();
411
412 return dump.Buffer;
413}
414
415} // namespace alib::app
416#include "ALib.Lang.CIMethods.H"
#define ALIB_LOCK_RECURSIVE_WITH(lock)
static AString & DumpParseResults(CommandLine &cmdLine, Paragraphs &text)
Definition cliutil.cpp:352
static OptionDecl * GetOptionDecl(CommandLine &cmdLine, const String &identString)
Definition cliutil.cpp:4
static AString & DumpDeclarations(CommandLine &cmdLine, Paragraphs &text)
Definition cliutil.cpp:237
static AString GetCommandUsageFormat(CommandLine &cmdLine, CommandDecl &commandDecl)
Definition cliutil.cpp:32
static ParameterDecl * GetParameterDecl(CommandLine &cmdLine, const String &identString)
Definition cliutil.cpp:23
static CommandDecl * GetCommandDecl(CommandLine &cmdLine, const String &identString)
Definition cliutil.cpp:15
static bool GetHelp(CommandLine &cmdLine, const String &topics, Paragraphs &text)
Definition cliutil.cpp:87
const String & HelpTextLong()
ListMA< ParameterDecl * > Parameters
Command parameters.
const String & Identifier()
HashMap< MonoAllocator, Enum, ExitCodeDecl * > ExitCodeDecls
Possible Errors.
Definition cli.hpp:93
const String & TryResource(const NString &name)
Definition cli.hpp:185
ListMA< Command * > CommandsParsed
A list of commands actually parsed. Filled with method #"ReadNextCommands".
Definition cli.hpp:107
MonoAllocator allocator
Definition cli.hpp:52
ListMA< CommandDecl * > CommandDecls
Commands defined.
Definition cli.hpp:84
ListMA< OptionDecl * > OptionDecls
Possible Options.
Definition cli.hpp:87
ListMA< ParameterDecl * > ParameterDecls
Possible Parameters.
Definition cli.hpp:90
const String & GetResource(const NString &name)
Definition cli.hpp:173
virtual String GetArg(integer idx)
Definition cli.hpp:455
ListMA< String, Recycling::Shared > OptionArgsIgnored
Definition cli.hpp:104
bool RemoveArg(integer argNo)
Definition cli.cpp:173
StdVectorMA< integer > ArgsLeft
Definition cli.hpp:80
virtual int ArgCount()
Definition cli.hpp:448
ListMA< Option * > Options
The options parsed in the order of their appearance.
Definition cli.hpp:98
const String & HelpUsageLine()
const String & Identifier()
const String & HelpText()
const String & GetHelpTextLong()
integer size() const
Definition list.hpp:390
static threads::RecursiveLock DEFAULT_LOCK
Paragraphs & PushIndent(uinteger qty, character fillChar=' ')
void Add(boxing::TBoxes< TAllocatorArgs > &args)
void AddMarked(boxing::TBoxes< TAllocatorArgs > &args)
Paragraphs & PopIndent()
void Reset(Snapshot snapshot=Snapshot())
TAString & DeleteEnd(integer regionLength)
TAString & ShortenTo(integer newLength)
Definition tastring.hpp:741
void EnsureRemainingCapacity(integer spaceNeeded)
Definition tastring.hpp:555
constexpr integer Length() const
Definition string.hpp:300
constexpr bool IsEmpty() const
Definition string.hpp:349
TChar CharAtStart() const
Definition string.hpp:417
constexpr bool IsNotEmpty() const
Definition string.hpp:353
bool StartsWith(const TString &needle) const
Definition string.hpp:735
size_type size() const
Definition string.hpp:1977
TSubstring< TChar > Actual
Definition tokenizer.hpp:64
TSubstring< TChar > & Next(lang::Whitespaces trimming=lang::Whitespaces::Trim, TChar newDelim='\0')
Definition tokenizer.cpp:4
constexpr String NULL_STRING
A nulled string of the default character type.
Definition string.hpp:2247
strings::util::TTokenizer< character > Tokenizer
Type alias in namespace #"%alib".
containers::List< T, MonoAllocator, TRecycling > ListMA
Type alias in namespace #"%alib".
Definition list.hpp:689
constexpr CString NEW_LINE
A zero-terminated string containing the new-line character sequence.
Definition cstring.hpp:536
lang::integer integer
Type alias in namespace #"%alib".
Definition integers.hpp:149
boxing::Box Box
Type alias in namespace #"%alib".
Definition box.hpp:1128
strings::TString< character > String
Type alias in namespace #"%alib".
Definition string.hpp:2165
LocalString< 256 > String256
Type alias name for #"TLocalString;TLocalString<character,256>".
strings::TAString< character, lang::HeapAllocator > AString
Type alias in namespace #"%alib".
format::Paragraphs Paragraphs
Type alias in namespace #"%alib".
lang::uinteger uinteger
Type alias in namespace #"%alib".
Definition integers.hpp:152
variables::Declaration Declaration
Type alias in namespace #"%alib".
std::vector< T, StdMA< T > > StdVectorMA
Type alias in namespace #"%alib".
NLocalString< 64 > NString64
Type alias name for #"TLocalString;TLocalString<nchar,64>".
See sibling type #"NC".
Definition chk_nc.hpp:30
A command argument of the command-line.
ListMA< Parameter *, Recycling::Shared > ParametersOptional
Optional parameters parsed.
ListMA< String, Recycling::Shared > Args
Arguments belonging to this option.
integer ConsumedArguments