ALib C++ Library
Library Version: 2510 R0
Documentation generated by doxygen
Loading...
Searching...
No Matches
commandline.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# if ALIB_STRINGS
21 import ALib.Strings;
22# endif
23#else
25# include "ALib.Strings.H"
26# include "ALib.CLI.H"
27#endif
28// ====================================== Implementation =======================================
29namespace alib::cli {
30
31// #################################################################################################
32// CommandLine Constructor
33// #################################################################################################
34
35void CommandLine::Init( resources::ResourcePool* resourcePool, NCString resCategory )
36{
37 Resources = resourcePool;
38 ResourceCategory= resCategory;
39
40 ArgStrings.reserve( size_t(ARG_C) );
41 ArgsLeft .reserve( size_t(ARG_C) );
42
43 #if !ALIB_CHARACTERS_WIDE
44 if( ARG_VN )
45 {
46 for ( int i= 1; i < ARG_C ; ++i )
47 {
48 ArgStrings.emplace_back( ARG_VN[i] );
49 ArgsLeft .emplace_back( i -1 );
50 }
51 }
52 else
53 {
54 // convert wide to narrow strings
55 NString1K converter;
57
58 for ( int i= 1; i < ARG_C ; ++i )
59 {
60 converter.Reset() << ARG_VW[i];
61 ArgStrings.emplace_back( String( allocator, converter) );
62 ArgsLeft .emplace_back( i - 1 );
63 }
64 }
65 #else
66 #if ALIB_CHARACTERS_NATIVE_WCHAR // use original strings only if alib::wchar == wchar_t
67 if( ARG_VW )
68 {
69 for ( int i= 1; i < ARG_C ; ++i )
70 {
71 ArgStrings.emplace_back( ARG_VW[i] );
72 ArgsLeft .emplace_back( i - 1 );
73 }
74 }
75 else
76 #endif
77 {
78 // convert narrow to wide strings (or "wrong" wide width to width)
79 String1K converter;
81
82 for ( int i= 1; i < ARG_C ; ++i )
83 {
84 converter.Reset() << ARG_VN[i];
85 ArgStrings.emplace_back( String(allocator, converter) );
86 ArgsLeft .emplace_back( i -1 );
87 }
88 }
89 #endif
90}
91
92// #################################################################################################
93// Interface
94// #################################################################################################
95
97{
98 // loop over all arg indices in ArgsLeft
99 integer argIdx= 0;
100 while( argIdx < integer(ArgsLeft.size()) )
101 {
102 // get arg number and string once
103 auto argNo= ArgsLeft[size_t(argIdx)];
104 String arg = GetArg(argNo);
105
106 SHORTCUT_JUMP:
107
108 // ignore non-option args
109 if( arg.CharAtStart() != '-' )
110 {
111 ++argIdx;
112 continue;
113 }
114
115 // create an option object and search decl with the actual argument
116 {
117 Option* option= allocator().New<Option>(this);
118
119 auto optionDeclIt= OptionDecls.begin();
120 try
121 {
122 while( optionDeclIt != OptionDecls.end() )
123 {
124 if( option->Read( **optionDeclIt, arg, argNo ) )
125 break;
126 ++optionDeclIt;
127 }
128 }
129 catch ( Exception& e )
130 {
132 (*optionDeclIt)->HelpUsageLine() );
133 throw;
134 }
135
136 // found a declaration?
137 if( option->ConsumedArguments > 0 )
138 {
139 // shortcut to another option?
140 OptionDecl& decl= *option->Declaration;
142 {
143 arg= decl.ShortcutReplacementString();
144 goto SHORTCUT_JUMP;
145 }
146
147 // delete args and continue
148 ArgsLeft.erase( ArgsLeft.begin() + argIdx,
149 ArgsLeft.begin() + argIdx + option->ConsumedArguments );
150
151 // move local option into the monotonic memory add to the list for this option type.
152 Options.push_back( option );
153 continue;
154 }
155
156
157 // erase args that start with '-' and put them into field OptionsIgnored.
158 if( ArgsLeft.size() > 0 )
159 {
160 OptionArgsIgnored.push_back( GetArg(argNo) );
161 ArgsLeft.erase( ArgsLeft.begin() + argIdx );
162 }
163 }
164 }
165}
166
168{
169 for( auto optionIt= Options.rbegin() ; optionIt != Options.rend() ; optionIt ++ )
170 if( (*optionIt)->Declaration->Element() == element )
171 return *optionIt;
172 return nullptr;
173}
174
175
177{
178 // loop over all arg indices in ArgsLeft
179 bool lastCommandFullyParsed= true;
180 while( lastCommandFullyParsed && ArgsLeft.size() > 0 )
181 {
182 // create a command object and search decl with actual argument
183 Command* command= allocator().New<Command>(this);
184 ALIB_ASSERT_ERROR( CommandDecls.size() > 0, "CLI", "No commands declared." )
185 for( auto* commandDecl : CommandDecls )
186 {
187 try
188 {
189 lastCommandFullyParsed= command->Read( *commandDecl );
190 }
191 catch ( Exception& e )
192 {
194 CLIUtil::GetCommandUsageFormat( *this, *commandDecl ),
195 commandDecl->HelpTextShort() );
196 throw;
197 }
198
199 if( command->ConsumedArguments > 0 )
200 {
201 CommandsParsed.push_back( command );
202 if( NextCommandIt == CommandsParsed.end() )
204 break;
205 }
206 }
207 }
208}
209
211{
212 if( NextCommandIt == CommandsParsed.end() )
214 if( NextCommandIt == CommandsParsed.end() )
215 {
216 // check for arguments left which got not recognized
217 if( ArgsLeft.size() > 0 )
219 ArgsLeft[0], PeekArg() );
220
221 // check for no command
222 if ( CommandsParsed.empty() )
224
225 return nullptr;
226 }
227
228 auto* result= *NextCommandIt;
230 return result;
231}
232
233
235{
236 if( ArgsLeft.size() == 0)
237 return NULL_STRING;
238
239 String result= GetArg(ArgsLeft[0]);
240 ArgsLeft.erase( ArgsLeft.begin() );
241 return result;
242}
243
245{
246 for( auto it= ArgsLeft.begin() ; it != ArgsLeft.end() ; ++it )
247 if( *it == argNo )
248 {
249 ArgsLeft.erase( it );
250 return;
251 }
252 ALIB_ERROR( "CLI", "Argument number {} already removed.", argNo )
253}
254
255
256
257} // namespace alib::cli
static ALIB_DLL AString GetCommandUsageFormat(CommandLine &cmdLine, CommandDecl &commandDecl)
Definition cliutil.cpp:65
virtual String PeekArg()
ALIB_DLL void RemoveArg(integer argNo)
List< MonoAllocator, Option * > Options
The options parsed in the order of their appearance.
virtual ALIB_DLL void ReadOptions()
virtual ALIB_DLL void ReadNextCommands()
List< MonoAllocator, String, Recycling::Shared > OptionArgsIgnored
ALIB_DLL Option * GetOption(Enum element)
List< MonoAllocator, OptionDecl * > OptionDecls
Possible Options.
MonoAllocator allocator
void Init(camp::Camp *resModule)
StdVectorMono< integer > ArgsLeft
List< MonoAllocator, CommandDecl * > CommandDecls
Commands defined.
NCString ResourceCategory
The resource category to fetch CLI resources within field Resources.
List< MonoAllocator, Command * > CommandsParsed
A list of commands actually parsed. Filled with method ReadNextCommands.
StdVectorMono< String > ArgStrings
List< MonoAllocator, Command * >::iterator NextCommandIt
The next command in CommandsParsed to be processed. Used with method NextCommand.
resources::ResourcePool * Resources
virtual ALIB_DLL String PopArg()
virtual ALIB_DLL Command * NextCommand()
virtual String GetArg(integer idx)
const String & ShortcutReplacementString()
Exception & Add(const lang::CallerInfo &ci, TEnum type, TArgs &&... args)
void DbgDisableBufferReplacementWarning()
Definition tastring.inl:245
TChar CharAtStart() const
Definition string.inl:440
constexpr bool IsNotEmpty() const
Definition string.inl:371
#define ALIB_CALLER_NULLED
Definition alib.inl:1010
#define ALIB_ERROR(domain,...)
Definition alib.inl:1045
#define ALIB_ASSERT_ERROR(cond, domain,...)
Definition alib.inl:1049
@ ParsingOptions
General option parse error. Adds option help text.
Definition clicamp.inl:59
@ ParsingCommand
General parameter parse error. Adds command help text.
Definition clicamp.inl:60
@ NoCommandGiven
Unknown command given.
Definition clicamp.inl:57
@ UnknownCommand
Unknown command given.
Definition clicamp.inl:58
constexpr String NULL_STRING
A nulled string of the default character type.
Definition string.inl:2463
const wchar_t ** ARG_VW
Definition mainargs.cpp:25
lang::integer integer
Type alias in namespace alib.
Definition integers.inl:149
NLocalString< 1024 > NString1K
Type alias name for TLocalString<nchar,1024>.
strings::TCString< nchar > NCString
Type alias in namespace alib.
Definition cstring.inl:512
boxing::Enum Enum
Type alias in namespace alib.
Definition enum.inl:211
LocalString< 1024 > String1K
Type alias name for TLocalString<character,1024>.
exceptions::Exception Exception
Type alias in namespace alib.
strings::TString< character > String
Type alias in namespace alib.
Definition string.inl:2381
const char ** ARG_VN
Definition mainargs.cpp:24
int ARG_C
Definition mainargs.cpp:23
A command of a ALib CLI command line.
ALIB_DLL bool Read(CommandDecl &decl)
OptionDecl * Declaration
The declaration struct.
ALIB_DLL bool Read(OptionDecl &decl, String &arg, const integer argNo)
Definition arguments.cpp:69
integer ConsumedArguments
Definition arguments.inl:35