00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
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
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 }
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 }
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 }
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
00181
00182 read (tConfigFileIfstream);
00183 }
00184
00185 }
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
00211
00212
00213
00214
00215
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
00238
00239
00240 tCommandLineArgumentsArray.push_back (ppkcParametersList [J]);
00241 }
00242 }
00243 }
00244
00245 }
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
00261
00262 while ( rtSOURCE_ISTREAM.good() )
00263 {
00264
00265
00266
00267 while ( tMatcher.scan ("[[:space:]]*#%t\n", NULL) ) { ++iLineNumber; }
00268 while ( tMatcher.scan ("[[:space:]]*\n", NULL) ) { ++iLineNumber; }
00269
00270
00271
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
00302
00303
00304 if ( tValidNameSpaceSet.find (yOptionNameSpace) != tValidNameSpaceSet.end() )
00305 {
00306 updateOptionWithName (yOptionName, yOptionValue);
00307 }
00308 }
00309 }
00310 }
00311
00312 }
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 }
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 }
00379
00380
00381
00382
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 }
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 }
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 }
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 }
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 }
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 }
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 }
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 }
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 }
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 }