cmdline.cpp

Go to the documentation of this file.
00001 /*
00002  * cmdline.cpp
00003  *
00004  * Copyright 2004  Thomas A. Vaughan
00005  * All rights reserved.
00006  *
00007  *
00008  * Redistribution and use in source and binary forms, with or without
00009  * modification, are permitted provided that the following conditions are met:
00010  *     * Redistributions of source code must retain the above copyright
00011  *       notice, this list of conditions and the following disclaimer.
00012  *     * Redistributions in binary form must reproduce the above copyright
00013  *       notice, this list of conditions and the following disclaimer in the
00014  *       documentation and/or other materials provided with the distribution.
00015  *     * Neither the name of the <organization> nor the
00016  *       names of its contributors may be used to endorse or promote products
00017  *       derived from this software without specific prior written permission.
00018  *
00019  * THIS SOFTWARE IS PROVIDED BY THOMAS A. VAUGHAN ''AS IS'' AND ANY
00020  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
00021  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
00022  * DISCLAIMED. IN NO EVENT SHALL THOMAS A. VAUGHAN BE LIABLE FOR ANY
00023  * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
00024  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
00025  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
00026  * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
00027  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
00028  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
00029  *
00030  *
00031  * Implementation of command line parsing object.
00032  */
00033 
00034 // includes --------------------------------------------------------------------
00035 #include "cmdline.h"            // always include our own header first!
00036 
00037 
00038 // CommandLine interface destructor implementation
00039 CommandLine::~CommandLine(void) throw() { }
00040 
00041 
00042 ////////////////////////////////////////////////////////////////////////////////
00043 //
00044 //      Implementation class
00045 //
00046 ////////////////////////////////////////////////////////////////////////////////
00047 
00048 class CmdImpl : public CommandLine {
00049 public:
00050         // constructor, destructor ---------------------------------------------
00051         ~CmdImpl(void) throw() { }
00052 
00053         // public class methods ------------------------------------------------
00054         void initialize(IN int argc, IN const char * argv[]) throw();
00055 
00056         // CommandLine class interface methods ---------------------------------
00057         virtual void getKeys(OUT VecString& keys) throw();
00058         virtual bool getValues(IN const char * key,
00059                                 OUT VecString& values) throw();
00060 
00061 private:
00062         // private typedefs ----------------------------------------------------
00063         typedef std::map<std::string, VecString> KeyValues;
00064 
00065         // private data members ------------------------------------------------
00066         KeyValues       m_values;
00067 };
00068 
00069 
00070 
00071 ////////////////////////////////////////////////////////////////////////////////
00072 //
00073 //      CmdImpl - public class methods
00074 //
00075 ////////////////////////////////////////////////////////////////////////////////
00076 
00077 void
00078 CmdImpl::initialize
00079 (
00080 IN int argc,
00081 IN const char * argv[]
00082 )
00083 throw()
00084 {
00085         ASSERT(argc > 0, "No arguments at all?");
00086 
00087         VecString * values = NULL;      // current values
00088         for (int i = 1; i < argc; ++i) {
00089                 // look at this argument -- is it a key?
00090                 const char * p = argv[i];
00091                 if (strstr(p, "--") == p) {
00092                         // key!  strip leading dashes, and store
00093                         p += 2; // skip dashes
00094                         KeyValues::iterator x = m_values.find(p);
00095                         if (m_values.end() != x) {
00096                                 ASSERT(false, "Parameter '--%s' is specified "
00097                                     "multiple times on the command line", p);
00098                         }
00099                         VecString empty;
00100                         m_values[p] = empty;
00101                         values = &m_values[p];
00102                         ASSERT(0 == values->size(), "Should be empty");
00103                 } else {
00104                         // must be a value
00105                         if (!values) {
00106                                 ASSERT(false, "Read value '%s' without a key?",
00107                                     p);
00108                         }
00109                         values->push_back(p);
00110                 }
00111         }
00112 }
00113 
00114 
00115 
00116 ////////////////////////////////////////////////////////////////////////////////
00117 //
00118 //      CmdImpl -- CommandLine class interface methods
00119 //
00120 ////////////////////////////////////////////////////////////////////////////////
00121 
00122 void
00123 CmdImpl::getKeys
00124 (
00125 OUT VecString& keys
00126 )
00127 throw()
00128 {
00129         keys.clear();
00130 
00131         for (KeyValues::iterator i = m_values.begin(); i != m_values.end();
00132              ++i) {
00133                 keys.push_back(i->first);
00134         }
00135 }
00136 
00137 
00138 
00139 bool
00140 CmdImpl::getValues
00141 (
00142 IN const char * key,
00143 OUT VecString& values
00144 )
00145 throw()
00146 {
00147         ASSERT(key, "NULL key");
00148 
00149         values.clear();
00150 
00151         KeyValues::iterator i = m_values.find(key);
00152         if (m_values.end() == i) {
00153                 // DPRINTF("No such key found on command line: %s", key);
00154                 return false;
00155         }
00156 
00157         values = i->second;
00158         return true;
00159 }
00160 
00161 
00162 
00163 ////////////////////////////////////////////////////////////////////////////////
00164 //
00165 //      CommandLine -- public static methods (factories)
00166 //
00167 ////////////////////////////////////////////////////////////////////////////////
00168 
00169 smart_ptr<CommandLine>
00170 CommandLine::create
00171 (
00172 IN int argc,
00173 IN const char * argv[]
00174 )
00175 throw()
00176 {
00177         smart_ptr<CmdImpl> local = new CmdImpl;
00178         local->initialize(argc, argv);
00179         return local;
00180 }
00181 
00182 
00183 
00184 ////////////////////////////////////////////////////////////////////////////////
00185 //
00186 //      public API + helpers
00187 //
00188 ////////////////////////////////////////////////////////////////////////////////
00189 
00190 const char *
00191 getSingleKeyValue
00192 (
00193 IN CommandLine * cmd,
00194 IN const char * key,
00195 bool is_required,
00196 const char * description
00197 )
00198 throw()
00199 {
00200         ASSERT(cmd, "null");
00201         ASSERT(key, "null");
00202         IMPLIES(is_required, description, "must have description if required");
00203 
00204         VecString values;
00205         if (!cmd->getValues(key, values)) {
00206                 if (!is_required)
00207                         return NULL;
00208                 ASSERT(false, "Missing required command-line parameter '--%s' "
00209                     "(%s)", key, description);
00210         }
00211 
00212         ASSERT(1 == values.size(),
00213             "Parameter '--%s' can only have 1 value, you have %d",
00214             key, (int) values.size());
00215         return values[0].c_str();
00216 }
00217