Main Page | Class List | File List | Class Members | File Members

ProgramOptions.cpp

Go to the documentation of this file.
00001 // ProgramOptions.cpp
00002 
00003 #include "ProgramOptions.h"
00004 #include "format_paragraph.h"
00005 #include <iostream>
00006 #include <sstream>
00007 
00008 std::ostream& operator<<(std::ostream& os, const ProgramOption& po)
00009 {
00010   os << "Option '" << po.GetShortOption() << "' or '" << po.GetLongOption() << "'";
00011   if (po.IsCaseSensitive())
00012     os << " (case sensitive)";
00013   switch(po.GetType())
00014   {
00015   case ProgramOption::opt_boolean:
00016     os << " with";
00017     if (!po.IsDefined())
00018       os << " default";
00019     os << " boolean value " << po.GetBoolValue();
00020     break;
00021   case ProgramOption::opt_string:
00022     os << " with";
00023     if (!po.IsDefined())
00024       os << " default";
00025     os << " string value '" << po.GetStringValue() << "'";
00026     break;
00027   case ProgramOption::opt_long:
00028     os << " with";
00029     if (!po.IsDefined())
00030       os << " default";
00031     os << " long value " << po.GetLongValue();
00032     os << " (" << po.GetLongValueMin() << ", " << po.GetLongValueMax() << ")";
00033     break;
00034   }  
00035   return os;
00036 }
00037 
00038 ProgramOptions::ProgramOptions()
00039 {
00040   m_sOptionChars = "-/";
00041 }
00042 
00043 ProgramOptions::~ProgramOptions()
00044 {
00045    for (option_iterator i = m_options.begin(); i != m_options.end(); ++i)
00046     delete *i;
00047   m_options.clear();
00048 }
00049 
00050 void ProgramOptions::AddBoolean(
00051     char cShortOption, const char* pszLongOption, bool bDefault,
00052     bool bCaseSensitive, const char* pszHelpText)
00053   {
00054     ProgramOption* po =
00055       new ProgramOption(
00056         cShortOption,
00057         pszLongOption,
00058         ProgramOption::opt_boolean,
00059         false
00060       );
00061     po->m_bValue = bDefault;
00062     po->m_bCaseSensitive = bCaseSensitive;
00063     safe_assign(po->m_sHelpText, pszHelpText);
00064     Add(po);
00065   }
00066   
00067 void ProgramOptions::AddString(
00068     char cShortOption, const char* pszLongOption, const char* pszDefault,
00069     bool bCaseSensitive,
00070     const char* pszParameterHint, const char* pszHelpText)
00071   {
00072     ProgramOption* po =
00073       new ProgramOption(
00074         cShortOption,
00075         pszLongOption,
00076         ProgramOption::opt_string,
00077         true
00078       );
00079     safe_assign(po->m_sValue, pszDefault);
00080     po->m_bCaseSensitive = bCaseSensitive;
00081     safe_assign(po->m_sHelpText, pszHelpText);
00082     safe_assign(po->m_sParameterHint, pszParameterHint);
00083     Add(po);
00084   }
00085   
00086 void ProgramOptions::AddLong(
00087     char cShortOption, const char* pszLongOption, long lDefault,
00088     long lMin, long lMax,
00089     bool bCaseSensitive,
00090     const char* pszParameterHint, const char* pszHelpText)
00091   {
00092     ProgramOption* po =
00093       new ProgramOption(
00094         cShortOption,
00095         pszLongOption,
00096         ProgramOption::opt_long,
00097         true
00098       );
00099     po->m_lValue = lDefault;
00100     po->m_lMinValue = lMin;
00101     po->m_lMaxValue = lMax;
00102     po->m_bCaseSensitive = bCaseSensitive;
00103     safe_assign(po->m_sHelpText, pszHelpText);
00104     safe_assign(po->m_sParameterHint, pszParameterHint);
00105     Add(po);
00106   }
00107 
00108   void ProgramOptions::PrintHelp(std::ostream& os, int width) const
00109   {
00110     char optchar = m_sOptionChars[0];
00111     for (ProgramOptions::const_option_iterator o = options_begin(); o != options_end(); ++o)
00112     {
00113       const ProgramOption& po = **o;
00114       if (po.HasShortOption())
00115       {
00116         os << optchar << po.GetShortOption();
00117         if (po.HasParameter() && !po.GetParameterHint().empty())
00118           os << " " << po.GetParameterHint();
00119       }
00120       if (po.HasLongOption())
00121       {
00122         if (po.HasShortOption())
00123           os << ", ";
00124         os << optchar << po.GetLongOption() << " ";
00125         if (po.HasParameter() && !po.GetParameterHint().empty())
00126           os << po.GetParameterHint();
00127       }
00128       os << std::endl;
00129       os << format_paragraph(po.GetHelpText().c_str(), 2, width-1);
00130     }
00131   }
00132 
00133 void ProgramOptions::Add(ProgramOption* pOption)
00134 {
00135   m_options.push_back(pOption);
00136 }
00137 
00138 void ProgramOptions::AddParameter(const char* psz)
00139 {
00140   std::string s;
00141   safe_assign(s, psz);
00142   m_parameters.push_back(s);
00143 }
00144 
00145 bool ProgramOptions::IsOptionChar(char c) const
00146 {
00147   return (m_sOptionChars.find(c) != std::string::npos);
00148 }
00149 
00150 ProgramOption* ProgramOptions::GetOption(char c) const
00151 {
00152   for (const_option_iterator i = options_begin(); i != options_end(); ++i)
00153   {
00154     ProgramOption* pOption = *i;
00155     if (pOption->IsOption(c))
00156       return pOption;
00157   }
00158   return 0;
00159 }
00160  
00161 ProgramOption* ProgramOptions::GetOption(const char* psz) const
00162 {
00163   for (const_option_iterator i = options_begin(); i != options_end(); ++i)
00164   {
00165     ProgramOption* pOption = *i;
00166     if (pOption->IsOption(psz))
00167       return pOption;
00168   }
00169   return 0;
00170 }
00171 
00172 std::string ProgramOptions::GetStringParameter(const char* psz) const
00173 {
00174   std::string s;
00175   size_t len = strlen(psz);
00176   if (len > 2)
00177   {
00178     const char* pszLast = psz + len-1;
00179     if (*psz == '\"' && *pszLast == '\"')
00180       s.assign(psz+1, len-2);
00181     else
00182       s.assign(psz, len);
00183   }
00184   else
00185   {
00186     safe_assign(s, psz);
00187   }
00188   return s;
00189 }
00190 
00191 bool ProgramOptions::Parse(int argc, char* argv[], std::locale loc)
00192 {
00193   ProgramOption* pParameterOption = 0;
00194   for (int arg = 1; arg < argc; ++arg)
00195   {
00196     char optChar = argv[arg][0];
00197     if (IsOptionChar(optChar) && !pParameterOption)
00198     {
00199       // This is one or more options
00200       const char* pszOption = &argv[arg][1];
00201       ProgramOption* pOption = GetOption(pszOption);
00202       if (pOption)
00203       {
00204         if (pOption->HasParameter())
00205           pParameterOption = pOption;
00206         else
00207           pOption->SetBoolValue();
00208       }
00209       else
00210       {
00211         // Try each character as an option
00212         bool bFoundSomething = false;
00213         for (char* pOpt = &argv[arg][1]; *pOpt; ++pOpt)
00214         {
00215           pOption = GetOption(*pOpt);
00216           if (pOption)
00217           {
00218             bFoundSomething = true;
00219             if (pOption->HasParameter())
00220             {
00221               if (!pParameterOption)
00222               {
00223                 pParameterOption = pOption;
00224               }
00225               else
00226               {
00227                 std::cerr << "Invalid usage of two options with parameters in " << argv[arg] << std::endl;
00228                 return false;
00229               }
00230             }
00231             else
00232               pOption->SetBoolValue();
00233           }
00234         }
00235         if (!bFoundSomething)
00236         {
00237           std::cerr << "Unknown option " << argv[arg] << std::endl;
00238           return false;
00239         }
00240       }
00241     }
00242     else
00243     {
00244       // This is a parameter or a an option value
00245       if (pParameterOption)
00246       {
00247         switch (pParameterOption->GetType())
00248         {
00249         case ProgramOption::opt_long:
00250           {
00251           std::istringstream is(argv[arg]);
00252           is.imbue(loc);
00253           long l;
00254           is >> l;
00255           // Stream should not have errors and no characters left
00256           if (!(!is.fail() && !is.good() && pParameterOption->SetLongValue(l)))
00257           {
00258             std::cerr << "Invalid parameter : " << argv[arg] << std::endl;
00259             std::cerr << "for " << *pParameterOption << std::endl;
00260             return false;
00261           }
00262           }
00263           break;
00264         case ProgramOption::opt_string:
00265           pParameterOption->SetStringValue(GetStringParameter(argv[arg]).c_str());
00266           break;
00267         }
00268       }
00269       else
00270       {
00271         AddParameter(GetStringParameter(argv[arg]).c_str());
00272       }
00273       pParameterOption = 0;
00274     }
00275   }
00276   // Last parameter should be used by now
00277   if (pParameterOption)
00278   {
00279     std::cerr << "Missing parameter for " << *pParameterOption << std::endl;
00280     return false;
00281   }
00282   return true;
00283 }
00284 
00285 bool ProgramOptions::GetBoolValue(char option) const
00286 {
00287   ProgramOption* pOption = GetOption(option);
00288   if (pOption)
00289     return pOption->GetBoolValue();
00290   else
00291     return false;
00292 }
00293 
00294 bool ProgramOptions::GetBoolValue(const char* pszOption) const
00295 {
00296   ProgramOption* pOption = GetOption(pszOption);
00297   if (pOption)
00298     return pOption->GetBoolValue();
00299   else
00300     return false;
00301 }
00302 
00303 long ProgramOptions::GetLongValue(char option) const
00304 {
00305   ProgramOption* pOption = GetOption(option);
00306   if (pOption)
00307     return pOption->GetLongValue();
00308   else
00309     return 0;
00310 }
00311 
00312 long ProgramOptions::GetLongValue(const char* pszOption) const
00313 {
00314   ProgramOption* pOption = GetOption(pszOption);
00315   if (pOption)
00316     return pOption->GetLongValue();
00317   else
00318     return 0;
00319 }
00320 
00321 std::string ProgramOptions::GetStringValue(char option) const
00322 {
00323   ProgramOption* pOption = GetOption(option);
00324   if (pOption)
00325     return pOption->GetStringValue();
00326   else
00327     return "";
00328 }
00329 
00330 std::string ProgramOptions::GetStringValue(const char* pszOption) const
00331 {
00332   ProgramOption* pOption = GetOption(pszOption);
00333   if (pOption)
00334     return pOption->GetStringValue();
00335   else
00336     return "";
00337 }
00338 
00339 std::ostream& operator<<(std::ostream& os, const ProgramOptions& pos)
00340 {
00341   for (ProgramOptions::const_option_iterator o = pos.options_begin(); o != pos.options_end(); ++o)
00342     os << **o << std::endl;
00343   os << (unsigned long)pos.m_parameters.size() << " parameters:" << std::endl;
00344   for (ProgramOptions::const_parameter_iterator p = pos.parameter_begin(); p != pos.parameter_end(); ++p)
00345     os << *p << std::endl;
00346   return os;
00347 }
00348 
00349 
00350 #ifdef _DEBUG
00351 void test_programoptions()
00352 {
00353   ProgramOptions po1;
00354   po1.AddBoolean('q', "quiet", false);
00355   po1.AddLong('w', "timeout", 1000, 0);
00356   po1.AddLong('p', "pause", 1000, 0);
00357   po1.AddString('o', "outputfile");
00358   po1.AddString('g', "targetfile");
00359   char* t1[] = {
00360     "dummy",
00361     "-timeout",
00362     "999",
00363     "-p",
00364     "500",
00365     "-qo",
00366     "\"C:\\Documents and Settings\\erik\\My Documents\"",
00367     "localhost"
00368   };
00369   po1.Parse(8, t1);
00370   std::cout << po1 << std::endl;
00371   
00372   ProgramOptions po2;
00373   po2.AddBoolean('q', "quiet", false);
00374   po2.AddLong('w', "timeout", 1000, 0);
00375   po2.AddLong('p', "pause", 1000, 0);
00376   po2.AddString('o', "outputfile");
00377   po2.AddString('g', "targetfile");
00378   po2.AddLong('l', "longlimittest1", 1, 1, 5);
00379   po2.AddLong('L', "longlimittest2", 1, 1, 5, true);
00380   char* t2[] = {
00381     "dummy",
00382     "-qp",
00383     "1234",
00384     "-Lq",
00385     "3",
00386     "-longlimittest",
00387     "6"
00388   };
00389   po2.Parse(7, t2);
00390   std::cout << po2 << std::endl;
00391 
00392   ProgramOptions po3;
00393   po3.AddBoolean('q', "quiet", false);
00394   po3.AddLong('w', "timeout", 1000, 0);
00395   po3.AddLong('p', "pause", 1000, 0);
00396   po3.AddString('o', "outputfile");
00397   po3.AddString('g', "targetfile");
00398   char* t3[] = {
00399     "dummy",
00400     "-p",
00401     "1,4"
00402   };
00403   po3.Parse(3, t3);
00404   std::cout << po3 << std::endl;
00405 
00406   ProgramOptions po4;
00407   po4.AddBoolean('q', "quiet", false);
00408   po4.AddLong('w', "timeout", 1000, 0);
00409   po4.AddLong('p', "pause", 1000, 0);
00410   po4.AddString('o', "outputfile");
00411   po4.AddString('g', "targetfile");
00412   char* t4[] = {
00413     "dummy",
00414     "-p"
00415   };
00416   po4.Parse(2, t4);
00417   std::cout << po4 << std::endl;
00418 
00419   ProgramOptions po5;
00420   po5.AddBoolean('q', "quiet", false);
00421   po5.AddLong('w', "timeout", 1000, 0);
00422   po5.AddLong('p', "pause", 1000, 0);
00423   po5.AddString('o', "outputfile");
00424   po5.AddString('g', "targetfile");
00425   char* t5[] = {
00426     "dummy",
00427     "-pqw",
00428     "1234"
00429   };
00430   po5.Parse(3, t5);
00431   std::cout << po5 << std::endl;
00432 
00433   ProgramOptions po6;
00434   po6.AddBoolean(
00435     'q', "quiet",
00436     false, false,
00437     "Quiet operation. Only errors are sent to console."
00438   );
00439   po6.AddLong(
00440     'w', "timeout",
00441     1000, 0, LONG_MAX,
00442     false,
00443     "ms", "Time in milliseconds to wait while sending to and receiving from targets."
00444   );
00445   po6.AddLong('\0', "pause",
00446     1000, 0, LONG_MAX,
00447     false,
00448     "ms", "Time in milliseconds to pause between sending to and receiving from all targets."
00449   );
00450   po6.AddString(
00451     'o', "outputfile",
00452     0, false,
00453     "filename", ""
00454   );
00455   po6.AddString(
00456     'g', "targetfile",
00457     0, false,
00458     "filename", "Reads targets from file with one target per line. Targets in file are added to targets specified as parameters."
00459   );
00460   po6.PrintHelp(std::cout);
00461 }
00462 
00463 /*
00464 int main(int argc, char* argv[])
00465 {
00466   test_programoptions();
00467 }
00468 */
00469 #endif // _DEBUG

Generated on Sun Jun 26 13:43:46 2005 for pingem by  doxygen 1.4.3