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.51 2008/09/25 13:06:57 bckhouse 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){ \
00319 MSG("Registry", Msg::kError) << "Key " << key \
00320 << " does not have type " \
00321 << #TYPE << " as required" \
00322 << endl; \
00323 return false; \
00324 } \
00325 val = *(rix->Get()); \
00326 return true; \
00327 }
00328
00329 REGISTRY_GET(char)
00330 REGISTRY_GET(Registry)
00331 REGISTRY_GET(const char*)
00332 REGISTRY_GET(int)
00333
00334 bool Registry::Get(const char* key, double & val) const
00335 {
00336 tRegMap::const_iterator mit = fMap.find(key);
00337 if (mit == fMap.end()) return false;
00338
00339 RegistryItemXxx<double>* rixd =
00340 dynamic_cast<RegistryItemXxx<double>*>(mit->second);
00341 if (rixd) {
00342 val = *(rixd->Get());
00343 return true;
00344 }
00345
00346 RegistryItemXxx<int>* rixi =
00347 dynamic_cast<RegistryItemXxx<int>*>(mit->second);
00348 if (rixi) {
00349 val = *(rixi->Get());
00350 return true;
00351 }
00352 MSG("Registry", Msg::kError) << "Key " << key
00353 << " does not have type double or int"
00354 << " as required" << endl;
00355 return false;
00356 }
00357
00358 #define REGISTRY_GET_TYPE(NAME, RETTYPE, TYPE) \
00359 RETTYPE Registry::Get##NAME(const char* key) const \
00360 { \
00361 TYPE retval = 0; \
00362 if (Get(key,retval)) return retval; \
00363 if (fErrorHandler) { fErrorHandler(); return 0; } \
00364 else { \
00365 MSG("Registry",Msg::kWarning) \
00366 << "\nRegistry::GetTYPE: failed to get value for key \"" \
00367 << key << "\" from Registry \"" << this->GetName() \
00368 << "\". Aborting\n\n"; \
00369 bool must_get_a_value = false; \
00370 assert(must_get_a_value); \
00371 return 0; \
00372 } \
00373 }
00374
00375
00376 REGISTRY_GET_TYPE(Char, char, char)
00377 REGISTRY_GET_TYPE(CharString, const char*, const char*)
00378 REGISTRY_GET_TYPE(Int, int, int)
00379 REGISTRY_GET_TYPE(Double, double, double)
00380
00381 #undef REGISTRY_GET_TYPE
00382 Registry Registry::GetRegistry(const char* key) const
00383 {
00384 Registry retval;
00385 if (Get(key,retval)) return retval;
00386 if (fErrorHandler) { fErrorHandler(); return retval; }
00387 else {
00388 MSG("Registry",Msg::kWarning)
00389 << "\nRegistry::GetTYPE: failed to get value for key \""
00390 << key << "\" from Registry \"" << this->GetName()
00391 << "\". Aborting\n\n";
00392 bool must_get_a_value = false;
00393 assert(must_get_a_value);
00394 return retval;
00395 }
00396 }
00397
00398 const type_info& Registry::GetType(const char* key) const
00399 {
00400 tRegMap::const_iterator mit = fMap.find(key);
00401 if (mit == fMap.end()) return typeid(void);
00402 return mit->second->GetType();
00403 }
00404 string Registry::GetTypeAsString(const char* key) const
00405 {
00406 tRegMap::const_iterator mit = fMap.find(key);
00407 if (mit == fMap.end()) return "void";
00408 return mit->second->GetTypeAsString();
00409 }
00410
00411 string Registry::GetValueAsString(const char* key) const
00412 {
00413 ostringstream os;
00414 tRegMap::const_iterator mit = fMap.find(key);
00415 if (mit == fMap.end()) return "";
00416 mit->second->PrintStream(os);
00417 return os.str();
00418 }
00419
00420 void Registry::Streamer(TBuffer& b)
00421 {
00422 int nobjects;
00423
00424 if (b.IsReading()) {
00425 Version_t v = b.ReadVersion();
00426 if (v) {}
00427 TNamed::Streamer(b);
00428
00429 b >> nobjects;
00430
00431 for (int i = 0; i < nobjects; ++i) {
00432
00433 char tmp[1024];
00434 b >> tmp;
00435 string key(tmp);
00436
00437 RegistryItem *ri;
00438 b >> ri;
00439
00440
00441 tRegMap::iterator mit = fMap.find(key);
00442 if (mit != fMap.end()) {
00443 delete mit->second;
00444 fMap.erase(mit);
00445 }
00446 fMap[key] = ri;
00447
00448 }
00449 }
00450 else {
00451 b.WriteVersion(Registry::IsA());
00452 TNamed::Streamer(b);
00453
00454 nobjects = fMap.size();
00455 b << nobjects;
00456
00457 MSG("Registry",Msg::kDebug)
00458 << "Streamer, Writing "<< nobjects <<" objects\n";
00459
00460 tRegMap::iterator mit = fMap.begin();
00461 while (mit != fMap.end()) {
00462 b << mit->first.c_str();
00463
00464 MSG("Registry",Msg::kDebug)
00465 << mit->first.c_str() << endl;
00466
00467 b << mit->second;
00468
00469 ++mit;
00470 }
00471 }
00472 }
00473
00474
00475 std::ostream& Registry::PrintStream(std::ostream& os) const
00476 {
00477 os << "['" << this->GetName() << "'";
00478
00479 tRegMap::const_iterator mit, done = fMap.end();
00480 for (mit = fMap.begin(); mit != done; ++mit) {
00481 os << " '" << mit->first << "'=(";
00482 os << mit->second->GetTypeAsString();
00483 os << ")";
00484 mit->second->PrintStream(os);
00485 }
00486
00487 os << "]";
00488 return os;
00489 }
00490
00491
00492 static std::istream& bail(std::istream& is)
00493 {
00494 MSG("Registry",Msg::kWarning)
00495 << "Registry::Read(istream&) stream corrupted\n";
00496 return is;
00497 }
00498
00499 std::istream& Registry::ReadStream(std::istream& is)
00500 {
00501 Registry reg;
00502
00503 char c;
00504 if (!is.get(c)) return bail(is);
00505 if (c != '[') {
00506 is.putback(c);
00507 return bail(is);
00508 }
00509 string name = Util::read_quoted_string(is);
00510 reg.SetName(name.c_str());
00511
00512 while (is.get(c)) {
00513 if (isspace(c)) continue;
00514 if (c == ']') {
00515 *this = reg;
00516 return is;
00517 }
00518 is.putback(c);
00519
00520
00521 string key = read_quoted_string(is);
00522 if (key == "") return bail(is);
00523
00524
00525 if (!is.get(c)) return bail(is);
00526
00527
00528 if (!is.get(c) || c != '(') {
00529 is.putback(c);
00530 return bail(is);
00531 }
00532
00533
00534 string type;
00535 while (is.get(c)) {
00536 if (c == ')') break;
00537 type += c;
00538 }
00539
00540
00541 RegistryItem* ri = 0;
00542 if (type == "char")
00543 ri = new RegistryItemXxx<char>();
00544 else if (type == "int")
00545 ri = new RegistryItemXxx<int>();
00546 else if (type == "double")
00547 ri = new RegistryItemXxx<double>();
00548 else if (type == "string")
00549 ri = new RegistryItemXxx<const char*>();
00550 else if (type == "Registry")
00551 ri = new RegistryItemXxx<Registry>();
00552 else return bail(is);
00553
00554 ri->ReadStream(is);
00555 reg.fMap[key] = ri;
00556 }
00557 return is;
00558
00559 }