00001 #include <map>
00002 #include <iomanip>
00003
00004 #include "TBuffer.h"
00005 #include "TObject.h"
00006
00007 #include "Registry.h"
00008 #include "RegistryItem.h"
00009
00010 #include <Util/UtilStream.h>
00011 using namespace Util;
00012
00013 #include <MessageService/MsgService.h>
00014 CVSID("$Id: Registry.cxx,v 1.48 2006/10/23 16:13:14 bv Exp $");
00015
00016 #include <typeinfo>
00017 #include <iostream>
00018 #include <sstream>
00019 #include <cassert>
00020 using namespace std;
00021
00022 ClassImp(Registry)
00023
00024
00025
00026
00027
00028 Registry::Registry(bool readonly )
00029 : fValuesLocked(readonly),
00030 fKeysLocked(false),
00031 fErrorHandler(0)
00032 {
00033 MSG("Registry",Msg::kVerbose) << "Creating Registry at " << (void * ) this << endl;
00034 this->SetDirty();
00035 }
00036
00037
00038 Registry::Registry(const Registry& rhs) : TNamed(rhs)
00039 {
00040 MSG("Registry",Msg::kVerbose) << "Creating Registry at " << (void * ) this << endl;
00041 RegistryKey rk = rhs.Key();
00042 const char* s;
00043
00044 while ( (s = rk()) ) fMap[s] = rhs.fMap.find(s)->second->Dup();
00045
00046 fValuesLocked = rhs.fValuesLocked;
00047 fKeysLocked = rhs.fKeysLocked;
00048 this->SetDirty();
00049 this->SetName(rhs.GetName());
00050 }
00051
00052 Registry& Registry::operator=(const Registry& rhs)
00053 {
00054 if (this == &rhs) return *this;
00055
00056 UnLockValues();
00057 UnLockKeys();
00058
00059
00060 if (Size() != 0) Clear();
00061
00062 RegistryKey rk = rhs.Key();
00063 const char* s;
00064
00065 while ( (s = rk()) ) fMap[s] = rhs.fMap.find(s)->second->Dup();
00066
00067 fValuesLocked = rhs.fValuesLocked;
00068 fKeysLocked = rhs.fKeysLocked;
00069 this->SetDirty();
00070 this->SetName(rhs.GetName());
00071
00072
00073 return *this;
00074 }
00075
00076 void Registry::Merge(const Registry& rhs)
00077 {
00078 if (this == &rhs) return;
00079
00080 RegistryKey rk = rhs.Key();
00081 const char* s;
00082 while ( (s = rk()) ) {
00083 tRegMap::iterator mit = fMap.find(s);
00084 bool exists = mit != fMap.end();
00085
00086 if (fKeysLocked && !exists) {
00087 MSG("Registry",Msg::kWarning)
00088 << "Merge: can't, add new key " << s <<", keys locked."
00089 << " merger=" << this->GetName()
00090 << ", mergie=" << rhs.GetName() << endl;
00091 continue;
00092 }
00093 if (exists && fValuesLocked) {
00094 MSG("Registry",Msg::kWarning)
00095 << "Merge: can't, merge key " << s <<", values locked."
00096 << " merger=" << this->GetName()
00097 << ", mergie=" << rhs.GetName() << endl;
00098 continue;
00099 }
00100 if (exists) delete mit->second;
00101 fMap[s] = rhs.fMap.find(s)->second->Dup();
00102 }
00103 this->SetDirty();
00104 }
00105
00106 bool Registry::KeyExists(const char* key) const
00107 {
00108 return fMap.find(key) != fMap.end();
00109 }
00110
00111 void Registry::RemoveKey(const char* key)
00112 {
00113 tRegMap::iterator dead = fMap.find(key);
00114 if (dead == fMap.end()) return;
00115 fMap.erase(dead);
00116 delete dead->second;
00117 this->SetDirty();
00118 }
00119
00120 void Registry::Clear(Option_t * )
00121 {
00122 if (fValuesLocked || fKeysLocked) {
00123 MSG("Registry",Msg::kWarning)
00124 << "Clear: can't, there are locks in \""
00125 << this->GetName() << "\"\n";
00126 return;
00127 }
00128
00129 tRegMap::iterator mit = fMap.begin();
00130 while (mit != fMap.end()) {
00131 delete mit->second;
00132 ++mit;
00133 }
00134 fMap.clear();
00135 this->SetDirty();
00136 }
00137
00138 void Registry::Dump(void) const
00139 {
00140 this->TNamed::Dump();
00141 tRegMap::const_iterator mit = fMap.begin();
00142 MSG("Registry",Msg::kInfo)
00143 << "Registry: `" << this->GetName() << "', "
00144 << this->Size() << " entries."
00145 << " (Locks: [Keys|Values] `key', `value'):\n";
00146 while (mit != fMap.end()) {
00147 MSG("Registry",Msg::kInfo)
00148 << " [" << (fKeysLocked ? 'L' : 'U') << "|"
00149 << (fValuesLocked ? 'L' : 'U') << "] "
00150 << "`" << mit->first << "', `";
00151 mit->second->Dump();
00152 MSG("Registry",Msg::kInfo) << "'\n";
00153 ++mit;
00154 }
00155
00156 }
00157
00158 ostream& Registry::PrettyPrint(ostream& os) const
00159 {
00160 static int print_depth = 0;
00161
00162
00163 tRegMap::const_iterator mit = this->fMap.begin();
00164 for(int i=0; i<print_depth; ++i) os << " ";
00165 os << "\"" << this->GetName() << "\", "
00166 << this->Size() << " entries."
00167 << " keys " << (this->fKeysLocked ? "locked" : "unlocked")
00168 << ", values " << (this->fValuesLocked ? "locked" : "unlocked")
00169 << "\n";
00170
00171 print_depth+=4;
00172 while (mit != this->fMap.end()) {
00173 for(int i=0; i<print_depth; ++i) os << " ";
00174
00175 os << mit->first << " = ";
00176 mit->second->PrintStream(os);
00177 os << endl;
00178 ++mit;
00179 }
00180 print_depth-=4;
00181 return os;
00182 }
00183
00184 void Registry::Print(Option_t* ) const
00185 {
00186 this->PrettyPrint(cout);
00187 }
00188
00189
00190 Registry::~Registry()
00191 {
00192 tRegMap::iterator mit = fMap.begin();
00193 while (mit != fMap.end()) {
00194 delete mit->second;
00195 ++mit;
00196 }
00197 }
00198
00199 Registry::RegistryKey::RegistryKey(const Registry* r) :
00200 fReg(r)
00201 {
00202
00203
00204 fIt = const_cast<Registry*>(fReg)->fMap.begin();
00205 }
00206
00207 Registry::RegistryKey::RegistryKey()
00208 {
00209 }
00210
00211 Registry::RegistryKey::~RegistryKey()
00212 {
00213 }
00214
00215 const char* Registry::RegistryKey::operator()(void)
00216 {
00217 if (fIt == fReg->fMap.end()) return 0;
00218 const char* s = fIt->first.c_str();
00219 ++ fIt;
00220 return s;
00221 }
00222
00223 Registry::RegistryKey Registry::Key(void) const
00224 {
00225 return RegistryKey(this);
00226 }
00227
00228 #define REGISTRY_SET(TYPE) \
00229 bool Registry::Set(const char* key, TYPE val) \
00230 { \
00231 tRegMap::iterator mit = fMap.find(key); \
00232 if (mit != fMap.end()) { \
00233 if (fValuesLocked) { \
00234 MSG("Registry",Msg::kWarning) \
00235 << "Set: Values are locked - not overwriting \"" \
00236 << key << "\" with \"" << val << "\" in registry \"" << this->GetName() << "\"\n";\
00237 return false; \
00238 } \
00239 if (!dynamic_cast<RegistryItemXxx<TYPE>*>(mit->second)) { \
00240 MSG("Registry",Msg::kWarning) \
00241 << "Set: attempt to overwrite old value for key \"" \
00242 << key << "\" with different type value " \
00243 << val << " in registry \"" << this->GetName() << "\"\n";\
00244 return false; \
00245 } \
00246 delete mit->second; \
00247 fMap.erase(mit); \
00248 } \
00249 else { \
00250 if (fKeysLocked) { \
00251 MSG("Registry",Msg::kWarning) \
00252 << "Set: Keys are locked - not adding `" \
00253 << key << "' to registry \"" << this->GetName() << "\"\n";\
00254 return false; \
00255 } \
00256 } \
00257 RegistryItem* ri = new RegistryItemXxx< TYPE >(new TYPE (val)); \
00258 fMap[key] = ri; \
00259 this->SetDirty(); \
00260 return true; \
00261 }
00262
00263 REGISTRY_SET(char)
00264 REGISTRY_SET(int)
00265 REGISTRY_SET(double)
00266 REGISTRY_SET(Registry)
00267 #undef REGISTRY_SET
00268
00269
00270
00271 bool Registry::Set(const char* key, const char* val)
00272 {
00273 tRegMap::iterator mit = fMap.find(key);
00274 if (mit != fMap.end()) {
00275 if (fValuesLocked) {
00276 MSG("Registry",Msg::kWarning)
00277 << "Set: Values are locked - not overwriting `"
00278 << key << "\" with \"" << val << "\" in registry \"" << this->GetName() << "\"\n";
00279 return false;
00280 }
00281 if (! dynamic_cast<RegistryItemXxx<const char*>*>(mit->second) ) {
00282 MSG("Registry",Msg::kWarning)
00283 << "Set: attempt to overwrite old value for key \""
00284 << key << "\" with different type value "
00285 << val << " in registry \"" << this->GetName() << "\"\n";
00286 return false;
00287 }
00288 delete mit->second;
00289 fMap.erase(mit);
00290 }
00291 else {
00292 if (fKeysLocked) {
00293 MSG("Registry",Msg::kWarning)
00294 << "Registry::Set: Keys are locked - not adding `"
00295 << key << "' in registry \"" << this->GetName() << "\"\n";
00296 return false;
00297 }
00298 }
00299
00300 char** cpp = new char*;
00301 (*cpp) = new char [strlen(val)+1];
00302 strcpy(*cpp,val);
00303 const char** ccpp = const_cast<const char**>(cpp);
00304 RegistryItem* ri = new RegistryItemXxx< const char* >(ccpp);
00305 fMap[key] = ri;
00306 this->SetDirty();
00307 return true;
00308 }
00309
00310
00311 #define REGISTRY_GET(TYPE) \
00312 bool Registry::Get(const char* key, TYPE & val) const \
00313 { \
00314 tRegMap::const_iterator mit = fMap.find(key); \
00315 if (mit == fMap.end()) return false; \
00316 RegistryItemXxx<TYPE>* rix = \
00317 dynamic_cast<RegistryItemXxx<TYPE>*>(mit->second); \
00318 if (rix == 0) return false; \
00319 val = *(rix->Get()); \
00320 return true; \
00321 }
00322
00323 REGISTRY_GET(char)
00324 REGISTRY_GET(Registry)
00325 REGISTRY_GET(const char*)
00326 REGISTRY_GET(int)
00327
00328 bool Registry::Get(const char* key, double & val) const
00329 {
00330 tRegMap::const_iterator mit = fMap.find(key);
00331 if (mit == fMap.end()) return false;
00332
00333 RegistryItemXxx<double>* rixd =
00334 dynamic_cast<RegistryItemXxx<double>*>(mit->second);
00335 if (rixd) {
00336 val = *(rixd->Get());
00337 return true;
00338 }
00339
00340 RegistryItemXxx<int>* rixi =
00341 dynamic_cast<RegistryItemXxx<int>*>(mit->second);
00342 if (rixi) {
00343 val = *(rixi->Get());
00344 return true;
00345 }
00346 return false;
00347 }
00348
00349 #define REGISTRY_GET_TYPE(NAME, RETTYPE, TYPE) \
00350 RETTYPE Registry::Get##NAME(const char* key) const \
00351 { \
00352 TYPE retval = 0; \
00353 if (Get(key,retval)) return retval; \
00354 if (fErrorHandler) { fErrorHandler(); return 0; } \
00355 else { \
00356 MSG("Registry",Msg::kWarning) \
00357 << "\nRegistry::GetTYPE: failed to get value for key \"" \
00358 << key << "\" from Registry \"" << this->GetName() \
00359 << "\". Aborting\n\n"; \
00360 bool must_get_a_value = false; \
00361 assert(must_get_a_value); \
00362 return 0; \
00363 } \
00364 }
00365
00366
00367 REGISTRY_GET_TYPE(Char, char, char)
00368 REGISTRY_GET_TYPE(CharString, const char*, const char*)
00369 REGISTRY_GET_TYPE(Int, int, int)
00370 REGISTRY_GET_TYPE(Double, double, double)
00371
00372 #undef REGISTRY_GET_TYPE
00373 Registry Registry::GetRegistry(const char* key) const
00374 {
00375 Registry retval;
00376 if (Get(key,retval)) return retval;
00377 if (fErrorHandler) { fErrorHandler(); return retval; }
00378 else {
00379 MSG("Registry",Msg::kWarning)
00380 << "\nRegistry::GetTYPE: failed to get value for key \""
00381 << key << "\" from Registry \"" << this->GetName()
00382 << "\". Aborting\n\n";
00383 bool must_get_a_value = false;
00384 assert(must_get_a_value);
00385 return retval;
00386 }
00387 }
00388
00389 const type_info& Registry::GetType(const char* key) const
00390 {
00391 tRegMap::const_iterator mit = fMap.find(key);
00392 if (mit == fMap.end()) return typeid(void);
00393 return mit->second->GetType();
00394 }
00395 string Registry::GetTypeAsString(const char* key) const
00396 {
00397 tRegMap::const_iterator mit = fMap.find(key);
00398 if (mit == fMap.end()) return "void";
00399 return mit->second->GetTypeAsString();
00400 }
00401
00402 string Registry::GetValueAsString(const char* key) const
00403 {
00404 ostringstream os;
00405 tRegMap::const_iterator mit = fMap.find(key);
00406 if (mit == fMap.end()) return "";
00407 mit->second->PrintStream(os);
00408 return os.str();
00409 }
00410
00411 void Registry::Streamer(TBuffer& b)
00412 {
00413 int nobjects;
00414
00415 if (b.IsReading()) {
00416 Version_t v = b.ReadVersion();
00417 if (v) {}
00418 TNamed::Streamer(b);
00419
00420 b >> nobjects;
00421
00422 for (int i = 0; i < nobjects; ++i) {
00423
00424 char tmp[1024];
00425 b >> tmp;
00426 string key(tmp);
00427
00428 RegistryItem *ri;
00429 b >> ri;
00430
00431
00432 tRegMap::iterator mit = fMap.find(key);
00433 if (mit != fMap.end()) {
00434 delete mit->second;
00435 fMap.erase(mit);
00436 }
00437 fMap[key] = ri;
00438
00439 }
00440 }
00441 else {
00442 b.WriteVersion(Registry::IsA());
00443 TNamed::Streamer(b);
00444
00445 nobjects = fMap.size();
00446 b << nobjects;
00447
00448 MSG("Registry",Msg::kDebug)
00449 << "Streamer, Writing "<< nobjects <<" objects\n";
00450
00451 tRegMap::iterator mit = fMap.begin();
00452 while (mit != fMap.end()) {
00453 b << mit->first.c_str();
00454
00455 MSG("Registry",Msg::kDebug)
00456 << mit->first.c_str() << endl;
00457
00458 b << mit->second;
00459
00460 ++mit;
00461 }
00462 }
00463 }
00464
00465
00466 std::ostream& Registry::PrintStream(std::ostream& os) const
00467 {
00468 os << "['" << this->GetName() << "'";
00469
00470 tRegMap::const_iterator mit, done = fMap.end();
00471 for (mit = fMap.begin(); mit != done; ++mit) {
00472 os << " '" << mit->first << "'=(";
00473 os << mit->second->GetTypeAsString();
00474 os << ")";
00475 mit->second->PrintStream(os);
00476 }
00477
00478 os << "]";
00479 return os;
00480 }
00481
00482
00483 static std::istream& bail(std::istream& is)
00484 {
00485 MSG("Registry",Msg::kWarning)
00486 << "Registry::Read(istream&) stream corrupted\n";
00487 return is;
00488 }
00489
00490 std::istream& Registry::ReadStream(std::istream& is)
00491 {
00492 Registry reg;
00493
00494 char c;
00495 if (!is.get(c)) return bail(is);
00496 if (c != '[') {
00497 is.putback(c);
00498 return bail(is);
00499 }
00500 string name = Util::read_quoted_string(is);
00501 reg.SetName(name.c_str());
00502
00503 while (is.get(c)) {
00504 if (isspace(c)) continue;
00505 if (c == ']') {
00506 *this = reg;
00507 return is;
00508 }
00509 is.putback(c);
00510
00511
00512 string key = read_quoted_string(is);
00513 if (key == "") return bail(is);
00514
00515
00516 if (!is.get(c)) return bail(is);
00517
00518
00519 if (!is.get(c) || c != '(') {
00520 is.putback(c);
00521 return bail(is);
00522 }
00523
00524
00525 string type;
00526 while (is.get(c)) {
00527 if (c == ')') break;
00528 type += c;
00529 }
00530
00531
00532 RegistryItem* ri = 0;
00533 if (type == "char")
00534 ri = new RegistryItemXxx<char>();
00535 else if (type == "int")
00536 ri = new RegistryItemXxx<int>();
00537 else if (type == "double")
00538 ri = new RegistryItemXxx<double>();
00539 else if (type == "string")
00540 ri = new RegistryItemXxx<const char*>();
00541 else if (type == "Registry")
00542 ri = new RegistryItemXxx<Registry>();
00543 else return bail(is);
00544
00545 ri->ReadStream(is);
00546 reg.fMap[key] = ri;
00547 }
00548 return is;
00549
00550 }