ALib C++ Library
Library Version: 2402 R1
Documentation generated by doxygen
Loading...
Searching...
No Matches
commandline.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_COMMANDLINE)
12#endif
13
14#if !defined (HPP_ALIB_CLI_CLIUTIL)
15# include "alib/cli/cliutil.hpp"
16#endif
17
18#if !defined (HPP_ALIB_LANG_BASECAMP)
20#endif
21#endif // !defined(ALIB_DOX)
22
23
24namespace alib::cli {
25
26// #################################################################################################
27// CommandLine Constructor
28// #################################################################################################
29
30void CommandLine::Init( ResourcePool* resourcePool, NCString resCategory )
31{
32 Resources = resourcePool;
33 ResourceCategory= resCategory;
34
35 ArgStrings.reserve( static_cast<size_t>(ArgC) );
36 ArgsLeft .reserve( static_cast<size_t>(ArgC) );
37
39
40 #if !ALIB_CHARACTERS_WIDE
41 if( ArgVN )
42 {
43 for ( int i= 1; i < ArgC ; ++i )
44 {
45 ArgStrings.emplace_back( ArgVN[i] );
46 ArgsLeft .emplace_back( i -1 );
47 }
48 }
49 else
50 {
51 // convert wide to narrow strings
52 NString1K converter;
54
55 for ( int i= 1; i < ArgC ; ++i )
56 {
57 converter.Reset() << ArgVW[i];
58 ArgStrings.emplace_back( allocator.EmplaceString(converter) );
59 ArgsLeft .emplace_back( i - 1 );
60 }
61 }
62 #else
63 #if ALIB_CHARACTERS_NATIVE_WCHAR // use original strings only if alib::wchar == wchar_t
64 if( ArgVW )
65 {
66 for ( int i= 1; i < ArgC ; ++i )
67 {
68 ArgStrings.emplace_back( ArgVW[i] );
69 ArgsLeft .emplace_back( i - 1 );
70 }
71 }
72 else
73 #endif
74 {
75 // convert narrow to wide strings (or "wrong" wide width to width)
76 String1K converter;
78
79 for ( int i= 1; i < ArgC ; ++i )
80 {
81 converter.Reset() << ArgVN[i];
82 ArgStrings.emplace_back( allocator.EmplaceString(converter) );
83 ArgsLeft .emplace_back( i -1 );
84 }
85 }
86 #endif
88}
89
90// #################################################################################################
91// Interface
92// #################################################################################################
93
95{
96 // loop over all arg indices in ArgsLeft
97 integer argIdx= 0;
98 while( argIdx < static_cast<integer>(ArgsLeft.size()) )
99 {
100 // get arg number and string once
101 auto argNo= ArgsLeft[static_cast<size_t>(argIdx)];
102 String arg = GetArg(argNo);
103
104 SHORTCUT_JUMP:
105
106 // ignore non-option args
107 if( arg.CharAtStart() != '-' )
108 {
109 ++argIdx;
110 continue;
111 }
112
113 // create an option object and search decl with actual argument
114 {
115 Option* option= allocator.Emplace<Option>(this);
116
117 auto optionDeclIt= OptionDecls.begin();
118 try
119 {
120 while( optionDeclIt != OptionDecls.end() )
121 {
122 if( option->Read( **optionDeclIt, arg, argNo ) )
123 break;
124 ++optionDeclIt;
125 }
126 }
127 catch ( Exception& e )
128 {
130 (*optionDeclIt)->HelpUsageLine() );
131 throw;
132 }
133
134 // found a declaration?
135 if( option->QtyArgsConsumed > 0 )
136 {
137 // shortcut to another option?
138 OptionDecl& decl= *option->Declaration;
140 {
141 arg= decl.ShortcutReplacementString();
142 goto SHORTCUT_JUMP;
143 }
144
145 // delete args and continue
146 ArgsLeft.erase( ArgsLeft.begin() + argIdx,
147 ArgsLeft.begin() + argIdx + option->QtyArgsConsumed );
148
149 // move local option into the monotonic memory add to the list for this option type.
150 Options.PushBack( option );
151 continue;
152 }
153
154
155 // erase args that start with '-' and put them into field OptionsIgnored.
156 if( ArgsLeft.size() > 0 )
157 {
158 OptionArgsIgnored.PushBack( GetArg(argNo) );
159 ArgsLeft.erase( ArgsLeft.begin() + argIdx );
160 }
161 }
162 }
163}
164
166{
167 for( auto optionIt= Options.rbegin() ; optionIt != Options.rend() ; optionIt ++ )
168 if( (*optionIt)->Declaration->Element() == element )
169 return *optionIt;
170 return nullptr;
171}
172
173
175{
176 // loop over all arg indices in ArgsLeft
177 bool lastCommandFullyParsed= true;
178 while( lastCommandFullyParsed && ArgsLeft.size() > 0 )
179 {
180 // create a command object and search decl with actual argument
181 Command* command= allocator.Emplace<Command>(this);
182 ALIB_ASSERT_ERROR( CommandDecls.Size() > 0, "CLI", "No commands declared." )
183 for( auto* commandDecl : CommandDecls )
184 {
185 try
186 {
187 lastCommandFullyParsed= command->Read( *commandDecl );
188 }
189 catch ( Exception& e )
190 {
192 CLIUtil::GetCommandUsageFormat( *this, *commandDecl ),
193 commandDecl->HelpTextShort() );
194 throw;
195 }
196
197 if( command->QtyArgsConsumed > 0 )
198 {
199 CommandsParsed.PushBack( command );
200 if( NextCommandIt == CommandsParsed.end() )
202 break;
203 }
204 }
205 }
206}
207
209{
210 if( NextCommandIt == CommandsParsed.end() )
212 if( NextCommandIt == CommandsParsed.end() )
213 {
214 // check for arguments left which got not recognized
215 if( ArgsLeft.size() > 0 )
217 ArgsLeft[0], PeekArg() );
218
219 // check for no command
220 if ( CommandsParsed.IsEmpty() )
222
223 return nullptr;
224 }
225
226 auto* result= *NextCommandIt;
228 return result;
229}
230
231
233{
234 if( ArgsLeft.size() == 0)
235 return NullString();
236
237 String result= GetArg(ArgsLeft[0]);
238 ArgsLeft.erase( ArgsLeft.begin() );
239 return result;
240}
241
243{
244 for( auto it= ArgsLeft.begin() ; it != ArgsLeft.end() ; ++it )
245 if( *it == argNo )
246 {
247 ArgsLeft.erase( it );
248 return;
249 }
250 ALIB_ERROR( "CLI", "Argument number {} already removed.", argNo )
251}
252
253
254
255} // namespace alib::cli
static ALIB_API AString GetCommandUsageFormat(CommandLine &cmdLine, CommandDecl &commandDecl)
Definition cliutil.cpp:62
lang::resources::ResourcePool * Resources
List< OptionDecl * > OptionDecls
void Init(lang::Camp *resModule)
virtual ALIB_API Command * NextCommand()
List< Command * >::Iterator NextCommandIt
virtual String GetArg(integer idx)
List< Command * > CommandsParsed
MonoAllocator allocator
virtual String PeekArg()
List< Option * > Options
virtual ALIB_API void ReadOptions()
std::vector< String, StdContMA< String > > ArgStrings
virtual ALIB_API String PopArg()
ALIB_API void RemoveArg(integer argNo)
ALIB_API Option * GetOption(Enum element)
virtual ALIB_API void ReadNextCommands()
List< String, Recycling::Shared > OptionArgsIgnored
List< CommandDecl * > CommandDecls
std::vector< integer, StdContMA< integer > > ArgsLeft
const String & ShortcutReplacementString()
Exception & Add(const NCString &file, int line, const NCString &func, TEnum type, TArgs &&... args)
ALIB_FORCE_INLINE T * Emplace(TArgs &&... args)
strings::TString< TChar > EmplaceString(const strings::TString< TChar > &src)
void DbgDisableBufferReplacementWarning()
Definition astring.hpp:353
constexpr bool IsNotEmpty() const
Definition string.hpp:420
#define ALIB_CALLER_NULLED
Definition alib.hpp:846
#define ALIB_WARNINGS_RESTORE
Definition alib.hpp:715
#define ALIB_ERROR(...)
Definition alib.hpp:980
#define ALIB_ASSERT_ERROR(cond,...)
Definition alib.hpp:984
#define ALIB_WARNINGS_ALLOW_UNSAFE_BUFFER_USAGE
Definition alib.hpp:644
@ ParsingOptions
General option parse error. Adds option help text.
@ ParsingCommand
General parameter parse error. Adds command help text.
@ NoCommandGiven
Unknown command given.
@ UnknownCommand
Unknown command given.
const char ** ArgVN
Definition alib.cpp:60
lang::Exception Exception
Type alias in namespace alib.
int ArgC
Definition alib.cpp:59
constexpr String NullString()
Definition string.hpp:2498
const wchar_t ** ArgVW
Definition alib.cpp:61
lang::integer integer
Type alias in namespace alib.
Definition integers.hpp:286
ALIB_API bool Read(CommandDecl &decl)
OptionDecl * Declaration
ALIB_API bool Read(OptionDecl &decl, String &arg, const integer argNo)
Definition arguments.cpp:69
integer QtyArgsConsumed
Definition arguments.hpp:50