While not GNSS-related, the gnsstk provides a set of frameworks to reduce the amount of effort required when writing applications.
The classes used for quickly implementing applications are:
Using the application frameworks is pretty consistent across all applications (which of course is the intent). An application will define a class that derives from one of the frameworks, and overrides the methods of the framework class that are appropriate for the application. The implementation of the main function is very similar from application to application, with only the application class name changing, in general.
The structure of applications using these frameworks follows the following formula:
When you need to implement an application that performs a single task before exiting (timeconvert is a good example of this), BasicFramework is probably the ideal framework class for you to use.
The flow of execution for applications derived from the BasicFramework class is as follows (indentation levels indicate the call stack):
The functions/methods of an application class perform functions as follows:
Why are there so many methods defined? The main reason is to allow further differentiation when specializing frameworks. That is, there are derived classes that provide further frameworks capabilities where initialization must occur in a very specific order, but the subclasses need to be able to override specific behaviors.
The BasicFramework class defines a data member named exitCode. This is intended to be used as the return value for main() (see the example in Overview). It is initialized to 0, which indicates successful completion of applications. Any non-zero return from main will be interpreted by the shell as a failed execution. While BasicFramework will set exitCode to an error code for exceptions caught within run() or command-line processing errors within initialize(), implementers should remember two things:
The following generic exit codes are defined within BasicFramework:
Other exit codes can be defined as needed on a per-application basis.
LoopedFramework is identical to BasicFramework with the following exceptions:
LoopedFramework is meant to be used when executing a set of statements repeatedly. Derived classes should set timeToDie to true whenever an appropriate termination condition has been met.
Command-line option processing used by the application frameworks involves the instantiation of objects derived from the CommandOption class. Usually this is done inside the application class constructor, however there may be occassions where the command option object is instantiated dynamically based on some conditional (typically only done in other frameworks). The CommandOption class and children do not have a default constructor, which is the primary reason for instantiating these objects in the application constructor.
The CommandOption classes in most cases will let you specify a short command-line option (e.g. 'h' becomes -h on the command line), a long command-line option (e.g. "help" becomes –help on the command line), a description of the command line option to be printed when help is requested, and a flag indicating whether the command-line argument is required or not. The CommandOption class has several other constructor parameters but using that class directly rather than one of the child classes is pretty much unheard of.
Really basic command-line option classes that are never directly used:
Command-line options that take an argument of some sort, usually with format checking of that argument:
Class | Description | Example |
---|---|---|
NoArg | Boolean or with count | CommandOption1.cpp |
WithAnyArg | No arg format checking | CommandOption1.cpp |
WithStringArg | Alpha chars only in arg | |
WithNumberArg | +/- integer arg | CommandOption2.cpp |
WithDecimalArg | decimal argument | CommandOption2.cpp |
WithTimeArg | multi-format time arg | |
WithSimpleTimeArg | pre-defined multi-format time arg | |
WithCommonTimeArg | formatted time arg | CommandOption2.cpp |
WithPositionArg | formatted position arg | |
Rest | args with no option | CommandOption1.cpp |
Classes for defining relationships between real command-line arguments:
Class | Example | Requires |
---|---|---|
NOf | CommandOption3.cpp | exactly N uses of x, y, z |
OneOf | CommandOption3.cpp | at least one usage of x, y, z |
AllOf | CommandOption4.cpp | all or none of x, y, z must be used |
Mutex | CommandOption4.cpp | ONLY one of x, y, or z |
Dependent | CommandOption4.cpp | e.g. if x is used, then y must be used |
Classes for implementing logical checks in conjunction (i.e. as one of the "options") in the above classes:
Class | Example | Virtually set if |
---|---|---|
GroupOr | CommandOption5.cpp | any of x, y or z are used |
GroupAnd | all of x, y and z are used |
Help options. These are handled specially by BasicFramework such that
BasicFramework will exit after printing the appropriate help information when any of the above command-line option types are requested by the user.
The arguments to the command-line arguments (e.g. for "-n 5", "5" is the argument) are available as a vector of strings (where each value in the vector corresponds to one use of the command-line argument) via the getValue() method. In most cases you will need to convert the strings to the appropriate data type yourself (time being an exception).
As an example, if a user specifies "-n 5 -n 7 -n 11", getValue() will return an array of the strings "5","7,"11". A common method for handling cases where only one argument is allowed is to use the vector [] operator like "someOpt.getValue()[0]".
A very common situation you will have is to limit the number of times a command-line argument can be used. This is usually done by calling the setMaxCount() method on the CommandOption-derived class in the application's constructor. See the example codes and CommandOption documentation for more details.