AppOption.hpp

Go to the documentation of this file.
00001 #pragma ident "$Id: AppOption.hpp 2972 2011-11-10 12:10:39Z yanweignss $"
00002 
00008 #ifndef GPSTK_APPOPTION_HPP
00009 #define GPSTK_APPOPTION_HPP
00010 
00011 //============================================================================
00012 //
00013 //  This file is part of GPSTk, the GPS Toolkit.
00014 //
00015 //  The GPSTk is free software; you can redistribute it and/or modify
00016 //  it under the terms of the GNU Lesser General Public License as published
00017 //  by the Free Software Foundation; either version 2.1 of the License, or
00018 //  any later version.
00019 //
00020 //  The GPSTk is distributed in the hope that it will be useful,
00021 //  but WITHOUT ANY WARRANTY; without even the implied warranty of
00022 //  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00023 //  GNU Lesser General Public License for more details.
00024 //
00025 //  You should have received a copy of the GNU Lesser General Public
00026 //  License along with GPSTk; if not, write to the Free Software Foundation,
00027 //  Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
00028 //
00029 //  Wei Yan - Chinese Academy of Sciences . 2011
00030 //
00031 //============================================================================
00032 
00033 #include <string>
00034 #include <set>
00035 #include "String.hpp"
00036 #include "Exception.hpp"
00037 #include "DebugUtils.hpp"
00038 
00039 namespace gpstk
00040 {
00041       //
00042       // class OptionCallback 
00043       //
00044 
00045    class AbstractOptionCallback
00046    {
00047    public:
00048       virtual void invoke(const std::string& name, 
00049                           const std::string& value) const = 0;
00050 
00051       virtual AbstractOptionCallback* clone() const = 0;
00052 
00053       virtual ~AbstractOptionCallback(){}
00054 
00055    protected:
00056       AbstractOptionCallback(){}
00057       AbstractOptionCallback(const AbstractOptionCallback&){}
00058    };
00059 
00060    template <class C>
00061    class OptionCallback: public AbstractOptionCallback
00062    {
00063    public:
00064       typedef void (C::*Callback)(const std::string& name, 
00065                                   const std::string& value);
00066 
00067       OptionCallback(C* pObject, Callback method)
00068          : _pObject(pObject), _method(method) { GPSTK_CHECK_PTR(pObject); }
00069 
00070       OptionCallback(const OptionCallback& cb)
00071          : AbstractOptionCallback(cb), _pObject(cb._pObject),_method(cb._method)
00072       {}
00073 
00074       ~OptionCallback(){}
00075 
00076       OptionCallback& operator = (const OptionCallback& cb)
00077       {
00078          if (&cb != this)
00079          {
00080             this->_pObject = cb._pObject;
00081             this->_method  = cb._method;
00082          }
00083 
00084          return *this;
00085       }
00086 
00087       void invoke(const std::string& name, const std::string& value) const
00088       { (_pObject->*_method)(name, value); }
00089 
00090       AbstractOptionCallback* clone() const
00091       { return new OptionCallback(_pObject, _method); }
00092 
00093    protected:
00094       OptionCallback(){}
00095 
00096       C* _pObject;
00097       Callback _method;
00098    };
00099 
00101 
00136    class Option
00137    {
00138    public:
00139       Option()
00140          : _required(false), _repeatable(false), 
00141            _argRequired(false),_pCallback(0) {}
00142 
00143 
00144       Option(const Option& option)
00145          : _shortName(option._shortName),
00146            _fullName(option._fullName),
00147            _description(option._description),
00148            _required(option._required),
00149            _repeatable(option._repeatable),
00150            _argName(option._argName),
00151            _argRequired(option._argRequired),
00152            _group(option._group),
00153            _pCallback(option._pCallback)
00154       { if (_pCallback) _pCallback = _pCallback->clone();}
00155 
00156 
00157       Option(const std::string& fullName, const std::string& shortName)
00158          : _shortName(shortName),
00159            _fullName(fullName),
00160            _required(false),
00161            _repeatable(false),
00162            _argRequired(false),
00163            _pCallback(0) {}
00164 
00165 
00166       Option(const std::string& fullName, 
00167              const std::string& shortName, 
00168              const std::string& description, 
00169              bool required=false)
00170          : _shortName(shortName),
00171            _fullName(fullName),
00172            _description(description),
00173            _required(required),
00174            _repeatable(false),
00175            _argRequired(false),
00176            _pCallback(0) {}
00177 
00178 
00179       Option(const std::string& fullName, 
00180              const std::string& shortName, 
00181              const std::string& description, 
00182              bool required, 
00183              const std::string& argName, 
00184              bool argRequired=false)
00185          : _shortName(shortName),
00186            _fullName(fullName),
00187            _description(description),
00188            _required(required),
00189            _repeatable(false),
00190            _argName(argName),
00191            _argRequired(argRequired),
00192            _pCallback(0) {}
00193 
00194       ~Option() { delete _pCallback; }
00195 
00196       Option& operator = (const Option& option)
00197       {
00198          if (&option != this)
00199          {
00200             Option tmp(option);
00201             swap(tmp);
00202          }
00203          return *this;
00204       }
00205 
00206       void swap(Option& option)
00207       {
00208          std::swap(_shortName, option._shortName);
00209          std::swap(_fullName, option._fullName);
00210          std::swap(_description, option._description);
00211          std::swap(_required, option._required);
00212          std::swap(_repeatable, option._repeatable);
00213          std::swap(_argName, option._argName);
00214          std::swap(_argRequired, option._argRequired);
00215          std::swap(_group, option._group);
00216          std::swap(_pCallback, option._pCallback);
00217       }
00218 
00219       Option& shortName(const std::string& name)
00220       {
00221          _shortName = name;
00222          return *this;
00223       }
00224 
00225       Option& fullName(const std::string& name)
00226       {
00227          _fullName = name;
00228          return *this;
00229       }
00230 
00231       Option& description(const std::string& text)
00232       {
00233          _description = text;
00234          return *this;
00235       }
00236 
00237       Option& required(bool flag)
00238       {
00239          _required = flag;
00240          return *this;
00241       }
00242 
00243       Option& repeatable(bool flag)
00244       {
00245          _repeatable = flag;
00246          return *this;
00247       }
00248 
00249       Option& argument(const std::string& name, bool required = true)
00250       {
00251          _argName     = name;
00252          _argRequired = required;
00253          return *this;
00254       }
00255 
00256       Option& noArgument()
00257       {
00258          _argName.clear();
00259          _argRequired = false;
00260          return *this;
00261       }
00262 
00263       Option& group(const std::string& group)
00264       {
00265          _group = group;
00266          return *this;
00267       }
00268 
00269       Option& callback(const AbstractOptionCallback& cb)
00270       {
00271          _pCallback = cb.clone();
00272          return *this;
00273       }
00274 
00275       const std::string& shortName() const 
00276       { return _shortName; }
00277 
00278       const std::string& fullName() const 
00279       { return _fullName; }
00280 
00281       const std::string& description() const
00282       { return _description; }
00283 
00284       bool required() const
00285       { return _required; }
00286 
00287       bool repeatable() const
00288       { return _repeatable; }
00289 
00290       bool takesArgument() const
00291       { return !_argName.empty(); }
00292 
00293       bool argumentRequired() const
00294       { return _argRequired; }
00295 
00296       const std::string& argumentName() const
00297       { return _argName; }
00298 
00299       const std::string& group() const
00300       { return _group; }
00301 
00302       AbstractOptionCallback* callback() const
00303       { return _pCallback; }
00304 
00305       bool matchesShort(const std::string& option) const
00306       {
00307          return option.length() > 0 
00308             && !_shortName.empty() && option.compare(0, _shortName.length(), _shortName) == 0;
00309       }
00310 
00311       bool matchesFull(const std::string& option) const
00312       {
00313          std::string::size_type pos = option.find_first_of(":=");
00314          std::string::size_type len = pos == std::string::npos ? option.length() : pos;
00315          return len == _fullName.length()
00316             && icompare(option, 0, len, _fullName, 0, len) == 0;
00317       }
00318 
00319       bool matchesPartial(const std::string& option) const
00320       {
00321          std::string::size_type pos = option.find_first_of(":=");
00322          std::string::size_type len = pos == std::string::npos ? option.length() : pos;
00323          return option.length() > 0 
00324             && icompare(option, 0, len, _fullName, 0, len) == 0;
00325       }
00326 
00327       inline void process(const std::string& option, std::string& arg) const;
00328        
00329    protected:
00330       std::string _shortName;
00331       std::string _fullName;
00332       std::string _description;
00333       bool        _required;
00334       bool        _repeatable;
00335       std::string _argName;
00336       bool        _argRequired;
00337       std::string _group;
00338       AbstractOptionCallback* _pCallback;
00339 
00340    }; // End of class 'Option'
00341 
00342    inline void Option::process(const std::string& option, 
00343                                std::string& arg) const
00344    {
00345       std::string::size_type pos = option.find_first_of(":=");
00346       std::string::size_type len = (pos==std::string::npos)?option.length():pos;
00347       if (icompare(option, 0, len, _fullName, 0, len) == 0)
00348       {
00349          if (takesArgument())
00350          {
00351             if (argumentRequired() && pos == std::string::npos)
00352                GPSTK_THROW(Exception(_fullName+" requires "+argumentName()));
00353             if (pos != std::string::npos)
00354                arg.assign(option, pos + 1, option.length() - pos - 1);
00355             else
00356                arg.clear();
00357          }
00358          else if (pos != std::string::npos)
00359          {
00360             GPSTK_THROW(Exception("Unexpected argument "+option));
00361          }
00362          else arg.clear();
00363       }
00364       else if (!_shortName.empty() && 
00365                option.compare(0, _shortName.length(), _shortName) == 0)
00366       {
00367          if (takesArgument())
00368          {
00369             if (argumentRequired() && option.length() == _shortName.length())
00370                GPSTK_THROW(Exception(_shortName+" requires "+argumentName()));
00371             arg.assign(option, _shortName.length(), 
00372                        option.length()-_shortName.length());
00373          }
00374          else if (option.length() != _shortName.length())
00375          {
00376             GPSTK_THROW(Exception("Unexpected argument "+option));
00377          }
00378          else arg.clear();
00379       }
00380       else GPSTK_THROW(Exception("Unknown option "+option));
00381 
00382    }  // End of method 'Option::process()'
00383 
00384 
00385    class OptionSet
00386    {
00387    public:
00388       typedef std::vector<Option> OptionVec;
00389       typedef OptionVec::const_iterator Iterator;
00390 
00391       OptionSet(){}
00392 
00393       OptionSet(const OptionSet& options)
00394          : _options(options._options) {}
00395 
00396       ~OptionSet() {}
00397 
00398       OptionSet& operator = (const OptionSet& options)
00399       {
00400          if (&options != this) _options = options._options;
00401          return *this;
00402       }
00403       
00404       void addOption(const Option& option)
00405       {
00406          GPSTK_ASSERT(!option.fullName().empty());
00407 
00408          for (Iterator it=begin(); it != end(); it++)
00409          {
00410             if (it->fullName() == option.fullName())
00411             {
00412                GPSTK_THROW(Exception(it->fullName()));
00413             }
00414          }
00415 
00416          _options.push_back(option);
00417       }
00418 
00427       bool hasOption(const std::string& name, bool matchShort = false) const
00428       {
00429          bool found = false;
00430          for (Iterator it = _options.begin(); it != _options.end(); ++it)
00431          {
00432             if ((matchShort && it->matchesShort(name)) || 
00433                 (!matchShort && it->matchesFull(name)) )
00434             {
00435                if (!found) found = true;
00436                else return false;
00437             }
00438          }
00439          return found;
00440       }
00441       
00452       const Option& getOption(const std::string& name, 
00453                               bool matchShort = false) const
00454       {
00455          const Option* pOption = 0;
00456          for (Iterator it = _options.begin(); it != _options.end(); ++it)
00457          {
00458             if ((matchShort && it->matchesShort(name)) || 
00459                 (!matchShort && it->matchesPartial(name)))
00460             {
00461                if (!pOption)
00462                {
00463                   pOption = &*it;
00464                   if (!matchShort && it->matchesFull(name)) break;
00465                }
00466                else if (!matchShort && it->matchesFull(name))
00467                {
00468                   pOption = &*it;
00469                   break;
00470                }
00471                else GPSTK_THROW(Exception("Ambiguous Option " + name));
00472             }
00473          }
00474          if (pOption) return *pOption;
00475          else GPSTK_THROW(Exception("Unknown Option " + name));
00476       }
00477       
00478       Iterator begin() const { return _options.begin(); }
00479 
00480       Iterator end() const { return _options.end(); }
00481 
00482    protected:   
00483       OptionVec _options;
00484 
00485    }; // End of class 'OptionSet'
00486    
00487 
00518    class OptionProcessor
00519    {
00520    public:
00521       OptionProcessor(const OptionSet& options)
00522          :_options(options),_unixStyle(true),_ignore(false){}
00523       
00524       ~OptionProcessor() {}
00525 
00526       void setUnixStyle(bool flag)
00527       { _unixStyle = flag; }
00528       
00529 
00530       bool isUnixStyle() const
00531       { return _unixStyle; }
00532       
00533 
00534       bool process(const std::string& argument, 
00535                    std::string& optionName, 
00536                    std::string& optionArg)
00537       {
00538          if (!_ignore)
00539          {
00540             if (_unixStyle) return processUnix(argument, optionName, optionArg);
00541             else return processDefault(argument, optionName, optionArg);
00542          }
00543          return false;
00544       }
00545 
00546 
00547       void checkRequired() const
00548       {
00549          for (OptionSet::Iterator it = _options.begin(); it != _options.end(); ++it)
00550          {
00551             if (it->required() && 
00552                 _specifiedOptions.find(it->fullName())==_specifiedOptions.end())
00553                GPSTK_THROW(Exception(it->fullName()));
00554          }
00555       }
00556 
00557 
00558    protected:
00559       inline bool processUnix(const std::string& argument, 
00560                               std::string& optionName, 
00561                               std::string& optionArg );
00562       
00563       inline bool processDefault(const std::string& argument, 
00564                                  std::string& optionName, 
00565                                  std::string& optionArg);
00566       
00567       inline bool processCommon(const std::string& optionStr, 
00568                                 bool isShort, 
00569                                 std::string& optionName, 
00570                                 std::string& optionArg);
00571 
00572       const OptionSet& _options;
00573       bool _unixStyle;
00574       bool _ignore;
00575       std::set<std::string> _groups;
00576       std::set<std::string> _specifiedOptions;
00577 
00578    }; // End of class 'OptionProcessor'
00579 
00580    inline bool OptionProcessor::processUnix(const std::string& argument, 
00581                                             std::string& optionName, 
00582                                             std::string& optionArg )
00583    {
00584       std::string::const_iterator it  = argument.begin();
00585       std::string::const_iterator end = argument.end();
00586       if (it != end)
00587       {
00588          if (*it == '-')
00589          {
00590             ++it;
00591             if (it != end)
00592             {
00593                if (*it == '-')
00594                {
00595                   ++it;
00596                   if (it == end)
00597                   {
00598                      _ignore = true;
00599                      return true;
00600                   }
00601                   else return processCommon(std::string(it, end), false, optionName, optionArg);
00602                }
00603                else return processCommon(std::string(it, end), true, optionName, optionArg);
00604             }
00605          }
00606       }
00607       return false;
00608 
00609    }  // End of method 'OptionProcessor::processUnix()'
00610 
00611    inline bool OptionProcessor::processDefault(const std::string& argument, 
00612                                                std::string& optionName, 
00613                                                std::string& optionArg)
00614    {
00615       std::string::const_iterator it  = argument.begin();
00616       std::string::const_iterator end = argument.end();
00617       if (it != end)
00618       {
00619          if (*it == '/')
00620          {
00621             ++it;
00622             return processCommon(std::string(it, end), false, optionName, optionArg);
00623          }
00624       }
00625       return false;
00626 
00627    }  // End of method 'OptionProcessor::processDefault()'
00628 
00629    inline bool OptionProcessor::processCommon(const std::string& optionStr, 
00630                                               bool isShort, 
00631                                               std::string& optionName, 
00632                                               std::string& optionArg)
00633    {
00634       if (optionStr.empty()) throw Exception();
00635       const Option& option = _options.getOption(optionStr, isShort);
00636       const std::string& group = option.group();
00637       if (!group.empty())
00638       {
00639          if (_groups.find(group) != _groups.end())
00640          {
00641             GPSTK_THROW(Exception(option.fullName()));
00642          }
00643          else
00644             _groups.insert(group);
00645       }
00646       if (_specifiedOptions.find(option.fullName())!=_specifiedOptions.end() && 
00647           !option.repeatable())
00648       {
00649          GPSTK_THROW(Exception(option.fullName()));
00650       }
00651       _specifiedOptions.insert(option.fullName());
00652       option.process(optionStr, optionArg);
00653       optionName = option.fullName();
00654 
00655       return true;
00656 
00657    }  // End of method 'OptionProcessor::processCommon()'
00658 
00659   
00660    class HelpFormatter
00661    {
00662    public:
00663       HelpFormatter(const OptionSet& options)
00664          : _options(options),
00665            _width(78),
00666            _tabWidth(4),
00667            _indent(0),
00668            _unixStyle(true) { _indent = calcIndent(); }
00669 
00670       ~HelpFormatter(){}
00671 
00672       void setCommand(const std::string& command)
00673       { _command = command; }
00674 
00675       const std::string& getCommand() const
00676       { return _command; }
00677 
00678       void setUsage(const std::string& usage)
00679       { _usage = usage; }
00680 
00681       const std::string& getUsage() const
00682       { return _usage; }
00683 
00684       void setHeader(const std::string& header)
00685       { _header = header; }
00686 
00687       const std::string& getHeader() const
00688       { return _header; }
00689 
00690       void setFooter(const std::string& footer)
00691       { _footer = footer; }
00692 
00693       const std::string& getFooter() const
00694       { return _footer; }
00695 
00696       void format(std::ostream& ostr) const
00697       {
00698          ostr << "Usage: " << _command;
00699          if (!_usage.empty())
00700          {
00701             ostr << ' ';
00702             formatText(ostr, _usage, (int) _command.length() + 1);
00703          }
00704          ostr << '\n';
00705          if (!_header.empty())
00706          {
00707             formatText(ostr, _header, 0);
00708             ostr << "\n\n";
00709          }
00710          ostr << "Options: " << "\n";
00711          formatOptions(ostr);
00712          if (!_footer.empty())
00713          {
00714             ostr << '\n';
00715             formatText(ostr, _footer, 0);
00716             ostr << '\n';
00717          }
00718       }
00719 
00720       void setWidth(int width)
00721       { _width = width; }
00722 
00723       int getWidth() const
00724       { return _width; }
00725 
00726       void setIndent(int indent)
00727       { _indent = indent; }
00728 
00729       int getIndent() const
00730       { return _indent; }
00731 
00732       void setAutoIndent()
00733       { _indent = calcIndent(); }
00734 
00735       void setUnixStyle(bool flag)
00736       { _unixStyle = flag; }
00737 
00738       bool isUnixStyle() const
00739       { return _unixStyle; }
00740 
00741       std::string shortPrefix() const
00742       { return _unixStyle ? "-" : "/"; }
00743 
00744       std::string longPrefix() const
00745       { return _unixStyle ? "--" : "/"; }
00746 
00747    protected:
00748 
00749       int calcIndent() const
00750       {
00751          int indent = 0;
00752          for (OptionSet::Iterator it = _options.begin(); it != _options.end(); ++it)
00753          {
00754             int shortLen = (int) it->shortName().length();
00755             int fullLen  = (int) it->fullName().length();
00756             int n = 0;
00757             if (_unixStyle && shortLen > 0)
00758             {
00759                n += shortLen + (int) shortPrefix().length();
00760                if (it->takesArgument())
00761                   n += (int) it->argumentName().length() + (it->argumentRequired() ? 0 : 2);
00762                if (fullLen > 0) n += 2;
00763             }
00764             if (fullLen > 0)
00765             {
00766                n += fullLen + (int) longPrefix().length();
00767                if (it->takesArgument())
00768                   n += 1 + (int) it->argumentName().length() + (it->argumentRequired() ? 0 : 2);
00769             }
00770             n += 2;
00771             if (n > indent)
00772                indent = n;
00773          }
00774          return indent;
00775       }
00776 
00777       void formatOptions(std::ostream& ostr) const
00778       {
00779          int optWidth = calcIndent();
00780          for (OptionSet::Iterator it = _options.begin(); it != _options.end(); ++it)
00781          {
00782             formatOption(ostr, *it, optWidth);
00783             formatText(ostr, it->description(), _indent, optWidth);
00784             ostr << '\n';
00785          }
00786       }
00787 
00788       void formatOption(std::ostream& ostr, 
00789                         const Option& option, int width) const
00790       {
00791          int shortLen = (int) option.shortName().length();
00792          int fullLen  = (int) option.fullName().length();
00793 
00794          int n = 0;
00795          if (_unixStyle && shortLen > 0)
00796          {
00797             ostr << "  " << shortPrefix() << option.shortName();
00798             n += (int) shortPrefix().length() + (int) option.shortName().length();
00799             if (option.takesArgument())
00800             {
00801                if (!option.argumentRequired()) { ostr << '['; ++n; }
00802                ostr << option.argumentName();
00803                n += (int) option.argumentName().length();
00804                if (!option.argumentRequired()) { ostr << ']'; ++n; }
00805             }
00806             if (fullLen > 0) { ostr << ", "; n += 2; }
00807          }
00808          if (fullLen > 0)
00809          {
00810             ostr << longPrefix() << option.fullName();
00811             n += (int) longPrefix().length() + (int) option.fullName().length();
00812             if (option.takesArgument())
00813             {
00814                if (!option.argumentRequired()) { ostr << '['; ++n; }
00815                ostr << '=';
00816                ++n;
00817                ostr << option.argumentName();
00818                n += (int) option.argumentName().length();
00819                if (!option.argumentRequired()) { ostr << ']'; ++n; }
00820             }
00821          }
00822          while (n < width) { ostr << ' '; ++n; }     
00823       }
00824 
00825       void formatText(std::ostream& ostr, 
00826                       const std::string& text, int indent) const
00827       {
00828          formatText(ostr, text, indent, indent);
00829       }
00830       
00831       void formatText(std::ostream& ostr, 
00832                       const std::string& text, 
00833                       int indent, int firstIndent) const
00834       {
00835          int pos = firstIndent;
00836          int maxWordLen = _width - indent;
00837          std::string word;
00838          for (std::string::const_iterator it = text.begin(); it != text.end(); ++it)
00839          {
00840             if (*it == '\n')
00841             {
00842                clearWord(ostr, pos, word, indent);
00843                ostr << '\n';
00844                pos = 0;
00845                while (pos < indent) { ostr << ' '; ++pos; }
00846             }
00847             else if (*it == '\t')
00848             {
00849                clearWord(ostr, pos, word, indent);
00850                if (pos < _width) ++pos;
00851                while (pos < _width && pos % _tabWidth != 0)
00852                {
00853                   ostr << ' ';
00854                   ++pos;
00855                }
00856             }
00857             else if (*it == ' ')
00858             {
00859                clearWord(ostr, pos, word, indent);
00860                if (pos < _width) { ostr << ' '; ++pos; }
00861             }
00862             else 
00863             {
00864                if (word.length() == maxWordLen)
00865                {
00866                   clearWord(ostr, pos, word, indent);
00867                }
00868                else word += *it;
00869             }
00870          }
00871          clearWord(ostr, pos, word, indent);
00872       }
00873 
00874       void formatWord(std::ostream& ostr, int& pos, 
00875                       const std::string& word, int indent) const
00876       {
00877          if (pos + word.length() > _width)
00878          {
00879             ostr << '\n';
00880             pos = 0;
00881             while (pos < indent) { ostr << ' '; ++pos; }
00882          }
00883          ostr << word;
00884          pos += (int) word.length();
00885       }
00886       
00887       void clearWord(std::ostream& ostr, int& pos, 
00888                      std::string& word, int indent) const
00889       {
00890          formatWord(ostr, pos, word, indent);
00891          word.clear();
00892       }
00893 
00894    private:
00895       HelpFormatter(const HelpFormatter&);
00896       
00897       HelpFormatter& operator = (const HelpFormatter&);
00898 
00899       const OptionSet& _options;
00900 
00901       int _width;
00902       int _tabWidth;
00903       int _indent;
00904       
00905       std::string _command;
00906       std::string _usage;
00907       std::string _header;
00908       std::string _footer;
00909 
00910       bool _unixStyle;
00911 
00912    }; // End of class 'HelpFormatter'
00913 
00914 }   // End of namespace gpstk
00915 
00916 
00917 #endif  //GPSTK_OPTION_HPP
00918 

Generated on Tue May 22 03:30:56 2012 for GPS ToolKit Software Library by  doxygen 1.3.9.1