The keyval2cc utility is used to
translate a <keyval>
document (representing a
configuration) into the necessary C++ code for loading and using
the represented configuration. In addition, it will provide
useful parts for building documentation as well. The beauty of
this is that you, as the developer, should only have to maintain
the single <keyval>
file as these other "parts" can
automatically be generated as needed.
The following sections will take you through the steps of creating a new ldfilt command. We create this utility in the following steps:
We will use the newapaapp to get
started. To make use of this, you must be a Vaisala
developer with access to the
GAItool,
GAInlib and
GAIapa packages. The package
names may change, but you should be able to check out the
corresponding packages from the
gen/tool
,
gen/nlib
, and
apa2000/lp2000
areas under
CVS.
We will then create our own configuration file
(ldfilt_config.xml
) to define the
configurable options for our Ld filtering utility.
We will then update the ldfilt.cc
source code to create a nlib::Filter
object and use our configuration values.
We will then read in
nlib::Object
s, and write out the ones
that make it through our configurable filter.
We're going to be lazy and use the newapaapp command to get started. The following commands will stub in a template file, build the initial template code, and run it:
[pkb@salsa pkb]$
newapaapp -m ldfilt -n ldfilt -c true -v true -d \
>
"Filters Ld objects based upon user configuration"
*** Generating Template Files ***
*** Checking Files in /home/pkb/gai/cvs/apa/src/ldfilt ***
created: ldfilt.hh
created: ldfilt.cc
created: ldfilt.man.m4
created: makefile
created: ldfilt_config.xml
Success! Build with:
(cd /home/pkb/gai/cvs/apa/src/ldfilt; make -f makefile ldfilt)
[pkb@salsa pkb]$
(cd /home/pkb/gai/cvs/apa/src/ldfilt; make -f makefile ldfilt)
... lots of cryptic output as the initial application is built ...
[pkb@salsa pkb]$
ldfilt -h
Usage:
ldfilt [-verbosity LEVEL] [-cfg FNAME] [-cfg_loaded] [-cfg_defaults]
[-tag TAG] [-cdb_host HOST] [-cdb_db DATABASE] [-msg_ipc IPC]
[-msg_ipc_list] [-tape_ipc IPC] [-tape_ipc_list] [-sdata3d_ipc IPC]
[-sdata3d_ipc_list] [-fg] [-loglevel LEVEL] [-logmode MODE]
[-logas FACILITY] [-h] [-help] [-man] [-version] [-debug]
[-check_locks [FILE]]
[pkb@salsa pkb]$
ldfilt
check setup at line 189 in ldfilt.cc
ldfilt is doing nothing for 5 seconds!
ldfilt is doing nothing for 5 seconds!
ldfilt is doing nothing for 5 seconds!Control-C
[[pkb@salsa pkb]$
OK then. We really don't have a clue as to what we've done to deserve this, but somehow or other, we've already got a pretty good start at the new ldfilt utility. Sure, the new ldfilt doesn't do much yet, but we are well on our way.
We are going to replace the
ldfilt_config.xml
template file which the
newapaapp command created for us with the
following:
Figure 3.3. Modified ldfilt_config.xml
<?xml version="1.0"?> <!DOCTYPE keyval PUBLIC "-//VAISALA//DTD KeyValue XML V1.0.0//EN" "http://www.mekwin.com/vaisala/xml/dtd/keyval/keyval_1_0_0.dtd"> <!-- $Id: ldfilt_config.xml,v 1.1 2004/03/13 00:05:17 pkb Exp $ Definition of configurable options for ldfilt Edit this file, it will be used to produce: ldfilt_config.hh ldfilt_config.cc ldfilt_config.m4i src/package/ldfilt.cfg --> <keyval class="ldfilt" namespace="lp"> &verbosity; <boolean default="false" varname="Invert"> <key>lp.ldfilt.invert</key> <summary>Reverses the results of the filter rules.</summary> <description>If this option is set to <literal>true</literal>, then the rules will have the opposite affect. Data that would have been allowed through would be filtered out and data that would have been filtered out would now be allowed through.</description> </boolean> <real default="-1500.0" min="-15000.0" max="0.0" varname="SignalMin"> <key>lp.ldfilt.signal.min</key> <summary>Minimum signal strength (LLP units) to allow through.</summary> <description>All Ld objects which have a signal strength less than this value are filtered.</description> </real> <real default="1500.0" min="0.0" max="15000.0" varname="SignalMax"> <key>lp.ldfilt.signal.max</key> <summary>Maximum signal strength (LLP units) to allow through.</summary> <description>All Ld objects which have a signal strength greater than this value are filtered.</description> </real> </keyval>
Before we try to make use of the new configuration options, lets make sure things still build with the following:
[pkb@salsa pkb]$
cd $APAHOME/src/ldfilt
[pkb@salsa ldfilt]$
make all
... lots of cryptic output ...
[pkb@salsa ldfilt]$
ldfilt -h
Usage:
ldfilt [-verbosity LEVEL] [-cfg FNAME] [-cfg_loaded] [-cfg_defaults]
[-tag TAG] [-cdb_host HOST] [-cdb_db DATABASE] [-msg_ipc IPC]
[-msg_ipc_list] [-tape_ipc IPC] [-tape_ipc_list] [-sdata3d_ipc IPC]
[-sdata3d_ipc_list] [-fg] [-loglevel LEVEL] [-logmode MODE]
[-logas FACILITY] [-h] [-help] [-man] [-version] [-debug]
[-check_locks [FILE]]
If we're lucky, everything will build and run the same
as it did before. If we look at the man page, we'll notice
that the configuration section reflects the changes we made in
ldfilt_config.xml
.
Also due to the changes in
ldfilt_config.xml
, there are new member
functions available in ldfile_config.hh
and ldfilt_config.cc
. We will make use of
these new member functions as we add the source code for our
custom nlib::Filter
implementation to
the ldfilter.cc
source file. The
following shows the code added:
Figure 3.4. nlib::Filter
for
ldfilter.cc
//---------------------------------------------------------------- // nlib::Filter implementation for Ld objects //---------------------------------------------------------------- #ifndef __nobj_Filter_hh #include <nobj/Filter.hh> #endif #ifndef __nobj_Source_hh #include <nobj/Source.hh> #endif #ifndef __vdata_Ld_hh #include <vdata/Ld.hh> #endif namespace { class LdFilter : public nlib::Filter { public: LdFilter(const ldfiltConfig& cfg) { _Acceptable = !cfg.isInvert(); _SigMin = cfg.getSignalMin(); _SigMax = cfg.getSignalMax(); } bool isObjectAcceptable(const nlib::Handle& h) { const Ld* ld = Ld::toLd(h); if (ld == 0) return false; // only allow Ld objects through double sig; // we require signal strength values if (!ld->getSignal(sig)) return false; bool ok = _Acceptable; // see if out of range if ((sig < _SigMin) || (sig > _SigMax)) ok = !_Acceptable; return ok; } private: bool _Acceptable; double _SigMin, _SigMax; }; }
Again, we will be paranoid, and make certain things build as they should:
[pkb@salsa ldfilt]$
make all
... lots of cryptic output ...
[pkb@salsa ldfilt]$
ldfilt -h
Usage:
ldfilt [-verbosity LEVEL] [-cfg FNAME] [-cfg_loaded] [-cfg_defaults]
[-tag TAG] [-cdb_host HOST] [-cdb_db DATABASE] [-msg_ipc IPC]
[-msg_ipc_list] [-tape_ipc IPC] [-tape_ipc_list] [-sdata3d_ipc IPC]
[-sdata3d_ipc_list] [-fg] [-loglevel LEVEL] [-logmode MODE]
[-logas FACILITY] [-h] [-help] [-man] [-version] [-debug]
[-check_locks [FILE]]
[pkb@salsa ldfilt]$
Our work on ldfilt has been
progressing nicely. We'll now replace (or drastically update)
the main()
method of the
ldfilt
class to the following:
Figure 3.5. Updated main()
in
ldfilt.cc
//---------------------------------------------------------------- // ldfilt::main() implementation //---------------------------------------------------------------- int ldfilt::main() { // let base class make basic checks if (Application::main() != 0) { return 1; // leave now if it something is wrong } doInitialization(); // initialize class (loads config) // construct instance of our Ld Filter Handle filter(new LdFilter(_Cfg)); // install it as filter to object output Handle out(Source::toArchive(&std::cout,filter)); // now, read all Objects from cin, and // and send them through filter (and // possibly out) Source* in = Source::fromArchive(&std::cin); in->getNotifier().addListener(out); in->run(); delete in; if (verbosityLevel(1)) { vout() << "\nnormal termination of ldfilt::main()\n"; } return 0; // return success }
Once again, we'll compile and run (feeding in a set of 0 Ld objects) with the following:
[pkb@salsa ldfilt]$
make all
... lots of cryptic output ...
[pkb@salsa ldfilt]$
ldfilt < /dev/null
check setup at line 120 in ldfilt.cc
[pkb@salsa ldfilt]$
We don't really want the output shown. So, we'll take a
look at line 120
in
ldfilt.cc
. It turns out, that this
diagnostic output was inserted by the
newapaapp command when we first created our
ldfilt application. It indicates the point
in the file where we can do additional sanity checks upon
values read from the configuration file. As we like living on
the edge, we aren't going to worry about sissy sanity checks
and delete the lines of code which produced this warning
message.
We're just about done. We'll recompile, locate a test data file (some real Ld objects), make sure negative data comes through the filter, create a configuration that only allows positive Ld objects through, and try it out. This is shown below. NOTE: A sane person would simply edit the configuration file instead of using the sed hack shown below.
[pkb@salsa ldfilt]$
make all
... lots of cryptic output ...
[pkb@salsa ldfilt]$
ldfilt < /tmp/ld.raw | ldcat -printer dff
2004-03-12 21:36:32.999997661 32.9932 -100.0014 0 -75.0 0 0.7 0.3 2.3 20.9 0.2 4 G
[pkb@salsa ldfilt]$
sed -e 's/-1500.0/0.0/g' < $APAHOME/src/package/ldfilt.cfg \
> > $APAHOME/etc/positive.cfg
[pkb@salsa ldfilt]$
ldfilt -cfg positive.cfg < /tmp/ld.raw | ldcat -printer dff
[pkb@salsa ldfilt]$
And there you have it. We've got a working start to our new ldfilt application. At this point, we'd want to clean up the man page and start adding other options to the configuration file as we work towards a final product. I'll leave that exercise to the reader as I'm growing weary of documentation.