TDbiCfgPromptConfigurable.cxx

Go to the documentation of this file.
00001 #include "TDbiCfgPromptConfigurable.hxx"
00002 #include "TDbiCfgDialog.hxx"
00003 #include <TSK_DBI_Log.hxx>
00004 #include <MsgFormat.h>
00005 using std::endl;
00006 #include <string.h>
00007 #include <stdlib.h>
00008 #include <typeinfo>
00009 #include "TDbi.hxx" 
00010 #include <assert.h>
00011 
00012 ClassImp(TDbiCfgPromptConfigurable)
00013 
00014 TDbiCfgPromptConfigurable::TDbiCfgPromptConfigurable()
00015 {
00016   ////////////////////////////////////////////////////////////////////////////////////
00017   /// TDbiCfgPromptConfigurable
00018   ///
00019   /// A nice base class to use with configurable objects.
00020   ///
00021   /// Like the TDbiCfg(Lazy)Configurable class, but doesn't use
00022   /// lazy execution.
00023   ///
00024   /// How to use it:
00025   /// Set up defaults in the constructor (or somehwere else that happens soon)
00026   /// and call InitializeConfig() with them.
00027   ///
00028   /// At any time, use the Set() commands to modify your object.
00029   /// By default, your object has keys locked and values unlocked:
00030   /// This means that:
00031   ///    - If you try to set a key that doesn't exist, it fails. (Typo protection)
00032   ///    - If you try to set a key to different type, it fails. (Type protection)
00033   ///
00034   /// Note that the Set() commands include:
00035   /// Set( key, int )           |
00036   /// Set( key, double )        |- Work like TDbiRegistry() commands, but with above safeties
00037   /// Set( key, const char* )   |
00038   /// Set( key, TDbiRegistry )      |
00039   /// Set( TDbiRegistry )            - Works like Merge(), but with above safeties
00040   /// Set( TDbiRegistry, true)       - Ditto, but Merge()s sub-registries as well, with the same rules.
00041   /// Set( string )              - Works like JobControl parser
00042   ///                              i.e. Set("myint=1 myfloat=2.0 mystring=blahDeblah");
00043   ///
00044   /// If the configuration changes, ConfigModified() will be called, letting
00045   /// you read the new configuration variables.  But it's smart: your function
00046   /// only gets called if a variable has changed, not if they've stayed the same.
00047   ///
00048   /// Example:
00049   ///class MyClass : public TDbiCfgPromptConfigurable
00050   ///{
00051   ///   MyClass() {
00052   ///     TDbiRegistry r;
00053   ///     r.Set("Default1",1);
00054   ///     r.Set("Default2",2.0);
00055   ///     InitializeConfig(r);
00056   ///   };
00057   ///
00058   ///   void ConfigModified() {
00059   ///     GetConfig().Get("Default1",fDefault1);
00060   ///     .. etc ..
00061   ///   }
00062   ///
00063   ///};
00064 }
00065 
00066 void TDbiCfgPromptConfigurable::InitializeConfig(const TDbiRegistry& initConfig)
00067 {
00068   fConfig.UnLockKeys();
00069   fConfig.UnLockValues();
00070   fConfig.Clear();
00071   fConfig=initConfig;
00072   fConfig.SetDirty(false); // Do this whenever ConfigModified is called.
00073   fConfig.LockKeys();
00074   fConfig.UnLockValues();
00075 
00076   // For GUIs:
00077   fDefaultConfig=initConfig;
00078 
00079   ConfigModified();
00080 }
00081 
00082 Bool_t TDbiCfgPromptConfigurable::Split(const char* line, char sep, string& a, string& b)
00083 {
00084  //======================================================================
00085   // Purpose: Split a character string into two pieces given a
00086   //          separator.  Example peas::carots::beans into
00087   //          a = peas
00088   //          b = carots::beans
00089   //
00090   //          Or, peas -> a=peas, b=""
00091   //
00092   // Inputs: line - the text to split
00093   //         sep  - the separation character (':' in the example above)
00094   //         a    - text before the separator
00095   //         b    - text after separator
00096   //
00097   // Return value: true if a split happened, false otherwise.
00098   //======================================================================
00099   // Clear a and b strings
00100   bool split = false;
00101   a = "";
00102   b = "";
00103   const char* c = line;
00104   while(*c != '\0') {
00105     if(*c == sep) {
00106       split=true;
00107       break;
00108     }
00109     a+=(*c);
00110     ++c;
00111   }
00112   while(*c == sep) { ++c; };
00113   b = c;
00114   return split;
00115 }
00116 
00117 bool TDbiCfgPromptConfigurable::IsInt(const std::string& s, Int_t& i)
00118 {
00119   //======================================================================
00120   // Does the string s represent an integer?
00121   //======================================================================
00122   const char* ss = s.c_str();
00123   char* endptr;
00124   double d = strtod(ss, &endptr);
00125   if (endptr==ss && d==0.0) return false; // Conversion to double failed...
00126 
00127   // Check if this number is int or float
00128   if (strchr(ss,'.')) return false;
00129   if (strchr(ss,'E')) return false;
00130   if (strchr(ss,'e')) return false;
00131 
00132   // All checks for "intness" passed
00133   i = atoi(ss);
00134 
00135   return true;
00136 }
00137 
00138 
00139 //......................................................................
00140 
00141 bool TDbiCfgPromptConfigurable::IsFloat(const std::string& s, Double_t& val)
00142 {
00143 //======================================================================
00144 // Does the string s represent an integer?
00145 //======================================================================
00146   char* endptr;
00147   double d = strtod(s.c_str(), &endptr);
00148   if (endptr==s && d==0.0) return false; // Conversion to double failed...
00149 
00150   // All checks for "floatness" passed
00151   val = d;
00152   return true;
00153 }
00154 
00155 
00156 void TDbiCfgPromptConfigurable::Set(TDbiCfgDialog* d)
00157 {
00158 //======================================================================
00159 // Update the configuration parameters. Allow a TDbiCfgDialog object to be
00160 // passed in. If none is passed in use the default, text based dialog
00161 // object.
00162 //======================================================================
00163   bool deleteDialog = false;
00164   if (d==0) {
00165     d = new TDbiCfgDialog();
00166     deleteDialog = true;
00167   }
00168 
00169   // Set up d with the default configuration parameters
00170   d->SetDefault(fDefaultConfig);
00171   d->SetCurrent(fConfig);
00172 
00173   // Do the querry
00174   TDbiRegistry r = d->Query();
00175   Set(r);
00176 
00177   // Clean up the dialog
00178   if (deleteDialog) { delete d; d = 0; }
00179 }
00180 
00181 void TDbiCfgPromptConfigurable::Set(const char* key, char val)
00182 { TDbiRegistry r;  r.Set(key,val); Set(r); }
00183 
00184 
00185 void TDbiCfgPromptConfigurable::Set(const char* key, const char* val)
00186 { TDbiRegistry r;  r.Set(key,val); Set(r); }
00187 
00188 
00189 
00190 void TDbiCfgPromptConfigurable::Set(const char* key, double val)
00191 { TDbiRegistry r;  r.Set(key,val); Set(r); }
00192 
00193 
00194 void TDbiCfgPromptConfigurable::Set(const char* key, int val)
00195 { TDbiRegistry r;  r.Set(key,val); Set(r); }
00196 
00197 
00198 void TDbiCfgPromptConfigurable::Set(const char* key, const TDbiRegistry& val )
00199 { TDbiRegistry r;  r.Set(key,val); Set(r); }
00200 
00201 
00202 void TDbiCfgPromptConfigurable::Set(const char* setstring)
00203 {
00204   // Parse a whole string.
00205 
00206   // First, look for spaces to seperate entries.
00207   TDbiRegistry r;
00208   string a,b;
00209   string line = setstring;
00210   bool split;
00211   do {
00212     split = Split(line,' ',a,b);
00213 
00214     // a contains the possible code.
00215     string key, val;
00216     if(a.size()>0) {
00217       if(Split(a,'=',key,val)) {
00218         Int_t i;
00219         Double_t f;
00220         if(IsInt(val,i)) {
00221           r.Set(key.c_str(),i);
00222         } else if(IsFloat(val,f)) {
00223           r.Set(key.c_str(),f);
00224         } else {
00225           r.Set(key.c_str(),val.c_str());
00226         };
00227         
00228         
00229       } else {
00230         SK_DBI_Warn(  "Can't parse fragment: " << a << "  ");
00231       }
00232     }
00233 
00234     line = b;
00235   } while ( split );
00236 
00237   // Add the data.
00238   Set(r);
00239 }
00240 ///
00241 // Granddaddy of set() routines
00242 /// 
00243 ///
00244 void TDbiCfgPromptConfigurable::Set(const TDbiRegistry& stuff, Bool_t recursive)
00245 {
00246   if(SafeMerge(fConfig,stuff,recursive)) {
00247     // Something got changed, so allow user to change stuff:
00248     ConfigModified();
00249     fConfig.SetDirty(false);
00250   }
00251 }
00252 /// Sets multiple things at once in registry.
00253 /// If anything gets modified (to a new value) it returns true.
00254 /// Works recursively on owned registries.
00255 /// Keeps type-safety.. better than TDbiRegistry::Merge()
00256 ///
00257 ///     Throws EBadTDbiRegistryKeys();
00258 Bool_t TDbiCfgPromptConfigurable::SafeMerge(TDbiRegistry& modify,
00259                                      const TDbiRegistry& stuff,
00260                                      Bool_t recursive )
00261 {
00262  
00263   // First, see if we're locked up too tight to set anything.
00264   if(modify.ValuesLocked()) {
00265     SK_DBI_Warn( "Configurable has values locked. Can't set:" << "  ");
00266     SK_DBI_Warn( stuff << "  ");
00267     return false;
00268   }
00269 
00270 
00271   bool modified = false;
00272 
00273   // Iterate through all the keys in stuff.
00274   TDbiRegistry::TDbiRegistryKey keyitr = stuff.Key();
00275   const char* key;
00276   while( (key = keyitr()) ) {
00277                                                 
00278     // Does modify have this key?
00279     if(!modify.KeyExists(key)) {
00280       // Key doesn't exist.
00281 
00282       if(modify.KeysLocked()) {
00283 
00284         // Keys are locked, so throw away with an error.
00285         SK_DBI_Warn( "Key " << key << " is not initialized in this Configurable. Skipping." << "  ");
00286         SK_DBI_Info("Current key/values are:" <<"  ");
00287    modify.PrettyPrint(std::cout);
00288         SK_DBI_Severe("FATAL: " << "\"" << key << "\" is an illegal key! Fix your script!" << "  ");
00289         throw EBadTDbiRegistryKeys();
00290         continue;
00291 
00292       } else {
00293         // Key exists. Go on to save this one.
00294       }
00295 
00296     } else {
00297       // Key exists.
00298 
00299       // Is the key the right type?
00300       if(modify.GetType(key)!=stuff.GetType(key)) {
00301         SK_DBI_Warn( "Key \"" << key << "\" is not initialized as type ("
00302                                           << modify.GetType(key).name()
00303                                           << ") but you've tried to set it to type ("
00304                                           << stuff.GetType(key).name()
00305                                           << ")" << "  ");
00306         continue;
00307       }
00308 
00309       if( modify.GetValueAsString(key)==stuff.GetValueAsString(key) ) {
00310         // The values are identical. So save the work and skip it.
00311         continue;
00312       }
00313     }
00314 
00315     // Switch on type:
00316     int    vint;
00317     double vdouble;
00318     char   vchar;
00319     const char* vcharstar;
00320     TDbiRegistry vregistry;
00321 
00322     const type_info& theType(modify.GetType(key));
00323 
00324     if((theType==typeid(char))&&(stuff.Get(key,vchar)))   modify.Set(key,vchar);
00325     if((theType==typeid(int))&&(stuff.Get(key,vint)))    modify.Set(key,vint);
00326     if((theType==typeid(double))&&(stuff.Get(key,vdouble))) modify.Set(key,vdouble);
00327     if((theType==typeid(const char*))&&(stuff.Get(key,vcharstar))) modify.Set(key,vcharstar);
00328     if(stuff.GetTypeAsString(key) == "TDbiRegistry"){
00329       if(stuff.Get(key,vregistry)) {
00330         // Registries are harder. Merge using this function.
00331         if(recursive) {
00332 
00333           TDbiRegistry old;
00334           if(modify.Get(key,old)) {
00335             TDbiRegistry old;
00336             // Just for safety:
00337             old.UnLockValues();
00338             old.LockKeys();
00339             if(SafeMerge(old,vregistry)) modified = true;
00340             modify.Set(key,old);
00341           }
00342 
00343         } else {
00344           modify.Set(key,vregistry);
00345         }
00346       }
00347     }
00348 
00349     modified = true;
00350   };
00351 
00352   return modified;
00353 }
00354 
00355 

Generated on 11 Aug 2013 for SKDatabase by  doxygen 1.6.1