ALib C++ Framework
by
Library Version: 2511 R0
Documentation generated by doxygen
Loading...
Searching...
No Matches
CLI/sample.cpp
Go to the documentation of this file.
1// #################################################################################################
2// ALib C++ Framework
3// Configuration Sample
4//
5// Copyright 2025 A-Worx GmbH, Germany
6// Published under Boost Software License (a free software license, see LICENSE.txt)
7// #################################################################################################
8/// \file
9#include "ALib.Lang.H"
10#if !DOXYGEN // otherwise this sample would be seen in the ALib dox
11
12#include "samplecamp.hpp"
13
14// Include necessary ALib headers
15#include "ALib.Strings.StdIOStream.H" // Support to write ALib strings and boxes to cout
16#include "ALib.Boxing.StdFunctors.H" // Allow class boxing::Enum be key of Hashtables
17#include "ALib.Strings.Calendar.H" // ALib calendar formatting
18#include "ALib.Bootstrap.H" // Bootstrapping ALib
19
20#include <filesystem> // C++ filesystem
21#include <chrono> // C++ chrono
22
23// namespaces to use locally
24using namespace alib;
25
26DOX_MARKER( [DOX_EXPR_TUT_CLI_FWDDECL])
27// forward declaration
28ExitCodes processCLI( CommandLine& cli );
29DOX_MARKER( [DOX_EXPR_TUT_CLI_FWDDECL])
30
31// switch the macro ALIB_CALLER to not use "this" (because we have a global function here)
32#include "ALib.Lang.CIFunctions.H"
33
34DOX_MARKER( [DOX_EXPR_TUT_CLI_MAIN])
35int main( int argc, const char **argv )
36{
37 alib::ARG_C = argc;
38 alib::ARG_VN = argv;
39
40 // 1. Add our custom module to the list of modules
42 alib::CAMPS.push_back( &SAMPLE_CAMP );
43
44 // 2. Initialize all modules
46
47 // 3. now we start catching exceptions
48 Enum result= ExitCodes::ErrInternalError;
49 try
50 {
51 // 4. Create the central command-line interface object app and perform
52 // mandatory initializations.
54 {
55 // Read copyright string from resources and format to current version and year
56 Paragraphs buffer;
57 buffer.LineWidth= 70;
59 buffer.AddMarked( SAMPLE_CAMP.GetResource( "AppInfo" ),
62 CalendarDateTime(DateTime()).Year );
63 }
64 cli.AppInfo.Allocate(cli.GetAllocator(), buffer.Buffer);
65
66 // Initialize the CLI with the module to fetch the resources from.
67 cli.Init( &SAMPLE_CAMP );
68
69 // Read enum records from resources and build up corresponding object lists.
70 cli.DefineParameters<enum Parameters>();
71 cli.DefineCommands <enum Commands >();
72 cli.DefineOptions <enum Options >();
73 cli.DefineExitCodes <enum ExitCodes >();
74
75 // Read options from the command-line
76 cli.ReadOptions();
77 }
78
79 // 5. check for unprocess options (not allowed with this demo. Other application might pass
80 // those to other libraries or parts of the software, which provide their own option
81 // processing.
82 if( cli.OptionArgsIgnored.size() )
83 {
84 result= ExitCodes::ErrUnknownOption;
85 std::cerr << "Error: Unknown option given \""
86 << cli.OptionArgsIgnored.front()
87 << "\"" << std::endl;
88 goto END;
89 }
90
91 // 6. Now, the truly custom part: Process commands and options
92 result= processCLI( cli );
93 }
94
95 // fetch exceptions and assign a corresponding exit-code (error code)
96 catch( Exception& e)
98 std::cerr << e.Format() << std::endl; // print out human-readable exception information
99 result= e.Back().Type; // For this demo, just return the internal exception
100 // number as "exit-code".
101 }
102 catch(std::runtime_error& e)
103 {
104 result= ExitCodes::ErrInternalError;
105 std::cerr << "A runtime error occurred: " << e.what()<< std::endl;
106 }
107
108 // 7. That's it.
109 END:
111 return int(result.Integral());
112}
113DOX_MARKER( [DOX_EXPR_TUT_CLI_MAIN])
114
115
116
117DOX_MARKER( [DOX_EXPR_TUT_CLI_PROCESS])
118ExitCodes processCLI( CommandLine& cli )
119{
120 String64 format; // The date output format
121 Paragraphs helpText; // A buffer for help texts
122 DateTime dt; // The timestamp to output
123
124 format << "yyyy-MM-dd HH:mm:ss";
125
126 //------- check for option 'format' -------
127 cli::Option* option= cli.GetOption( Options::Format);
128 if( option )
129 {
130 format.Reset( option->Args.front() );
131 }
132
133 //------- check for option 'help' -------
134 option= cli.GetOption( Options::Help);
135 if( option )
136 {
137 if( !CLIUtil::GetHelp( cli, option, helpText ) )
138 {
139 std::cerr << "Error: Unknown help Topic \""
140 << (option->Args.size() > 0 ? option->Args.front() : String() )
141 << "\"" << std::endl
142 << "Usage Information follows: " << std::endl << std::endl;
143 option->Args.Clear();
144 helpText.Clear();
145 CLIUtil::GetHelp( cli, option, helpText );
146 }
147 std::cout << helpText.Buffer << std::endl;
148 return ExitCodes::OK;
149 }
150
151 //------- No command recognized? This is allowed, assuming now -------
152 cli.ReadNextCommands();
153 if( cli.CommandsParsed.size() == 0 )
154 {
155 // Still a command was given? This is not allowed
156 if( cli.ArgsLeft.size() > 0 )
157 {
158 std::cerr << "Error: Unknown command given \""
159 << cli.ArgStrings.at(std::size_t(*cli.ArgsLeft.begin()))
160 << "\"" << std::endl;
161 return ExitCodes::ErrUnknownCommand; w
162 }
163
164 // No command, results in command "now"
166 AString printBuffer;
167 calendar.Format( format, printBuffer, lang::CurrentData::Keep );
168 std::cout << printBuffer << std::endl;
169
170 return ExitCodes::OK;
171 }
172
173 //------- Command loop -------
174 // Note: Making a loop here is optional. We do it to allow multiple commands
175 // with one invocation of the application.
176 cli::Command* actCmd;
177 while ( (actCmd= cli.NextCommand()) != nullptr )
178 {
179 auto actCmdCode= actCmd->Declaration->Element();
180
181 if ( actCmdCode == Commands::Now )
182 {
183 dt= DateTime();
184 }
185
186 else if ( actCmdCode == Commands::File )
187 {
188 // check if filename was given as paraemter
189 if(actCmd->ParametersMandatory.size() < 1)
190 {
191 std::cerr << "Error: no filename given with command 'file'" << std::endl;
192 std::cerr << "Usage: " << CLIUtil::GetCommandUsageFormat(cli, *actCmd->Declaration )
193 << std::endl;
194 return ExitCodes::ErrMissingFilename;
195 }
196
197 // get file (or directory) modification date
198 String4K name( actCmd->ParametersMandatory.front()->Args.front() );
199 std::filesystem::path path( name.Terminate() );
200 dt.Import( std::chrono::clock_cast<std::chrono::system_clock>(
201 std::filesystem::last_write_time( path ) ) ) ;
202 }
203
204 else if ( actCmdCode == Commands::Help ) {
205 if( !CLIUtil::GetHelp( cli, actCmd, helpText ) ) {
206 std::cerr << "Error: Unknown help topic" << std::endl;
207 std::cerr << "Usage: " << CLIUtil::GetCommandUsageFormat(cli, *actCmd->Declaration )
208 << std::endl;
209 return ExitCodes::ErrUnknownHelpTopic;
210 }
211 std::cout << helpText.Buffer << std::endl;
212 continue;
213 }
214
215 // execute printing of commands "now" and "file"
217 AString printBuffer;
218 calendar.Format( format, printBuffer, lang::CurrentData::Keep );
219 std::cout << printBuffer << std::endl;
220 }
221 return ExitCodes::OK;
222}
223DOX_MARKER( [DOX_EXPR_TUT_CLI_PROCESS])
224
225
226
227#endif // !DOXYGEN
#define ALIB_LOCK_RECURSIVE_WITH(lock)
Definition alib.inl:1414
static bool GetHelp(CommandLine &cmdLine, const String &topics, Paragraphs &text)
Definition cliutil.cpp:110
static AString GetCommandUsageFormat(CommandLine &cmdLine, CommandDecl &commandDecl)
Definition cliutil.cpp:62
const Enum & Element() const
AString & Format(AString &target) const
static threads::RecursiveLock DEFAULT_LOCK
void AddMarked(boxing::TBoxes< TAllocatorArgs > &args)
integer LineWidth
Used as parameter lineWidth of static method invocations.
AString & Format(Substring format, AString &target, lang::CurrentData targetData=lang::CurrentData::Keep) const
Definition calendar.cpp:293
void Import(TTimePoint timePoint)
Options
Built-in options used with class #"AppCli".
ExitCodes
Built-in exit-code used with class #"AppCli".
Commands
Built-in commands used with class #"AppCli".
Parameters
Built-in parameters of commands and options used with class #"AppCli".
@ Keep
Chooses not no clear existing data.
ListMA< camp::Camp * > CAMPS
void BootstrapAddDefaultCamps()
void Bootstrap(BootstrapPhases targetPhase, camp::Camp *targetCamp, int alibVersion, int alibRevision, TCompilationFlags compilationFlags)
LocalString< 64 > String64
Type alias name for #"TLocalString;TLocalString<character,64>".
cli::CommandLine CommandLine
Type alias in namespace alib.
LocalString< 4096 > String4K
Type alias name for #"TLocalString;TLocalString<character,4096>".
int VERSION
strings::TString< character > String
Type alias in namespace alib.
Definition string.inl:2172
exceptions::Exception Exception
Type alias in namespace alib.
strings::util::CalendarDateTime CalendarDateTime
Type alias in namespace alib.
Definition calendar.inl:512
void Shutdown()
strings::TAString< character, lang::HeapAllocator > AString
Type alias in namespace alib.
format::Paragraphs Paragraphs
Type alias in namespace alib.
int ARG_C
Definition mainargs.cpp:23
const char ** ARG_VN
Definition mainargs.cpp:24
time::DateTime DateTime
Type alias in namespace alib.
Definition datetime.inl:185
boxing::Enum Enum
Type alias in namespace alib.
Definition enum.inl:211
unsigned char REVISION
TIntegral Integral() const
Definition enum.inl:88
A command of a ALib CLI command-line.
CommandDecl * Declaration
The underlying declaration.
ListMA< Parameter *, Recycling::Shared > ParametersMandatory
Mandatory parameters parsed.
ListMA< String, Recycling::Shared > Args
Arguments belonging to this option.