NAME
BUPf - BRTT utility for Antelope parameter file parsing and management
SYNOPSIS
-lbrttutil
#include "BUPf.h"
DESCRIPTION
This is a library with a single c++ class definition,
BUPf, that can
be used to read, parse, manage and write Antelope parameter files.
One might ask why to develop a new and different Antelope parameter file
utility given the extensive capabilities of the c-code routines
in pf(3). The traditional pf(3) functions are perfectly suited
to support batch-mode, non-interactive, Antelope applications, as long as applications
do need need to write modified parameter file values back into the files. The pf(3)
functions first convert the Antelope text parameter files into an internal
representation based on Antelope associative arrays. In the process of
doing this, pf(3) functions strip out all embedded comments from
the text files, loses basic ordering information because of the use of
the unordered associative array and also loses connections from the internal
representation back to the lines in the text files where the information
was read. In a scenario where an application program just wants to read
the parameter files and access the information in a systematic manner, the
existing pf(3) functions work perfectly. However, if an application
programmer wants to modify the internal representation of a parameter
file object and then write out the modifications back to text files
using the pf(3) functions, the results are obfuscated text files
in which the ordering and comments have been lost. For this reason there
are almost no Antelope applications that do this. In the one case where
this is done, rtm(1), the write-backs of modified information is
done through specialized ad hoc substring searches and replacements. Otherwise the rtexec.pf
file would quickly become unusable in a normal text editor. For these reasons
we general advise that Antelope parameter files should be only modified
using traditional text editors.
The c++ class BUPf parses text parameter files, in a manner similar
to pfread(3), into an internal representation that is different from
the associative array produced by pfread(3). The internal representation
of BUPf is an ordered list represented as a Table(3). Each entry in
this list corresponds to a single line in one of the Antelope parameter text files read when
the BUPf object is created. Substitutions at the base level of succeeding
parameter text file entries, in the normal search list returned by pffiles(3),
all are collapsed into text file line entries so that a one to one correspondence between
parameter file entries and a line in one of the Antelope text parameter files
can be established. All in-line comments are also parsed and preserved.
Each entry
in the BUPf internal ordered list is another ordered list also represented
as a Table(3). The individual entry lists consist of six strings, represented
as std::string objects; source, level, key, value, constraints
and comment,
where source is a source file string in the
form <source_file_name>:<line_nmber>, level is a level integer expressed
as a string corresponding to the hierarchy level within the parameter file
object, key is a compound key into the parameter file object expressed
in python form, value is the string value, constrains is a string
that defines value constraints, described below, and comment is an
embedded in-line comment if it exists. If a parameter file entry is the
beginning of another associative array, then the value is set to &Arr.
If a parameter file entry is an embedded list, then the value is set to &Tbl.
Note that in this manner of parsing both order and comments are preserved. Also this
representation provides the capability of writing back a changed value into one of
the source text files without the need to rewrite the entire file.
In particular, BUPf is well suited for applications where parameter files
appear as elements within a GUI. When displaying a parameter file, it is very desirable
to display the file as it appears in its text file form, with the ordering
and comments preserved. BUPf is also well suited for applications
that are designed to write changes back into text parameter files.
CONSTRAINTS
This class introduces an implementation of parameter file value constraints. A parameter
file value constraint is a definition of the value type plus optional enumeration lists,
regular expressions and allowable ranges. These constraints come about by the corresponding
value use within application programs. For instance, a particular value within a parameter
file could be meant to represent an integer number used by the application program, such
as a number of iterations or graphics window dimension expressed as pixels. In these examples,
if the string value cannot be parsed as an integer, then the application program will not
be able to do its job properly. If an improper value string is specified in the parameter
file for a value meant to represent an integer number, then the application program could
behave abnormally or even crash.
Parameter file value constraints can be specified within parameter files as special fields
within in-line comments. In this manner the constraint definitions are invisible to the
legacy parameter file processing routines. Following is an example of a line from a
parameter file in which a value constraint is defined.
window_geom 100 100 #<int> <int> window width and height in pixels
In this example a window geometry is being specified with the key window_geom
and the value "100 100". There is a normal parameter file in-line comment starting
with the # character. The constraints for this value come at the beginning of
the in-line comment. If any in-line comment starts with the #< characters, then
a list of constraints will be parsed from the in-line comment. Constraints
must be specified in the form constraint1[ constraint2[ ...]] with each
of the constraintN fields in the
form <type>[(range)].
More than one constraint can be specified for values that have more than one
white space delimited fields, such as in this case where the value contains
the window width and height in pixels.
For this example the constraints are two integer type constraints with no range
constraints. Therefore the constraints would be satisfied as long as there are
exactly two white space delimited fields in the value string and both field strings
can be parsed as integers. Allowable constraint types are defined below.
-
<str>
This is a string value field. Without an accompanying range constraint, any printable
ASCII characters are allowed except for white space. The type
return value for this constraint is PF_TYPE_STRING. Currently the only range
constraint recognized is a string enumeration constraint in which a list
of white space separated allowable strings are specified. An example of a string
with enumeration range constraints is as follows.
plot_mode loglog #<str>(loglog loglin linlog linlin) Plotting mode
-
<int>
This is a field that can be parsed as an integer. The type
return value of this constraint is PF_TYPE_INT. Currently there are no implemented range
constraints.
-
<float>
This is a field that can be parsed as a float or double. The type
return value of this constraint is PF_TYPE_FLOAT. Currently there are no implemented range
constraints.
-
<regex>
This is a field that is meant to be compiled into a regular expression. The type
return value of this constraint is PF_TYPE_REGEX. This constraint type
is not currently implemented in BUPf but is passed to higher layers of application
software for later checking.
-
<color>
This is a field that is meant to specify a graphics color. The type
return value of this constraint is PF_TYPE_COLOR. This constraint type
is not currently implemented in BUPf but is passed to higher layers of application
software for later checking.
-
<font>
This is a field that is meant to specify a graphics font. The type
return value of this constraint is PF_TYPE_FONT. This constraint type
is not currently implemented in BUPf but is passed to higher layers of application
software for later checking.
Note the constraint types that are simply passed to upper layers of the application
program software stack. For instance, the graphics color and font types cannot be checked
by BUPf since BUPf is meant to be usable outside of a graphics environment.
These constraints must be implemented in higher software layers that are in a
graphics environment, such as the pythonbqplot(3y) PfTreeview.checkvalue
method.
When the parameter files are first read, constraints for each line are parsed, if they exist,
and then compiled into an internal form for processing. If either the parsing or compilation
are not successful, then the constraint is ignored and any constraint checking will return true.
Constraint specifications that can be parsed but will not compile will still be accessible through
the getConstraints method defined below, but will return false if the checkOk
argument is specified.
Constraints generally apply to the line in which they are specified. The exceptions
to this are constraints specified in lines that begin &Arr and &Tbl blocks.
If constraints are specified in these lines, then they are used as default constraints
for the parameters within the block. Examples follow.
limit_colors &Arr{ #<color> color coding for limit spectra
DRS orange
OBE \#ff6000
SSE magenta
LSA darkgray
}
staprocs &Tbl{ #<str> <int> <int> staproc row column
AZ_CRY_D5 0 0
AZ_KNW_D5 1 0
AZ_PFO_D5 2 0
AZ_TRO_D5 3 0
AZ_FRD_D5 4 #<str> <int> this overrides the default constraints
}
In the first &Arr block the constraint for
all of the values is a single color field. In the second &Tbl
block The constraints for the first four table entries are
a string followed by two integers. In the last entry the default
constraints are overridden by another in-line set of constraints.
BUPf CONSTRUCTOR
BUPf(std::string pffile)
With the following constructor arguments:
-
pffile
The name of the parameter file as would specified to pfread(3). .pf is
appended to the basename of the pffile argument,
and a file of this name is sought.
When the environment variable PFPATH is specified, the search is
along the directories in PFPATH, otherwise $ANTELOPE/data/pf and
the current directory are searched. All files found are read; if a
parameter key appears in more than
one file, the complete line (key, value, comments) in the last file read is used.
BUPf METHODS
-
void display ()
This will produce a simple text display of the internal parameter file list
on standard output.
-
int size ()
This wil return the size of the internal parameter file list.
-
Table<Table<std::string>> getList()
This will return the internal parameter file list.
-
int getEntryIndex(std::string key)
This will return the internal parameter file list index corresponding
to the compound key key. If the key is not found, then -1
is returned. Note that searching for key values always occurs in reverse
order so that if two entries have the same key, then the one closest
to the end of the list will be returned.
-
Table<std::string> getEntry(std::string key)
This will return a single entry from the internal parameter file list, corresponding
to the compound key key. Each entry is a 6-tuple string list
with source, level, key, value, constraints and comment, as
defined above. The index
values PF_INDEX_SOURCE, PF_INDEX_LEVEL, PF_INDEX_KEY, PF_INDE_VALUE, PF_INDEX_CONSTRAINTS and PF_INDEX_COMMENT
can be used to reference the entries within the returned Table.
-
Table<std::string> getEntry(int index)
This will return a single entry from the internal parameter file list, corresponding
to the index index.
-
std::string getSource(std::string key)
This will return the source string from the internal parameter file list, corresponding
to the compound key key.
-
std::string getSource(int index)
This will return the source string from the internal parameter file list, corresponding
to the index index.
-
int getLevel(std::string key)
This will return the level string converted to an integer from the internal parameter
file list, corresponding to the compound key key. The level indicates the hierarchy depth.
-
int getLevel(int index)
This will return the integer level from the internal parameter file list, corresponding
to the index index.
-
std::string getKey(int index)
This will return the key string from the internal parameter file list, corresponding
to the index index.
-
std::string getValue(std::string key, bool *checkOk=NULL, Table<int> *types=NULL)
This will return the value from the internal parameter file list, corresponding
to the compound key key. If checkOk is not NULL, then a constraints check
will be returned. Note that the constraints check only checks the BUPf implemented
constraints. If types is not NULL, then a Table of constraint
types in the form PF_TYPE_... is returned.
-
std::string getValue(int index, bool *checkOk=NULL, Table<int> *types=NULL)
This will return the value from the internal parameter file list, corresponding
to the index index. If checkOk is not NULL, then a constraints check
will be returned. Note that the constraints check only checks the BUPf implemented
constraints. If types is not NULL, then a Table of constraint
types in the form PF_TYPE_... is returned.
-
std::string getComment(std::string key)
This will return the comment string from the internal parameter file list, corresponding
to the compound key key.
-
std::string getComment(int index)
This will return the comment string from the internal parameter file list, corresponding
to the index index.
-
std::string getConstraints(std::string key, bool *checkOk=NULL)
This will return the constraints string from the internal parameter file list, corresponding
to the compound key key. If checkOk is not NULL, then a constraints
compilation check will be returned. If this is false, then the constraints
string could not be properly compiled due to a specification error, in which case
the constraints string is ignored by BUPf and constraints checks will always
return true.
-
std::string getConstraints(int index, bool *checkOk=NULL)
This will return the constraints string from the internal parameter file list, corresponding
to the index index. If checkOk is not NULL, then a constraints
compilation check will be returned. If this is false, then the constraints
string could not be properly compiled due to a specification error, in which case
the constraints string is ignored by BUPf and constraints checks will always
return true.
-
bool checkValue(std::string key, std::string *invalue=NULL, Table<int> *types=NULL)
This will check if the value corresponding to the compound key key
meets the BUPf constraints checks and return a boolean result.
If invalue is not NULL, then the value checked will not be the internal value but
the value specified by *invalue instead. In this way prospective values can be checked
before setting them with setValue. If types is not NULL,
then a Table of constraint types in the form PF_TYPE_... is returned.
-
bool checkValue(int index, std::string *invalue=NULL, Table<int> *types=NULL)
This will check if the value corresponding to the index index
meets the BUPf constraints checks and return a boolean result.
If invalue is not NULL, then the value checked will not be the internal value but
the value specified by *invalue instead. In this way prospective values can be checked
before setting them with setValue. If types is not NULL,
then a Table of constraint types in the form PF_TYPE_... is returned.
-
std::string getPfString()
This will return a complete properly formed parameter file string compiled
from the current state of the internal parameter file list.
-
void getPf(Pf **pf)
This will return a standard Antelope parameter file object in *pf
in a manner similar to pfcompile(3).
-
void setValue(std::string key, std::string value)
This will set the value in the internal list of the compound key
corresponding to key to value. If the value has changed, then
the callback method valueChangedCallback, defined below, will be called.
The callback can replace the set value with some other value.
Note that constraint checks are always advisory and do not control the ability
of an application program to change parameter file values using this method.
-
void setValue(int index, std::string value)
This will set the value in the internal list with index index
to value. If the value has changed, then
the callback method valueChangedCallback, defined below, will be called.
-
void setComment(std::string key, std::string comment)
This will set the comment in the internal list of the compound key
corresponding to key to comment.
-
void setComment(int index, std::string comment)
This will set the comment in the internal list with index index
to comment.
-
void write(std::string &pffile)
This will cause the internal representation to be written to a normal
Antelope text parameter file with name pffile.
-
static std::string key2Perl (std::string key)
This is a static class method used to convert compound key indexes in
python form, key, to compound key indexes in perl form, as needed
by pfget(3).
-
static std::string key2Pfkey (std::string key)
This is a static class method used to convert compound key indexes in
python form, key, to simple parameter file key strings. Note that this
only returns the last key in the hierarchy.
-
static Table<std::string> key2Table (std::string key)
This is a static class method used to convert compound key indexes in
python form, key, to a table of values corresponding to all of the
parameter files in the hierarchy. Note that keys to &Arr
parameter file entries will be strings delimited by " characters.
Keys to &Tbl parameter file entries will not have the delimiting "
characters.
-
virtual void valueChangedCallback (std::string key, int index, std::string from, std::string &to)
This is a virtual callback method defined by BUPf sub-classes. If defined, then
it is called whenever a parameter file value is changed using setValue. The
compound key key and the list index index are specified along with the
original value, from, and the changed value to. This callback can be used as
a notification in applications that need to monitor changes in the parameter file object.
Note that the to string can be modified by the callback. This allows the callback
to either set the to string to the from string in cases where changes violate
the constraints, or for any other reason.
EXAMPLE
Following is a simple c++ example code that will exercise a
BUPf object.
/* A test for the BUPf class. */
#include "BUPf.h"
class myPf : public BUPf {
public:
myPf (std::string pffile) : BUPf (pffile, PF_TYPE_PFFILE) {}
protected:
void valueChangedCallback (std::string key, int index, std::string from, std::string &to) {
printf ("key = %s value '%s' changed to '%s'\n", key.c_str(), from.c_str(), to.c_str());
}
};
int
main (int argc, char **argv)
{
if (argc != 1 && argc != 2) {
fprintf (stderr, "usage:pf_test [pffile]\n");
exit (1);
}
char *pffile;
if (argc == 1) {
pffile = (char *) "q3302orb";
} else {
pffile = argv[1];
}
auto pf = new myPf (pffile);
pf->display();
char value[64];
sprintf (value, "%d", int(std_now()));
pf->setValue ("[\"pf_revision_time\"]", value);
std::string pfstring = pf->getPfString();
printf ("\n%s", pfstring.c_str());
std::string pfout = "pf_test";
pf->write(pfout);
exit (0);
}
BUGS AND CAVEATS
In this implementation of the
BUPf class, most, but not all, of the parameter
file features implemented in
pf(3) are implemented in
BUPf. Some of the
more exotic features in
pf(3), such as the
&Literal type and parameter substitution,
are not implemented in
BUPf. The ability to change the entries in the parameter file
are currently limited to value and comment edits. There are no current implementations
of line deletions, line insertions, key edits, or constraints edits. These changes must still
be done by editing the parameter files in a text editor.
SEE ALSO
pf(3),
Table(3)
AUTHOR
Danny Harvey, BRTT