ALib C++ Library
Library Version: 2510 R0
Documentation generated by doxygen
Loading...
Searching...
No Matches
sample.cpp
1// #################################################################################################
2// ALib C++ Library
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#include "ALib.Lang.H"
9#if !DOXYGEN // otherwise this sample would be seen in the ALib dox
10
11DOX_MARKER( [DOX_EXPR_TUT_CLI_INCLUDES])
12// Include necessary ALib CLI headers
13#include "ALib.Strings.StdIOStream.H" // Support to write ALib strings and boxes to cout
14#include "ALib.Boxing.StdFunctors.H" // Allow class boxing::Enum be key of Hashtables
15#include "ALib.CLI.H"
16#include "ALib.Camp.Base.H"
17#include "ALib.Camp.H" // Support customized module bootstrapping
18#include "ALib.EnumRecords.Bootstrap.H" // Support for bootstrapping resourced enum records
19#include "ALib.Lang.H" // ALib date/time types
20#include "ALib.Strings.Calendar.H" // ALib calendar formatting
21#include "ALib.Bootstrap.H" // Bootstrapping ALib
22#include <filesystem> // C++ filesystem
23#include <chrono> // C++ chrono
24
26// namespaces to use locally
27using namespace alib;
28using namespace alib::cli;
29DOX_MARKER( [DOX_EXPR_TUT_CLI_INCLUDES])
30
31DOX_MARKER( [DOX_EXPR_TUT_CLI_ENUMS])
32// #################################################################################################
33// Enumerations of Commands, Parameters, Options and ExitCodes of the CLI application
34// #################################################################################################
35enum class Commands
36{
37 Now = 1, ///< Returns the current date.
38 File = 2, ///< returns the modification date of a file or directory.
39 Help = 99, ///< Prints a help text.
40};
41
42enum class Options
43{
44 Format = 0, ///< Overwrite the default format string.
45 Help = 99, ///< Show help text. (We allow this as option as well a command)
46};
47
48enum class Parameters
49{
50 Filename = 0, ///< Used with command \e file to denote the file.
51 Topic = 1, ///< Used with command \e help to optionally denote a help topic.
52};
53
54enum class ExitCodes
55{
56 OK = 0, ///< Success.
57 ErrUnknownCommand = 100, ///< Unkown command given.
58 ErrUnknownOption = 101, ///< Unkown option given.
59 ErrMissingFilename = 102, ///< Command "file" given without a filename.
60 ErrUnknownHelpTopic = 103, ///< Command or option "help" given without an unknown subtopic.
61 ErrInternalError = 255, ///< Unspecified internal error.
62 /// (this demo might be incomplete :-)
63};
64DOX_MARKER( [DOX_EXPR_TUT_CLI_ENUMS])
65
66DOX_MARKER( [DOX_EXPR_TUT_CLI_ENUMS_ASSIGN])
67// assigning ALib enum records
72DOX_MARKER( [DOX_EXPR_TUT_CLI_ENUMS_ASSIGN])
73
74DOX_MARKER( [DOX_EXPR_TUT_CLI_CUSTOM_CAMP])
75// #################################################################################################
76// The custom ALib module, needed to define externalized resources.
77// #################################################################################################
78class SampleCamp : public camp::Camp
79{
80 public:
81 // Constructor. Passes version number and resource name to the module class
82 SampleCamp()
83 : Camp( "DATEMOD" )
84 {}
85
86 protected:
87 // Initialization of the module.
88 virtual void Bootstrap() override
89 {
90 if( GetBootstrapState() == BootstrapPhases::PrepareResources) {
91 // Add bulk !
92 resourcePool->BootstrapBulk( ResourceCategory,
93 #define EOS ,
94
95 // ################################### Single Strings ######################################
96 "AppInfo", A_CHAR( "@HL-"
97 "Command line tool 'date'. V. {}.{} (in fact a sample application only)\n"
98 "(c) 2023-{} AWorx GmbH. Published under MIT License (Open Source).\n"
99 "For more information, see: https://alib.dev\n"
100 "@HL-"),
101
102 // ######################################## Commands ######################################
103 "Commands", A_CHAR(
104 //enum ident minread Params
105 "1," "now" ",1" "," ","
106 "2," "file" ",1" ",filename" ","
107 "99," "help" ",1" ",topic" ) EOS
108
109 "Commands<", A_CHAR("datesample::Commands::"),
110
111 "THlpCmdSht_now", A_CHAR("Reports the actual date/time"),
112 "THlpCmdLng_now", A_CHAR("Reports the actual date/time. May be omitted, as this is the\n"
113 "default if no command is given.") EOS
114
115 "THlpCmdSht_file", A_CHAR("Returns the date/time of a file. "),
116 "THlpCmdLng_file", A_CHAR("Returns the last modification date/time of a file.") EOS
117
118 "THlpCmdSht_help", A_CHAR("Displays usage information. "),
119 "THlpCmdLng_help", A_CHAR("Displays usage information. Can also be given as an "
120 "option '--help'.") EOS
121
122
123 // ######################################## Options ######################################
124 "Options", A_CHAR(
125 //enum ident minread identChar in-arg-separ. args to consume ShortcutTo
126 "0," "format" ",1," "f," "=" ",1," ","
127 "99," "help" ",1," "h," "=" ",0," ) EOS
128
129 "Options<", A_CHAR("datesample::Options::"),
130
131 "TOptUsg_format", A_CHAR("--format[=]\"placholders\""),
132 "TOptHlp_format", A_CHAR("Sets the output format. The format specification is given with\n"
133 "documentation of ALib method CalendarDateTime::Format, found here:\n"
134 "https://alib.dev/classalib_1_1strings_1_1util_1_1CalendarDateTime.html" ) ,
135 "TOptUsg_help" , A_CHAR("--help[[=]TOPIC]"),
136 "TOptHlp_help" , A_CHAR("Displays usage information.")
137 EOS
138
139 // ######################################## Parameters ######################################
140 "Parameters", A_CHAR(
141 //enum name minIdentLen identifier in-arg-sep delim args to consume isOptional
142 // (if empty -> mandatory!)
143 "0," "FILENAME" ",1," "" "," "=" "," ",-1" ",0" ","
144 "1," "TOPIC" ",1," "" "," "=" "," ",-1" ",1" ) EOS
145
146 "Parameters<", A_CHAR("datesample::Parameters::"),
147 "THlpParSht_FILENAME", A_CHAR("Mandatory parameter of command 'file."),
148 "THlpParLng_FILENAME", A_CHAR("Denotes the file that is used for retrieving the modification date.\n"
149 "This parameter is mandatory to command file and has to be appended\n"
150 "to this command, separated by '='"),
151 "THlpParSht_TOPIC" , A_CHAR("Optional parameter of command (or option) 'help'."),
152 "THlpParLng_TOPIC" , A_CHAR("Denotes a specific toopic that the help command should be verbose about.")
153 EOS
154
155 // ######################################## ExitCodes ######################################
156 "ExitCodes", A_CHAR(
157 //enum name assoc. cli exception
158 "0," "OK" ",-1" ","
159 "100," "ErrUnknownCommand" ",-1" ","
160 "101," "ErrUnknownOption" ",-1" ","
161 "102," "ErrMissingFilename" ",-1" ","
162 "103," "ErrUnknownHelpTopic" ",-1" ","
163 "255," "ErrInternalError" ",-1" ) EOS
164
165 "ExitCodes<", A_CHAR("datesample::"),
166
167 "TExit0" , A_CHAR("Success (no error).")
168 ,"TExit100" , A_CHAR("An unknown command was given. Valid commands are 'now' and 'file'")
169 ,"TExit101" , A_CHAR("An unknown option was given. The only valid option is '--format='FORMATSPEC'.")
170 ,"TExit102" , A_CHAR("Command 'file' given without a filename argument.")
171 ,"TExit103" , A_CHAR("Command or option 'help' given without an unknown subtopic.")
172 ,"TExit255" , A_CHAR("Unspecified internal error.")
173 EOS
174
175 // ################################### Help Texts ######################################
176 "HlpCLIAppName", A_CHAR("date"),
177 "HlpUsage" , A_CHAR("date [format=\"FORMATSPEC\" [now]|[file FILENAME]"),
178 "HlpHdlOpts" , A_CHAR("OPTIONS:" ),
179 "HlpHdlCmds" , A_CHAR("COMMANDS:" ),
180 "HlpHdlExtCds" , A_CHAR("EXIT CODES:" ),
181 "HlpHdlUsage" , A_CHAR("USAGE:" ),
182 "HlpHdlDscr" , A_CHAR( "DESCRIPTION:" ),
183 "HlpHdlPDscr" , A_CHAR("PARAMETER DESCRIPTION:" ),
184 "HlpHdlTopic" , A_CHAR("Help on {} {!Q<>}:\n" ),
185
186 "HlpGeneral", A_CHAR(
187 "\nABOUT date\n"
188 "@>>"
189 "This is a sample application provided with C++ library 'ALib'\n"
190 "to demonstrate the use of its module \"ALib CLI\"."
191 "\n@<<\n" )
192 EOS
193
194 // end of AddBulk()
195 nullptr );
196 }
197
198 else if( GetBootstrapState() == BootstrapPhases::PrepareConfig )
199 {
200 enumrecords::bootstrap::Bootstrap<Commands >();
201 enumrecords::bootstrap::Bootstrap<Parameters >();
202 enumrecords::bootstrap::Bootstrap<Options >();
203 enumrecords::bootstrap::Bootstrap<ExitCodes >();
204 }
205 }
206
207 // Termination this module. (Nothing to do.)
208 virtual void Shutdown( ShutdownPhases phase ) override
209 { (void) phase; }
210
211}; // class SampleCamp
212DOX_MARKER( [DOX_EXPR_TUT_CLI_CUSTOM_CAMP])
213
214DOX_MARKER( [DOX_EXPR_TUT_CLI_CUSTOM_CAMP_SINGLETON])
215// The module singleton object
216extern SampleCamp SAMPLE_CAMP;
217SampleCamp SAMPLE_CAMP;
218DOX_MARKER( [DOX_EXPR_TUT_CLI_CUSTOM_CAMP_SINGLETON])
219
220DOX_MARKER( [DOX_EXPR_TUT_CLI_ENUMS_ASSIGN2])
221// Specifying our custom module to hold resources of our enum records
222ALIB_RESOURCED_IN_MODULE( Commands , SAMPLE_CAMP, "Commands" )
223ALIB_RESOURCED_IN_MODULE( Parameters, SAMPLE_CAMP, "Parameters" )
224ALIB_RESOURCED_IN_MODULE( Options , SAMPLE_CAMP, "Options" )
225ALIB_RESOURCED_IN_MODULE( ExitCodes , SAMPLE_CAMP, "ExitCodes" )
226DOX_MARKER( [DOX_EXPR_TUT_CLI_ENUMS_ASSIGN2])
227
228DOX_MARKER( [DOX_EXPR_TUT_CLI_ENUMS_FWDDECL])
229// forward declaration
230ExitCodes processCLI( CommandLine& cli );
231DOX_MARKER( [DOX_EXPR_TUT_CLI_ENUMS_FWDDECL])
232
233DOX_MARKER( [DOX_EXPR_TUT_CLI_ENUMS_MAIN])
234// #################################################################################################
235// The main() function of the CLI application
236// #################################################################################################
237
238// switch the macro ALIB_CALLER to not use "this" (because we have a global function here)
239#include "ALib.Lang.CIFunctions.H"
240
241int main( int argc, const char **argv )
242{
243 alib::ARG_C = argc;
244 alib::ARG_VN = argv;
245
246 // 1. Add our custom module to the list of modules
248 alib::CAMPS.push_back( &SAMPLE_CAMP );
249
250 // 2. Initialize all modules
252
253 // 3. now we start catching exceptions
254 Enum result= ExitCodes::ErrInternalError;
255 try
256 {
257 // 4. Create the central command line interface object app and perform
258 // mandatory initializations.
260 {
261 // Read copyright string from resources and format to current version and year
262 Paragraphs buffer;
263 buffer.LineWidth= 70;
265 buffer.AddMarked( SAMPLE_CAMP.GetResource( "AppInfo" ),
268 CalendarDateTime(DateTime()).Year );
269 }
270 cli.AppInfo.Allocate(cli.GetAllocator(), buffer.Buffer);
271
272 // Initialize the CLI with the module to fetch the resources from.
273 cli.Init( &SAMPLE_CAMP );
274
275 // Read enum records from resources and build up corresponding object lists.
276 cli.DefineParameters<enum Parameters>();
277 cli.DefineCommands <enum Commands >();
278 cli.DefineOptions <enum Options >();
279 cli.DefineExitCodes <enum ExitCodes >();
280
281 // Read options from the command line
282 cli.ReadOptions();
283 }
284
285 // 5. check for unprocess options (not allowed with this demo. Other application might pass
286 // those to other libraries or parts of the software, which provide their own option
287 // processing.
288 if( cli.OptionArgsIgnored.size() )
289 {
290 result= ExitCodes::ErrUnknownOption;
291 std::cerr << "Error: Unknown option given \""
292 << cli.OptionArgsIgnored.front()
293 << "\"" << std::endl;
294 goto END;
295 }
296
297 // 6. Now, the truly custom part: Process commands and options
298 result= processCLI( cli );
299 }
300
301 // fetch exceptions and assign a corresponding exit code (error code)
302 catch( Exception& e)
304 std::cerr << e.Format() << std::endl; // print out human-readable exception information
305 result= e.Back().Type; // For this demo, just return the internal exception
306 // number as "exit code".
307 }
308 catch(std::runtime_error& e)
309 {
310 result= ExitCodes::ErrInternalError;
311 std::cerr << "A runtime error occurred: " << e.what()<< std::endl;
312 }
313
314 // 7. That's it.
315 END:
317 return int(result.Integral());
318}
319DOX_MARKER( [DOX_EXPR_TUT_CLI_ENUMS_MAIN])
320
321
322DOX_MARKER( [DOX_EXPR_TUT_CLI_ENUMS_PROCESS])
323// #################################################################################################
324// The custom function to process CLI params
325// #################################################################################################
326ExitCodes processCLI( CommandLine& cli )
327{
328 AString format; // The date output format
329 Paragraphs helpText; // A buffer for help texts
330 DateTime dt; // The timestamp to output
331
332 format << "yyyy-MM-dd HH:mm:ss";
333
334 //------- check for option 'format' -------
335 Option* option= cli.GetOption( Options::Format);
336 if( option )
337 {
338 format.Reset( option->Args.front() );
339 }
340
341 //------- check for option 'help' -------
342 option= cli.GetOption( Options::Help);
343 if( option )
344 {
345 if( !CLIUtil::GetHelp( cli, nullptr, option, helpText ) )
346 {
347 std::cerr << "Error: Unknown help Topic \""
348 << (option->Args.size() > 0 ? option->Args.front() : String() )
349 << "\"" << std::endl
350 << "Usage Information follows: " << std::endl << std::endl;
351 option->Args.Clear();
352 helpText.Clear();
353 CLIUtil::GetHelp( cli, nullptr, option, helpText );
354 }
355 std::cout << helpText.Buffer << std::endl;
356 return ExitCodes::OK;
357 }
358
359 //------- No command recognized? This is allowed, assuming now -------
360 cli.ReadNextCommands();
361 if( cli.CommandsParsed.size() == 0 )
362 {
363 // Still a command was given? This is not allowed
364 if( cli.ArgsLeft.size() > 0 )
365 {
366 std::cerr << "Error: Unknown command given \""
367 << cli.ArgStrings.at(std::size_t(*cli.ArgsLeft.begin()))
368 << "\"" << std::endl;
369 return ExitCodes::ErrUnknownCommand;
370 }
371
372 // No command, results in command "now"
374 AString printBuffer;
375 calendar.Format( format, printBuffer, lang::CurrentData::Clear );
376 std::cout << printBuffer << std::endl;
377
378 return ExitCodes::OK;
379 }
380
381 //------- Command loop -------
382 // Note: Making a loop here is optional. We do it to allow multiple commands
383 // with one invokation of the application.
384 Command* actCmd;
385 while ( (actCmd= cli.NextCommand()) != nullptr )
386 {
387 auto actCmdCode= actCmd->Declaration->Element();
388
389 if ( actCmdCode == Commands::Now )
390 {
391 dt= DateTime();
392 }
393
394 else if ( actCmdCode == Commands::File )
395 {
396 // check if filename was given as paraemter
397 if(actCmd->ParametersMandatory.size() < 1)
398 {
399 std::cerr << "Error: no filename given with command 'file'" << std::endl;
400 std::cerr << "Usage: " << CLIUtil::GetCommandUsageFormat(cli, *actCmd->Declaration )
401 << std::endl;
402 return ExitCodes::ErrMissingFilename;
403 }
404
405 // get file (or directory) modification date
406 String4K name( actCmd->ParametersMandatory.front()->Args.front() );
407 std::filesystem::path path( name.Terminate() );
408 dt.Import( std::chrono::clock_cast<std::chrono::system_clock>(
409 std::filesystem::last_write_time( path ) ) ) ;
410 }
411
412 else if ( actCmdCode == Commands::Help )
413 {
414 if( !CLIUtil::GetHelp( cli, actCmd, nullptr, helpText ) )
415 {
416 std::cerr << "Error: Unknown help topic" << std::endl;
417 std::cerr << "Usage: " << CLIUtil::GetCommandUsageFormat(cli, *actCmd->Declaration )
418 << std::endl;
419 return ExitCodes::ErrUnknownHelpTopic;
420 }
421 std::cout << helpText.Buffer << std::endl;
422 continue;
423 }
424
425
426 // execute printing of commands "now" and "file"
428 AString printBuffer;
429 calendar.Format( format, printBuffer, lang::CurrentData::Clear );
430 std::cout << printBuffer << std::endl;
431 }
432 return ExitCodes::OK;
433}
434DOX_MARKER( [DOX_EXPR_TUT_CLI_ENUMS_PROCESS])
435
436#endif // !DOXYGEN
static ALIB_DLL bool GetHelp(CommandLine &cmdLine, Command *helpCmd, Option *helpOpt, Paragraphs &text)
Definition cliutil.cpp:89
static ALIB_DLL AString GetCommandUsageFormat(CommandLine &cmdLine, CommandDecl &commandDecl)
Definition cliutil.cpp:65
const Enum & Element() const
ALIB_DLL AString & Format(AString &target) const
ALIB_DLL Message & Back() const
static ALIB_DLL threads::RecursiveLock DefaultLock
void AddMarked(boxing::TBoxes< TAllocatorArgs > &args)
integer LineWidth
Used as parameter lineWidth of static method invocations.
ALIB_DLL Paragraphs & Clear()
ALIB_DLL AString & Format(Substring format, AString &target, lang::CurrentData targetData=lang::CurrentData::Keep) const
Definition calendar.cpp:319
void Import(TTimePoint timePoint)
#define A_CHAR(STR)
#define ALIB_ENUMS_ASSIGN_RECORD(TEnum, TRecord)
#define ALIB_LOCK_RECURSIVE_WITH(lock)
Definition alib.inl:1323
#define ALIB_RESOURCED_IN_MODULE(T, Camp, ResName)
@ Clear
Chooses to clear existing data.
@ Filename
Denotes the actual source file as the scope.
files::File File
Type alias in namespace alib.
Definition ftree.inl:1036
strings::TAString< character, lang::HeapAllocator > AString
Type alias in namespace alib.
unsigned char REVISION
LocalString< 4096 > String4K
Type alias name for TLocalString<character,4096>.
time::DateTime DateTime
Type alias in namespace alib.
Definition datetime.inl:224
void Shutdown(ShutdownPhases targetPhase, camp::Camp *targetCamp)
void BootstrapAddDefaultCamps()
format::Paragraphs Paragraphs
Type alias in namespace alib.
void Bootstrap(BootstrapPhases targetPhase, camp::Camp *targetCamp, int alibVersion, int alibRevision, TCompilationFlags compilationFlags)
int VERSION
strings::util::CalendarDateTime CalendarDateTime
Type alias in namespace alib.
Definition calendar.inl:647
boxing::Enum Enum
Type alias in namespace alib.
Definition enum.inl:211
exceptions::Exception Exception
Type alias in namespace alib.
strings::TString< character > String
Type alias in namespace alib.
Definition string.inl:2381
ALIB_DLL void Shutdown()
ALIB_DLL List< MonoAllocator, camp::Camp * > CAMPS
const char ** ARG_VN
Definition mainargs.cpp:24
cli::CommandLine CommandLine
Type alias in namespace alib.
int ARG_C
Definition mainargs.cpp:23
integer Integral() const
Definition enum.inl:87
A command of a ALib CLI command line.
CommandDecl * Declaration
The underlying declaration.
List< MonoAllocator, Parameter *, Recycling::Shared > ParametersMandatory
Mandatory parameters parsed.
ALib Enum Record type used by class CommandDecl.
ALib Enum Record type used by class OptionDecl.
ALib Enum Record type used by class ParameterDecl.
Definition arguments.inl:54
List< MonoAllocator, String, Recycling::Shared > Args
Arguments belonging to this option.