Main Page   Namespace List   Class Hierarchy   Compound List   File List   Namespace Members   Compound Members  

config_processor.cc

00001 /*
00002 *  Name:         config_processor.cc
00003 *  Author:       Rafael Jesus Alcantara Perez
00004 *  Contributor:  Francisco Vides Fernandez
00005 *  Summary:      Config processor
00006 *  Date:         $Date: 2003/04/14 00:18:35 $
00007 *  Revision:     $Revision: 1.1 $
00008 *
00009 *  Copyright (C) 1994-2002  Rafael Jesus Alcantara Perez <rafa@dedalo-ing.com>
00010 *
00011 *  This program is free software; you can redistribute it and/or modify
00012 *  it under the terms of the GNU General Public License as published by
00013 *  the Free Software Foundation; either version 2 of the License, or
00014 *  (at your option) any later version.
00015 *
00016 *  This program is distributed in the hope that it will be useful,
00017 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
00018 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00019 *  GNU General Public License for more details.
00020 *
00021 *  You should have received a copy of the GNU General Public License
00022 *  along with this program; if not, write to the Free Software
00023 *  Foundation, Inc., 59 Temple Place, Suite 330, Boston,
00024 *  MA 02111-1307, USA.
00025 */
00026 
00027 #include <cstdlib>
00028 #include <fstream>
00029 #include <mpcl/system/all.hh>
00030 #include <mpcl/text/regex/matcher.hh>
00031 #include <mpcl/text/string.hh>
00032 #include <mpcl/util/prefs/config_processor.hh>
00033 #include <sstream>
00034 
00035 
00036 //
00037 //  C O N S T R U C T O R S
00038 //
00039 
00040 void mpcl::util::prefs::TConfigProcessor::
00041 addOption (const TString& rkyNAME, const TString& rkySHORTCUT)
00042 {
00043 
00044   using text::Format;
00045 
00046   TString                         yFullName;
00047   TString                         yShortcut (rkySHORTCUT);
00048   TOptionVector::const_iterator   I (tOptionVector.begin());
00049 
00050   if ( yCurrentNameSpace.empty() )
00051   {
00052     yFullName = rkyNAME;
00053   }
00054   else
00055   {
00056     yFullName = yCurrentNameSpace + "." + rkyNAME;
00057   }
00058   yFullName.lowercase();
00059   for (; ( I != tOptionVector.end() ) ;++I)
00060   {
00061     if ( I->name() == yFullName )
00062     {
00063       TString   yMessage (Format ("option name '%s' already defined", yFullName.c_str()));
00064 
00065       throw TOptionAlreadyDefinedException (yMessage, __FILE__, __LINE__);
00066     }
00067     if ( I->shortcut() == yShortcut )
00068     {
00069       TString   yMessage (Format ("option shortcut '%s' already defined", yShortcut.c_str()));
00070 
00071       throw TOptionAlreadyDefinedException (yMessage, __FILE__, __LINE__);
00072     }
00073   }
00074   tOptionVector.push_back (TOption (yFullName, yShortcut));
00075   gOptionsProcessed = false;
00076   
00077 }  // addOption()
00078   
00079 
00080 void mpcl::util::prefs::TConfigProcessor::
00081 addOption ( const TString& rkyNAME     ,
00082             const TString& rkySHORTCUT ,
00083             const TString& rkyVALUE    )
00084 {
00085 
00086   using text::Format;
00087 
00088   TString                         yFullName;
00089   TString                         yShortcut (rkySHORTCUT);
00090   TOptionVector::const_iterator   I (tOptionVector.begin());
00091 
00092   if ( yCurrentNameSpace.empty() )
00093   {
00094     yFullName = rkyNAME;
00095   }
00096   else
00097   {
00098     yFullName = yCurrentNameSpace + "." + rkyNAME;
00099   }
00100   yFullName.lowercase();
00101   for (; ( I != tOptionVector.end() ) ;++I)
00102   {
00103     if ( I->name() == yFullName )
00104     {
00105       TString   yMessage (Format ("option name '%s' already defined", yFullName.c_str()));
00106 
00107       throw TOptionAlreadyDefinedException (yMessage, __FILE__, __LINE__);
00108     }
00109     if ( I->shortcut() == yShortcut )
00110     {
00111       TString   yMessage (Format ("option shortcut '%s' already defined", yShortcut.c_str()));
00112 
00113       throw TOptionAlreadyDefinedException (yMessage, __FILE__, __LINE__);
00114     }
00115   }
00116   tOptionVector.push_back (TOption (yFullName, yShortcut, rkyVALUE));
00117   gOptionsProcessed = false;
00118   
00119 }  // addOption()
00120 
00121 
00122 void mpcl::util::prefs::TConfigProcessor::
00123 addEnvironmentVariable (const char* pkcENVIRONMENT_NAME, bool gREQUIRED)
00124   throw (TVariableNotFoundException)
00125 {
00126 
00127   using std::getenv;
00128   using text::Format;
00129 
00130   if ( !pkcENVIRONMENT_NAME )
00131   {
00132     throw TVariableNotFoundException ("null environment name", __FILE__, __LINE__);
00133   }
00134   else
00135   {
00136     const char*   pkcEnvironmentValue = getenv (pkcENVIRONMENT_NAME);
00137     
00138     if ( pkcEnvironmentValue )
00139     {
00140       tEnvironmentVariableMap.bind (pkcENVIRONMENT_NAME, pkcEnvironmentValue);
00141     }
00142     else
00143     {
00144       if ( gREQUIRED )
00145       {
00146         TString   yMessage;
00147         
00148         yMessage = Format ("environment variable '%s' has null value", pkcENVIRONMENT_NAME);
00149         throw TVariableNotFoundException (yMessage, __FILE__, __LINE__);
00150       }
00151       else
00152       {
00153         tEnvironmentVariableMap.bind (pkcENVIRONMENT_NAME, "");
00154       }
00155     }
00156   }
00157   
00158 }  // addEnvironmentVariable()
00159 
00160 
00161 void mpcl::util::prefs::TConfigProcessor::
00162 processConfigFile (void)
00163 {
00164 
00165   using text::Format;
00166 
00167   if ( gInputConfigFile )
00168   {
00169     std::basic_ifstream<char>   tConfigFileIfstream (yConfigFileName.c_str());
00170 
00171     if ( !tConfigFileIfstream.is_open() )
00172     {
00173       TString   yMessage;
00174       
00175       yMessage = Format ("couldn't open file '%s'", yConfigFileName.c_str());
00176       throw TFileErrorException (yMessage, __FILE__, __LINE__);
00177     }
00178     
00179     //
00180     //  Load parameter values from configuration file.
00181     //
00182     read (tConfigFileIfstream);
00183   }
00184   
00185 }  // processConfigFile()
00186 
00187 
00188 void mpcl::util::prefs::TConfigProcessor::
00189 processCommandLine (void)
00190 {
00191 
00192   using text::regex::TMatcher;
00193 
00194   if ( iParametersCount )
00195   {
00196     TString    yOptionName;
00197     TString    yOptionShortcut;
00198     TString    yOptionValue;
00199     TMatcher   tMatcher;
00200     
00201     for (register int J = 1; ( J < iParametersCount ) ;++J)
00202     {
00203       std::basic_istringstream<char_type>   tCurrentOption (ppkcParametersList [J]);
00204       
00205       yOptionName.erase();
00206       yOptionShortcut.erase();
00207       yOptionValue.erase();
00208       
00209       //
00210       //  Warning:  There should exists better support
00211       //            from TMatcher.
00212       //
00213 
00214       //
00215       //  Scan option.
00216       //
00217       tMatcher.setInput (tCurrentOption);
00218       if ( tMatcher.scan ("--%s=%t", &yOptionName, &yOptionValue, NULL) )
00219       {
00220         updateOptionWithName (yOptionName, yOptionValue).setCmdLinePresence();
00221       }
00222       else if ( tMatcher.scan ("-%s=%t", &yOptionShortcut, &yOptionValue, NULL) )
00223       {
00224         updateOptionWithShortcut (yOptionShortcut, yOptionValue).setCmdLinePresence();
00225       }
00226       else if ( tMatcher.scan ("--%s", &yOptionName, NULL) )
00227       {
00228         optionWithName (yOptionName).setCmdLinePresence();
00229       }
00230       else if ( tMatcher.scan ("-%s", &yOptionShortcut, NULL) )
00231       {
00232         optionWithName (nameForShortcut (yOptionShortcut)).setCmdLinePresence();
00233       }
00234       else
00235       {
00236         //
00237         //  Add to "tCommandLineArgumentsArray" all the arguments 
00238         //  (not options) passed to the user of the instance.
00239         //
00240         tCommandLineArgumentsArray.push_back (ppkcParametersList [J]);
00241       }
00242     }
00243   }
00244   
00245 }  // processCommandLine()
00246 
00247 
00248 void mpcl::util::prefs::TConfigProcessor::
00249 read (std::basic_istream<char_type, traits_type>& rtSOURCE_ISTREAM)
00250 {
00251 
00252   using text::regex::TMatcher;
00253 
00254   TString    yOptionName;
00255   TString    yOptionValue;
00256   TMatcher   tMatcher (rtSOURCE_ISTREAM);
00257   int        iLineNumber = 1;
00258   
00259   //
00260   //  Parses every option (removing comments).
00261   //
00262   while ( rtSOURCE_ISTREAM.good() )
00263   {
00264     //
00265     //  Removes preceding comments and spaces.
00266     //
00267     while ( tMatcher.scan ("[[:space:]]*#%t\n", NULL) ) { ++iLineNumber; }
00268     while ( tMatcher.scan ("[[:space:]]*\n",    NULL) ) { ++iLineNumber; }
00269 
00270     //
00271     //  Scan option.
00272     //
00273     if ( !tMatcher.scan ( "[[:space:]]*%s[[:blank:]]*=[[:blank:]]*%t[[:blank:]]*\n" ,
00274                           &yOptionName                                              ,
00275                           &yOptionValue                                             ,
00276                           NULL                                                      ) )
00277     {
00278       if ( rtSOURCE_ISTREAM.peek() == EOF )
00279       {
00280         break;
00281       }
00282       else
00283       {
00284         throw TParseErrorException (NULL, yConfigFileName, iLineNumber);
00285       }
00286     }
00287     else
00288     {
00289       TString   yOptionNameSpace;
00290 
00291       ++iLineNumber;
00292       yOptionName.lowercase();
00293       yOptionNameSpace = nameSpace (yOptionName);
00294       if ( yOptionNameSpace.empty() )
00295       {
00296         updateOptionWithName (yOptionName, yOptionValue);
00297       }
00298       else
00299       {
00300         //
00301         //  If the name space is in the  valid name space set,  then it inserts
00302         //  the option, else it simply ignores it.
00303         //
00304         if ( tValidNameSpaceSet.find (yOptionNameSpace) != tValidNameSpaceSet.end() )
00305         {
00306           updateOptionWithName (yOptionName, yOptionValue);
00307         }
00308       }
00309     }
00310   }
00311   
00312 }  // read()
00313 
00314 
00315 mpcl::util::prefs::TOption& mpcl::util::prefs::TConfigProcessor::
00316 updateOptionWithName ( const TString& rkyNAME  ,
00317                        const TString& rkyVALUE )
00318 {
00319 
00320   using std::vector;
00321   using text::Format;
00322 
00323   bool                            gFound = false;
00324   TOptionVector::iterator         I      = tOptionVector.begin();
00325   TOptionVector::const_iterator   ktEnd  = tOptionVector.end();
00326   
00327   for (; ( I != ktEnd ) ;++I)
00328   {
00329     if ( I->name() == rkyNAME )
00330     {
00331       I->addValue (rkyVALUE);
00332       gFound = true;
00333       break;
00334     }
00335   }
00336   if ( !gFound )
00337   {
00338     TString   yMessage;
00339     
00340     yMessage = Format ("option '%s' not found", rkyNAME.c_str());
00341     throw TVariableNotFoundException (yMessage, __FILE__, __LINE__);
00342   }
00343   return *I;
00344 
00345 }  // updateOptionWithName()
00346 
00347 
00348 mpcl::util::prefs::TOption& mpcl::util::prefs::TConfigProcessor::
00349 updateOptionWithShortcut ( const TString& rkySHORTCUT ,
00350                            const TString& rkyVALUE    )
00351 {
00352 
00353   using std::vector;
00354   using text::Format;
00355   
00356   bool                            gFound = false;
00357   TOptionVector::iterator         I      = tOptionVector.begin();
00358   TOptionVector::const_iterator   ktEnd  = tOptionVector.end();
00359   
00360   for (; ( I != ktEnd ) ;++I)
00361   {
00362     if ( I->shortcut() == rkySHORTCUT )
00363     {
00364       I->addValue (rkyVALUE);
00365       gFound = true;
00366       break;
00367     }
00368   }
00369   if ( !gFound )
00370   {
00371     TString   yMessage;
00372     
00373     yMessage = Format ("option '%s' not found", rkySHORTCUT.c_str());
00374     throw TVariableNotFoundException (yMessage, __FILE__, __LINE__);
00375   }
00376   return *I;
00377 
00378 }  // updateOptionWithShortcut()
00379 
00380 
00381 //
00382 //  S E L E C T O R S
00383 //
00384 
00385 unsigned int mpcl::util::prefs::TConfigProcessor::longestOptionLength() const
00386 {
00387 
00388   using std::vector;
00389 
00390   unsigned int                    uiRet;
00391   TOptionVector::const_iterator   I     = tOptionVector.begin();
00392   TOptionVector::const_iterator   ktEnd = tOptionVector.end();
00393 
00394   for (uiRet = I->name().length(); I != ktEnd ;++I)
00395   {
00396     if ( uiRet < I->name().length() )
00397     {
00398       uiRet = I->name().length();
00399     }
00400   }  
00401   return uiRet;
00402 
00403 }  // longestOptionLength()
00404 
00405 
00406 mpcl::text::TString mpcl::util::prefs::TConfigProcessor::
00407 nameForShortcut (const TString& rkySHORTCUT) const
00408 {
00409   
00410   using std::vector;
00411 
00412   TString                         yResultName;
00413   TOptionVector::const_iterator   I     = tOptionVector.begin();
00414   TOptionVector::const_iterator   ktEnd = tOptionVector.end();
00415   
00416   for (; I != ktEnd ;++I)
00417   {
00418     if ( I->shortcut() == rkySHORTCUT )
00419     {
00420       yResultName = I->name();
00421       break;
00422     }
00423   }
00424   return yResultName;
00425   
00426 }  // nameForShortCut()
00427 
00428 
00429 mpcl::text::TString mpcl::util::prefs::TConfigProcessor::nameSpace (const TString& rkyNAME) const
00430 {
00431 
00432   TString              yNameSpace;
00433   TString::size_type   zPosition = rkyNAME.rfind ('.');
00434 
00435   if ( zPosition != TString::npos )
00436   {
00437     yNameSpace = rkyNAME.substr (0, zPosition);
00438   }
00439   return yNameSpace;
00440 
00441 }  // nameSpace()
00442 
00443 
00444 const mpcl::util::prefs::TOption& mpcl::util::prefs::TConfigProcessor::operator [] (const char* pkcNAME) const
00445   throw (TVariableNotFoundException)
00446 {
00447   
00448   using std::vector;
00449   using text::Format;
00450 
00451   TOptionVector::const_iterator   I     = tOptionVector.begin();
00452   TOptionVector::const_iterator   ktEnd = tOptionVector.end();
00453   
00454   for (; ( I != ktEnd ) ;++I)
00455   {
00456     if ( I->name() == pkcNAME )
00457     {
00458       break;
00459     } 
00460   }
00461   if ( I == ktEnd )
00462   {
00463     TString   yMessage;
00464     
00465     yMessage = Format ("option '%s' not found", pkcNAME);
00466     throw TVariableNotFoundException (yMessage, __FILE__, __LINE__);
00467   }
00468   return *I;
00469   
00470 }  // operator []()
00471 
00472 
00473 mpcl::util::prefs::TOption& mpcl::util::prefs::TConfigProcessor::
00474 operator [] (const char* pkcNAME)
00475   throw (TVariableNotFoundException)
00476 {
00477   
00478   using text::Format;
00479 
00480   TOptionVector::iterator         I     = tOptionVector.begin();
00481   TOptionVector::const_iterator   ktEnd = tOptionVector.end();
00482   
00483   for (; ( I != ktEnd ) ;++I)
00484   {
00485     if ( I->name() == pkcNAME )
00486     {
00487       break;
00488     } 
00489   }
00490   if ( I == ktEnd )
00491   {
00492     TString   yMessage;
00493     
00494     yMessage = Format ("option '%s' not found", pkcNAME);
00495     throw TVariableNotFoundException (yMessage, __FILE__, __LINE__);
00496   }
00497   return *I;
00498   
00499 }  // operator []()
00500 
00501 
00502 mpcl::text::TString mpcl::util::prefs::TConfigProcessor::
00503 formatUsageString (void) const
00504 {
00505 
00506   using std::vector;
00507   
00508   int                             iCurrentPadding;
00509   TString                         yPadding;
00510   TString                         yRet;
00511   TOptionVector::const_iterator   I             = tOptionVector.begin();
00512   TOptionVector::const_iterator   ktEnd         = tOptionVector.end();
00513   const int                       kiPaddingSize = longestOptionLength() + _kuiMinPadding;  
00514 
00515   yRet += yUsageHeader + '\n';
00516   do
00517   {
00518     iCurrentPadding = kiPaddingSize - I->name().length();
00519     yPadding.assign (iCurrentPadding, ' ');
00520     yRet += "  -" + I->shortcut() + ", --" + I->name() + yPadding + I->help() + '\n';
00521     I++;
00522   } while ( I != ktEnd );
00523   yRet += '\n';
00524   return yRet;
00525 
00526 }  // formatUsageString()
00527 
00528 
00529 const mpcl::text::TString mpcl::util::prefs::TConfigProcessor::
00530 programFileName (void) const
00531 {
00532 
00533   using system::tSystem;
00534 
00535   TString   yProgramFileName;
00536   
00537   if ( ppkcParametersList )
00538   {
00539     size_type   zSeparatorOffset;
00540     
00541     yProgramFileName = ppkcParametersList [0];
00542     zSeparatorOffset = yProgramFileName.rfind (tSystem.getDirectorySeparator());
00543     if ( TString::npos != zSeparatorOffset )
00544     {
00545       yProgramFileName = yProgramFileName.substr (zSeparatorOffset + 1);
00546     }
00547   }
00548   return yProgramFileName;
00549   
00550 }  // programFileName()
00551 
00552 
00553 void mpcl::util::prefs::TConfigProcessor::saveConfigFile (void) const
00554   throw (TFileErrorException)
00555 {
00556 
00557   using std::ofstream;
00558   using text::Format;
00559 
00560   ofstream   tConfigFileOfstream;
00561   
00562   tConfigFileOfstream.open (yConfigFileName.c_str());
00563   if ( tConfigFileOfstream.is_open() )
00564   {
00565     write (tConfigFileOfstream);
00566   }
00567   else
00568   {
00569     TString   yMessage;
00570     
00571     yMessage = Format ("couldn't write file '%s'", yConfigFileName.c_str());
00572     throw TFileErrorException (yMessage, __FILE__, __LINE__);
00573   }
00574   tConfigFileOfstream.close();
00575   
00576 }  // saveConfigFile()
00577 
00578 
00579 mpcl::text::TString mpcl::util::prefs::TConfigProcessor::
00580 shortcutForName (const TString& rkyNAME) const
00581 {
00582   
00583   using std::vector;
00584 
00585   TString                         yResultName;
00586   TOptionVector::const_iterator   I     = tOptionVector.begin();
00587   TOptionVector::const_iterator   ktEnd = tOptionVector.end();
00588   
00589   for (; ( I != ktEnd ) ;++I)
00590   {
00591     if ( I->name() == rkyNAME )
00592     {
00593       yResultName = I->shortcut();
00594       break;
00595     }
00596   }
00597   return yResultName;
00598   
00599 }  // shortCutForName()
00600 
00601 
00602 void mpcl::util::prefs::TConfigProcessor::
00603 write (std::basic_ostream<char_type, traits_type>& rtTARGET_OSTREAM) const
00604 {
00605 
00606   using std::vector;
00607 
00608   TOptionVector::const_iterator   I     = tOptionVector.begin();
00609   TOptionVector::const_iterator   ktEnd = tOptionVector.end();
00610 
00611   for (; ( I != ktEnd ) ;++I)
00612   {
00613     if ( I->isParameterAble() )
00614     {
00615       rtTARGET_OSTREAM << *I;
00616     }
00617   }
00618   
00619 }  // write()

Generated on Mon Oct 13 02:35:22 2003 for MPCL by doxygen1.2.18