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