#include "THaAnalysisObject.h"
#include "THaVarList.h"
#include "THaTextvars.h"
#include "THaGlobals.h"
#include "TClass.h"
#include "TDatime.h"
#include "TROOT.h"
#include "TMath.h"
#include "TError.h"
#include "TVector3.h"
#include "TSystem.h"
#include "TObjArray.h"
#include "TVirtualMutex.h"
#include "TThread.h"
#include "Varargs.h"
#include <cstring>
#include <cctype>
#include <errno.h>
#include <algorithm>
#include <iostream>
#include <cmath>
#include <cstdlib>
#include <cstdio>
#include <string>
#ifdef HAS_SSTREAM
#include <sstream>
#define ISSTREAM istringstream
#define OSSTREAM ostringstream
#else
#include <strstream>
#define ISSTREAM istrstream
#define OSSTREAM ostrstream
#endif
#include <stdexcept>
#include <cassert>
#include <map>
#include <limits>
using namespace std;
typedef string::size_type ssiz_t;
typedef vector<string>::iterator vsiter_t;
TList* THaAnalysisObject::fgModules = NULL;
const Double_t THaAnalysisObject::kBig = 1.e38;
static TVirtualMutex* gHereMutex = 0;
THaAnalysisObject::THaAnalysisObject( const char* name,
const char* description ) :
TNamed(name,description), fPrefix(NULL), fStatus(kNotinit),
fDebug(0), fIsInit(false), fIsSetup(false), fProperties(0),
fOKOut(false), fInitDate(19950101,0)
{
if( !fgModules ) fgModules = new TList;
fgModules->Add( this );
}
THaAnalysisObject::THaAnalysisObject( )
: fPrefix(NULL), fStatus(kNotinit), fDebug(0), fIsInit(false),
fIsSetup(false), fProperties(), fOKOut(false)
{
}
THaAnalysisObject::~THaAnalysisObject()
{
if (fgModules) {
fgModules->Remove( this );
if( fgModules->GetSize() == 0 ) {
delete fgModules;
fgModules = 0;
}
}
delete [] fPrefix; fPrefix = 0;
}
Int_t THaAnalysisObject::Begin( THaRunBase* )
{
return 0;
}
Int_t THaAnalysisObject::DefineVariables( EMode )
{
return kOK;
}
Int_t THaAnalysisObject::DefineVarsFromList( const VarDef* list, EMode mode,
const char* var_prefix ) const
{
return DefineVarsFromList( list, kVarDef, mode, var_prefix );
}
Int_t THaAnalysisObject::DefineVarsFromList( const RVarDef* list, EMode mode,
const char* var_prefix ) const
{
return DefineVarsFromList( list, kRVarDef, mode, var_prefix );
}
Int_t THaAnalysisObject::DefineVarsFromList( const void* list,
EType type, EMode mode,
const char* var_prefix ) const
{
TString here(GetClassName());
here.Append("::DefineVarsFromList");
return DefineVarsFromList( list, type, mode, var_prefix, this,
fPrefix, here.Data() );
}
Int_t THaAnalysisObject::DefineVarsFromList( const void* list,
EType type, EMode mode,
const char* var_prefix,
const TObject* obj,
const char* prefix,
const char* here )
{
if( !gHaVars ) {
TString action;
if( mode == kDefine )
action = "defined";
else if( mode == kDelete )
action = "deleted (this is safe when exiting)";
::Warning( ::Here(here,prefix), "No global variable list found. "
"No variables %s.", action.Data() );
return (mode==kDefine ? kInitError : kOK);
}
if( mode == kDefine ) {
if( type == kVarDef )
gHaVars->DefineVariables( static_cast<const VarDef*>(list),
prefix, ::Here(here,prefix) );
else if( type == kRVarDef )
gHaVars->DefineVariables( static_cast<const RVarDef*>(list), obj,
prefix, ::Here(here,prefix), var_prefix );
}
else if( mode == kDelete ) {
if( type == kVarDef ) {
const VarDef* item;
const VarDef* theList = static_cast<const VarDef*>(list);
while( (item = theList++) && item->name ) {
TString name(prefix);
name.Append( item->name );
gHaVars->RemoveName( name );
}
} else if( type == kRVarDef ) {
const RVarDef* item;
const RVarDef* theList = static_cast<const RVarDef*>(list);
while( (item = theList++) && item->name ) {
TString name(prefix);
name.Append( item->name );
gHaVars->RemoveName( name );
}
}
}
return kOK;
}
Int_t THaAnalysisObject::End( THaRunBase* )
{
return 0;
}
THaAnalysisObject* THaAnalysisObject::FindModule( const char* name,
const char* classname,
bool do_error )
{
static const char* const here = "FindModule";
static const char* const anaobj = "THaAnalysisObject";
if( !name || !*name ) {
if( do_error )
Error( Here(here), "No module name given." );
fStatus = kInitError;
return NULL;
}
TIter next(fgModules);
TObject* obj = 0;
while( (obj = next()) ) {
#ifdef NDEBUG
THaAnalysisObject* module = static_cast<THaAnalysisObject*>(obj);
#else
THaAnalysisObject* module = dynamic_cast<THaAnalysisObject*>(obj);
assert(module);
#endif
const char* cprefix = module->GetPrefix();
if( !cprefix ) {
module->MakePrefix();
cprefix = module->GetPrefix();
if( !cprefix )
continue;
}
TString prefix(cprefix);
if( prefix.EndsWith(".") )
prefix.Chop();
if( prefix == name )
break;
}
if( !obj ) {
if( do_error )
Error( Here(here), "Module %s does not exist.", name );
fStatus = kInitError;
return NULL;
}
if( !obj->IsA()->InheritsFrom( anaobj )) {
if( do_error )
Error( Here(here), "Module %s (%s) is not a %s.",
obj->GetName(), obj->GetTitle(), anaobj );
fStatus = kInitError;
return NULL;
}
if( classname && *classname && strcmp(classname,anaobj) &&
!obj->IsA()->InheritsFrom( classname )) {
if( do_error )
Error( Here(here), "Module %s (%s) is not a %s.",
obj->GetName(), obj->GetTitle(), classname );
fStatus = kInitError;
return NULL;
}
THaAnalysisObject* aobj = static_cast<THaAnalysisObject*>( obj );
if( do_error ) {
if( !aobj->IsOK() ) {
Error( Here(here), "Module %s (%s) not initialized.",
obj->GetName(), obj->GetTitle() );
fStatus = kInitError;
return NULL;
}
}
return aobj;
}
vector<string> THaAnalysisObject::GetDBFileList( const char* name,
const TDatime& date,
const char* here )
{
static const string defaultdir = "DEFAULT";
#ifdef WIN32
static const string dirsep = "\\", allsep = "/\\";
#else
static const string dirsep = "/", allsep = "/";
#endif
const char* dbdir = NULL;
const char* result;
void* dirp;
size_t pos;
vector<string> time_dirs, dnames, fnames;
vsiter_t it;
string item, filename, thedir;
Int_t item_date;
bool have_defaultdir = false, found = false;
if( !name || !*name )
goto exit;
filename = name;
if( filename.find_first_of(allsep) != string::npos ) {
fnames.push_back( filename );
goto exit;
}
if( (dbdir = gSystem->Getenv("DB_DIR")))
dnames.push_back( dbdir );
dnames.push_back( "DB" );
dnames.push_back( "db" );
dnames.push_back( "." );
it = dnames.begin();
while( !(dirp = gSystem->OpenDirectory( (*it).c_str() )) &&
(++it != dnames.end()) ) {}
if( it == dnames.end() ) {
::Error( here, "Cannot open any database directories. Check your disk!");
goto exit;
}
thedir = *it;
while( (result = gSystem->GetDirEntry(dirp)) ) {
item = result;
if( item.length() == 8 ) {
for( pos=0; pos<8; ++pos )
if( !isdigit(item[pos])) break;
if( pos==8 )
time_dirs.push_back( item );
} else if ( item == defaultdir )
have_defaultdir = true;
}
gSystem->FreeDirectory(dirp);
if( time_dirs.size() > 0 ) {
sort( time_dirs.begin(), time_dirs.end() );
for( it = time_dirs.begin(); it != time_dirs.end(); ++it ) {
item_date = atoi((*it).c_str());
if( it == time_dirs.begin() && date.GetDate() < item_date )
break;
if( it != time_dirs.begin() && date.GetDate() < item_date ) {
--it;
found = true;
break;
}
if( it+1 == time_dirs.end() && date.GetDate() >= item_date ) {
found = true;
break;
}
}
}
if( filename.substr(0,3) != "db_" )
filename.insert(0,"db_");
#ifndef NDEBUG
assert( filename.length() >= 4 );
#else
if( filename.length() < 4 ) { fnames.clear(); goto exit; }
#endif
if( *filename.rbegin() == '.' ) {
filename += "dat";
} else if( filename.substr(filename.length()-4) != ".dat" ) {
filename += ".dat";
}
fnames.push_back( filename );
if( found ) {
item = thedir + dirsep + *it + dirsep + filename;
fnames.push_back( item );
}
if( have_defaultdir ) {
item = thedir + dirsep + defaultdir + dirsep + filename;
fnames.push_back( item );
}
fnames.push_back( thedir + dirsep + filename );
exit:
return fnames;
}
const char* THaAnalysisObject::GetDBFileName() const
{
return GetPrefix();
}
const char* THaAnalysisObject::GetClassName() const
{
const char* classname = "UnknownClass";
if( TROOT::Initialized() )
classname = ClassName();
return classname;
}
void THaAnalysisObject::DoError( int level, const char* here,
const char* fmt, va_list va) const
{
TString location(here);
if( !location.BeginsWith("(\"") )
location.Prepend("::");
location.Prepend(GetClassName());
::ErrorHandler(level, location.Data(), fmt, va);
}
const char* Here( const char* method, const char* prefix )
{
static map<Long_t,TString> buffers;
TString txt;
if( prefix && *prefix ) {
TString full_prefix(prefix);
if( full_prefix.EndsWith(".") )
full_prefix.Chop();
full_prefix.Prepend("(\""); full_prefix.Append("\")");
const char* scope;
if( method && *method && (scope = strstr(method, "::")) ) {
Ssiz_t pos = scope - method;
txt = method;
assert(pos >= 0 && pos < txt.Length());
txt.Insert(pos, full_prefix);
method = 0;
} else {
txt = full_prefix + "::";
}
}
if( method )
txt.Append(method);
R__LOCKGUARD2(gHereMutex);
TString& ret = (buffers[ TThread::SelfId() ] = txt);
return ret.Data();
}
const char* THaAnalysisObject::Here( const char* here ) const
{
return ::Here( here, fPrefix );
}
const char* THaAnalysisObject::ClassNameHere( const char* here ) const
{
TString method(here);
if( method.Index("::") == kNPOS ) {
method.Prepend("::");
method.Prepend(GetClassName());
}
return ::Here( method.Data(), fPrefix );
}
THaAnalysisObject::EStatus THaAnalysisObject::Init()
{
return Init( TDatime() );
}
THaAnalysisObject::EStatus THaAnalysisObject::Init( const TDatime& date )
{
static const char* const here = "Init";
if( IsZombie() )
return fStatus = kNotinit;
fInitDate = date;
const char* fnam = "run.";
MakePrefix();
Int_t status = ReadRunDatabase(date);
if( status && (status != kFileError || (fProperties & kNeedsRunDB) != 0))
goto err;
if( IsA()->GetMethodAllAny("ReadDatabase") !=
gROOT->GetClass("THaAnalysisObject")->GetMethodAllAny("ReadDatabase") ) {
fnam = GetDBFileName();
try {
status = ReadDatabase(date);
}
catch( std::bad_alloc ) {
Error( Here(here), "Out of memory in ReadDatabase. Machine too busy? "
"Call expert." );
status = kInitError;
}
catch( ... ) {
Error( Here(here), "Exception caught in ReadDatabase. Not initialized. "
"Call expert." );
status = kInitError;
}
if( status )
goto err;
}
else if ( fDebug>0 ) {
Info( Here(here), "No ReadDatabase function defined. Database not read." );
}
status = DefineVariables(kDefine);
Clear("I");
goto exit;
err:
if( status == kFileError )
Error( Here(here), "Cannot open database file db_%sdat", fnam );
else if( status == kInitError )
Error( Here(here), "Error when reading file db_%sdat", fnam);
exit:
return fStatus = (EStatus)status;
}
Int_t THaAnalysisObject::InitOutput( THaOutput* )
{
fOKOut = true;
return kOK;
}
void THaAnalysisObject::MakePrefix( const char* basename )
{
delete [] fPrefix;
if( basename && *basename ) {
fPrefix = new char[ strlen(basename) + strlen(GetName()) + 3 ];
strcpy( fPrefix, basename );
strcat( fPrefix, "." );
} else {
fPrefix = new char[ strlen(GetName()) + 2 ];
*fPrefix = 0;
}
strcat( fPrefix, GetName() );
strcat( fPrefix, "." );
}
void THaAnalysisObject::MakePrefix()
{
MakePrefix(0);
}
FILE* THaAnalysisObject::OpenFile( const char *name, const TDatime& date,
const char *here, const char *filemode,
const int debug_flag )
{
if( !name || !*name )
return NULL;
if( !here )
here="";
if( !filemode )
filemode="r";
FILE* fi = NULL;
vector<string> fnames( GetDBFileList(name, date, here) );
if( !fnames.empty() ) {
vsiter_t it = fnames.begin();
do {
if( debug_flag>1 )
cout << "Info in <" << here << ">: Opening database file " << *it;
fi = fopen( (*it).c_str(), filemode);
if( debug_flag>1 )
if( !fi ) cout << " ... failed" << endl;
else cout << " ... ok" << endl;
else if( debug_flag>0 && fi )
cout << "<" << here << ">: Opened database file " << *it << endl;
} while ( !fi && ++it != fnames.end() );
}
if( !fi && debug_flag>0 ) {
::Error(here,"Cannot open database file db_%s%sdat",name,
(name[strlen(name)-1]=='.'?"":"."));
}
return fi;
}
FILE* THaAnalysisObject::OpenFile( const TDatime& date )
{
return OpenFile(GetDBFileName(), date, ClassNameHere("OpenFile()"), "r", fDebug);
}
FILE* THaAnalysisObject::OpenRunDBFile( const TDatime& date )
{
return OpenFile("run", date, ClassNameHere("OpenFile()"), "r", fDebug);
}
char* THaAnalysisObject::ReadComment( FILE* fp, char *buf, const int len )
{
int ch = fgetc(fp);
ungetc(ch,fp);
if (ch == EOF || ch == ' ')
return NULL;
char *s= fgets(buf,len,fp);
return s;
}
Int_t THaAnalysisObject::ReadDatabase( const TDatime& )
{
return kOK;
}
Int_t THaAnalysisObject::ReadRunDatabase( const TDatime& date )
{
if( !fPrefix ) return kInitError;
if( (fProperties & kConfigOverride) == 0) {
FILE* file = OpenRunDBFile( date );
if( !file ) return kFileError;
TString name(fPrefix); name.Append("config");
Int_t ret = LoadDBvalue( file, date, name, fConfig );
fclose(file);
if( ret == -1 ) return kFileError;
if( ret < 0 ) return kInitError;
if( ret == 1 ) fConfig = "";
}
return kOK;
}
Int_t THaAnalysisObject::RemoveVariables()
{
return DefineVariables( kDelete );
}
void THaAnalysisObject::SetName( const char* name )
{
if( !name || !*name ) {
Warning( Here("SetName()"),
"Cannot set an empty object name. Name not set.");
return;
}
TNamed::SetName( name );
MakePrefix();
}
void THaAnalysisObject::SetNameTitle( const char* name, const char* title )
{
SetName( name );
SetTitle( title );
}
void THaAnalysisObject::SetConfig( const char* label )
{
fConfig = label;
if( fConfig.IsNull() )
fProperties &= ~kConfigOverride;
else
fProperties |= kConfigOverride;
}
void THaAnalysisObject::SetDebug( Int_t level )
{
fDebug = level;
}
Bool_t THaAnalysisObject::IntersectPlaneWithRay( const TVector3& xax,
const TVector3& yax,
const TVector3& org,
const TVector3& ray_start,
const TVector3& ray_vect,
Double_t& length,
TVector3& intersect )
{
Double_t nom[9], den[9];
nom[0] = den[0] = xax.X();
nom[3] = den[3] = xax.Y();
nom[6] = den[6] = xax.Z();
nom[1] = den[1] = yax.X();
nom[4] = den[4] = yax.Y();
nom[7] = den[7] = yax.Z();
den[2] = -ray_vect.X();
den[5] = -ray_vect.Y();
den[8] = -ray_vect.Z();
Double_t det1 = den[0]*(den[4]*den[8]-den[7]*den[5])
-den[3]*(den[1]*den[8]-den[7]*den[2])
+den[6]*(den[1]*den[5]-den[4]*den[2]);
if( fabs(det1) < 1e-5 )
return false;
nom[2] = ray_start.X()-org.X();
nom[5] = ray_start.Y()-org.Y();
nom[8] = ray_start.Z()-org.Z();
Double_t det2 = nom[0]*(nom[4]*nom[8]-nom[7]*nom[5])
-nom[3]*(nom[1]*nom[8]-nom[7]*nom[2])
+nom[6]*(nom[1]*nom[5]-nom[4]*nom[2]);
length = det2/det1;
intersect = ray_start + length*ray_vect;
return true;
}
void THaAnalysisObject::GeoToSph( Double_t th_geo, Double_t ph_geo,
Double_t& th_sph, Double_t& ph_sph )
{
static const Double_t twopi = 2.0*TMath::Pi();
Double_t ct = cos(th_geo), cp = cos(ph_geo);
register Double_t tmp = ct*cp;
th_sph = acos( tmp );
tmp = sqrt(1.0 - tmp*tmp);
ph_sph = (fabs(tmp) < 1e-6 ) ? 0.0 : acos( sqrt(1.0-ct*ct)*cp/tmp );
if( th_geo/twopi-floor(th_geo/twopi) > 0.5 ) ph_sph = TMath::Pi() - ph_sph;
if( ph_geo/twopi-floor(ph_geo/twopi) > 0.5 ) ph_sph = -ph_sph;
}
void THaAnalysisObject::SphToGeo( Double_t th_sph, Double_t ph_sph,
Double_t& th_geo, Double_t& ph_geo )
{
static const Double_t twopi = 2.0*TMath::Pi();
Double_t ct = cos(th_sph), st = sin(th_sph), cp = cos(ph_sph);
if( fabs(ct) > 1e-6 ) {
th_geo = atan( st/ct*cp );
if( cp>0.0 && th_geo<0.0 ) th_geo += TMath::Pi();
else if( cp<0.0 && th_geo>0.0 ) th_geo -= TMath::Pi();
} else {
th_geo = TMath::Pi()/2.0;
if( cp<0.0 ) th_geo = -th_geo;
}
ph_geo = acos( sqrt( st*st*cp*cp + ct*ct ));
if( ph_sph/twopi - floor(ph_sph/twopi) > 0.5 ) ph_geo =- ph_geo;
}
static string errtxt;
static int loaddb_depth = 0;
static string loaddb_prefix;
static Int_t IsDBdate( const string& line, TDatime& date, bool warn = true )
{
ssiz_t lbrk = line.find('[');
if( lbrk == string::npos || lbrk >= line.size()-12 ) return 0;
ssiz_t rbrk = line.find(']',lbrk);
if( rbrk == string::npos || rbrk <= lbrk+11 ) return 0;
Int_t yy, mm, dd, hh, mi, ss;
if( sscanf( line.substr(lbrk+1,rbrk-lbrk-1).c_str(), "%4d-%2d-%2d %2d:%2d:%2d",
&yy, &mm, &dd, &hh, &mi, &ss) != 6
|| yy < 1995 || mm < 1 || mm > 12 || dd < 1 || dd > 31
|| hh < 0 || hh > 23 || mi < 0 || mi > 59 || ss < 0 || ss > 59 ) {
if( warn )
::Warning("THaAnalysisObject::IsDBdate()",
"Invalid date tag %s", line.c_str());
return 0;
}
date.Set(yy, mm, dd, hh, mi, ss);
return 1;
}
static Int_t IsDBkey( const string& line, const char* key, string& text )
{
register const char* ln = line.c_str();
const char* eq = strchr(ln, '=');
if( !eq ) return 0;
while( *ln == ' ' ) ++ln;
assert( ln <= eq );
if( ln == eq ) return -1;
register const char* p = eq-1;
assert( p >= ln );
while( *p == ' ' ) --p;
if( strncmp(ln, key, p-ln+1) ) return -1;
ln = eq+1;
assert( !*ln || *(ln+strlen(ln)-1) != ' ' );
while( *ln == ' ' ) ++ln;
text = ln;
return 1;
}
static Int_t ChopPrefix( string& s )
{
ssiz_t len = s.size(), pos;
Int_t ndot = 0;
if( len<2 )
goto null;
pos = s.rfind('.',len-2);
if( pos == string::npos )
goto null;
s.erase(pos+1);
for( ssiz_t i = 0; i <= pos; i++ ) {
if( s[i] == '.' )
ndot++;
}
return ndot;
null:
s.clear();
return 0;
}
bool THaAnalysisObject::IsTag( const char* buf )
{
register const char* p = buf;
while( *p && *p != '[' ) p++;
if( !*p ) return false;
p++;
if( !*p || *p == ']' ) return false;
p++;
while( *p && *p != ']' ) p++;
return ( *p == ']' );
}
static Int_t GetLine( FILE* file, char* buf, size_t bufsiz, string& line )
{
char* r = buf;
line.clear();
while( (r = fgets(buf, bufsiz, file)) ) {
char* c = strchr(buf, '\n');
if( c )
*c = '\0';
register char *p = buf;
while( (p = strchr(p,'\t')) ) *(p++) = ' ';
line.append(buf);
if( c )
break;
}
if( !r && line.empty() )
return EOF;
return 0;
}
static void Trim( string& str )
{
if( str.empty() )
return;
register const char* p = str.c_str();
while( *p == ' ' ) ++p;
if( *p == '\0' )
str.clear();
else if( p != str.c_str() ) {
ssiz_t pos = p-str.c_str();
str.substr(pos).swap(str);
}
if( !str.empty() ) {
const char* q = str.c_str() + str.length()-1;
p = q;
while( *p == ' ' ) --p;
if( p != q ) {
ssiz_t pos = p-str.c_str();
str.erase(pos+1);
}
}
}
Int_t THaAnalysisObject::ReadDBline( FILE* file, char* buf, size_t bufsiz,
string& line )
{
line.clear();
Int_t r = 0;
bool maybe_continued = false, unfinished = true;
string linbuf;
fpos_t oldpos;
while( unfinished && fgetpos(file, &oldpos) == 0 &&
(r = GetLine(file,buf,bufsiz,linbuf)) == 0 ) {
bool continued = false, comment = false, has_equal = false,
trailing_space = false, leading_space = false;
ssiz_t pos = linbuf.find_first_of("#\\");
if( pos != string::npos ) {
if( linbuf[pos] == '\\' )
continued = true;
else
comment = true;
linbuf.erase(pos);
}
if( !linbuf.empty() ) {
if( linbuf[0] == ' ')
leading_space = true;
if( linbuf[linbuf.length()-1] == ' ')
trailing_space = true;
if( leading_space || trailing_space )
Trim(linbuf);
}
if( line.empty() && linbuf.empty() )
continue;
if( !linbuf.empty() ) {
has_equal = (linbuf.find('=') != string::npos);
if( maybe_continued && has_equal ) {
assert( !line.empty() );
fsetpos(file, &oldpos);
break;
}
} else if( continued || comment ) {
continue;
} else {
break;
}
if( line.empty() && !continued && has_equal ) {
maybe_continued = true;
}
unfinished = (continued || maybe_continued);
if( maybe_continued || (trailing_space && continued) )
linbuf += ' ';
if( leading_space && !line.empty() && line[line.length()-1] != ' ')
line += ' ';
line.append(linbuf);
}
if( maybe_continued ) {
if( r == EOF ) {
fsetpos(file, &oldpos);
r = 0;
}
assert( !line.empty() );
if( line[line.length()-1] == ' ')
line.erase(line.length()-1);
}
return r;
}
Int_t THaAnalysisObject::LoadDBvalue( FILE* file, const TDatime& date,
const char* key, string& text )
{
if( !file || !key ) return -255;
TDatime keydate(950101,0), prevdate(950101,0);
errno = 0;
errtxt.clear();
rewind(file);
static const size_t bufsiz = 256;
char* buf = new char[bufsiz];
bool found = false, ignore = false;
string dbline;
vector<string> lines;
while( ReadDBline(file, buf, bufsiz, dbline) != EOF ) {
if( dbline.empty() ) continue;
lines.assign( 1, dbline );
gHaTextvars->Substitute( lines );
for( vsiter_t it = lines.begin(); it != lines.end(); ++it ) {
string& line = *it;
Int_t status;
if( !ignore && (status = IsDBkey( line, key, text )) != 0 ) {
if( status > 0 ) {
found = true;
prevdate = keydate;
}
} else if( IsDBdate( line, keydate ) != 0 )
ignore = ( keydate>date || keydate<prevdate );
}
}
delete [] buf;
if( errno ) {
perror( "THaAnalysisObject::LoadDBvalue" );
return -1;
}
return found ? 0 : 1;
}
Int_t THaAnalysisObject::LoadDBvalue( FILE* file, const TDatime& date,
const char* key, Double_t& value )
{
string text;
Int_t err = LoadDBvalue( file, date, key, text );
if( err == 0 )
value = atof(text.c_str());
return err;
}
Int_t THaAnalysisObject::LoadDBvalue( FILE* file, const TDatime& date,
const char* key, Int_t& value )
{
string text;
Int_t err = LoadDBvalue( file, date, key, text );
if( err == 0 )
value = atoi(text.c_str());
return err;
}
Int_t THaAnalysisObject::LoadDBvalue( FILE* file, const TDatime& date,
const char* key, TString& text )
{
string _text;
Int_t err = LoadDBvalue( file, date, key, _text );
if( err == 0 )
text = _text.c_str();
return err;
}
template <class T>
Int_t THaAnalysisObject::LoadDBarray( FILE* file, const TDatime& date,
const char* key, vector<T>& values )
{
string text;
Int_t err = LoadDBvalue( file, date, key, text );
if( err )
return err;
values.clear();
text += " ";
ISSTREAM inp(text);
T dval;
while( 1 ) {
inp >> dval;
if( inp.good() )
values.push_back(dval);
else
break;
}
return 0;
}
template <class T>
Int_t THaAnalysisObject::LoadDBmatrix( FILE* file, const TDatime& date,
const char* key,
vector<vector<T> >& values,
UInt_t ncols )
{
vector<T>* tmpval = new vector<T>;
if( !tmpval )
return -255;
Int_t err = LoadDBarray( file, date, key, *tmpval );
if( err ) {
delete tmpval;
return err;
}
if( (tmpval->size() % ncols) != 0 ) {
delete tmpval;
errtxt = "key = "; errtxt += key;
return -129;
}
values.clear();
typename vector<vector<T> >::size_type nrows = tmpval->size()/ncols, irow;
for( irow = 0; irow < nrows; ++irow ) {
vector<T> row;
for( typename vector<T>::size_type i=0; i<ncols; ++i ) {
row.push_back( tmpval->at(i+irow*ncols) );
}
values.push_back( row );
}
delete tmpval;
return 0;
}
Int_t THaAnalysisObject::LoadDB( FILE* f, const TDatime& date,
const DBRequest* req, Int_t search )
{
TString here(GetClassName());
here.Append("::LoadDB");
return LoadDB( f, date, req, GetPrefix(), search, here.Data() );
}
#define CheckLimits(T,val) \
if( (val) < std::numeric_limits<T>::min() || \
(val) > std::numeric_limits<T>::max() ) { \
OSSTREAM txt; \
txt << (val); \
errtxt = txt.str(); \
goto rangeerr; \
}
#define CheckLimitsUnsigned(T,val) \
if( (val) < 0 || static_cast<T>(val) > std::numeric_limits<T>::max() ) { \
OSSTREAM txt; \
txt << (val); \
errtxt = txt.str(); \
goto rangeerr; \
}
Int_t THaAnalysisObject::LoadDB( FILE* f, const TDatime& date,
const DBRequest* req, const char* prefix,
Int_t search, const char* here )
{
if( !req ) return -255;
if( !prefix ) prefix = "";
Int_t ret = 0;
if( loaddb_depth++ == 0 )
loaddb_prefix = prefix;
const DBRequest* item = req;
while( item->name ) {
if( item->var ) {
string keystr = prefix; keystr.append(item->name);
UInt_t nelem = item->nelem;
const char* key = keystr.c_str();
if( item->type == kDouble || item->type == kFloat ) {
if( nelem < 2 ) {
Double_t dval;
ret = LoadDBvalue( f, date, key, dval );
if( ret == 0 ) {
if( item->type == kDouble )
*((Double_t*)item->var) = dval;
else {
CheckLimits( Float_t, dval );
*((Float_t*)item->var) = dval;
}
}
} else {
vector<double> dvals;
ret = LoadDBarray( f, date, key, dvals );
if( static_cast<UInt_t>(dvals.size()) != nelem ) {
nelem = dvals.size();
ret = -130;
} else if( ret == 0 ) {
if( item->type == kDouble ) {
for( UInt_t i = 0; i < nelem; i++ )
((Double_t*)item->var)[i] = dvals[i];
} else {
for( UInt_t i = 0; i < nelem; i++ ) {
CheckLimits( Float_t, dvals[i] );
((Float_t*)item->var)[i] = dvals[i];
}
}
}
}
} else if( item->type >= kInt && item->type <= kByte ) {
if( nelem < 2 ) {
Int_t ival;
ret = LoadDBvalue( f, date, key, ival );
if( ret == 0 ) {
switch( item->type ) {
case kInt:
*((Int_t*)item->var) = ival;
break;
case kUInt:
CheckLimitsUnsigned( UInt_t, ival );
*((UInt_t*)item->var) = ival;
break;
case kShort:
CheckLimits( Short_t, ival );
*((Short_t*)item->var) = ival;
break;
case kUShort:
CheckLimitsUnsigned( UShort_t, ival );
*((UShort_t*)item->var) = ival;
break;
case kChar:
CheckLimits( Char_t, ival );
*((Char_t*)item->var) = ival;
break;
case kByte:
CheckLimitsUnsigned( Byte_t, ival );
*((Byte_t*)item->var) = ival;
break;
default:
goto badtype;
}
}
} else {
vector<Int_t> ivals;
ret = LoadDBarray( f, date, key, ivals );
if( static_cast<UInt_t>(ivals.size()) != nelem ) {
nelem = ivals.size();
ret = -130;
} else if( ret == 0 ) {
switch( item->type ) {
case kInt:
for( UInt_t i = 0; i < nelem; i++ )
((Int_t*)item->var)[i] = ivals[i];
break;
case kUInt:
for( UInt_t i = 0; i < nelem; i++ ) {
CheckLimitsUnsigned( UInt_t, ivals[i] );
((UInt_t*)item->var)[i] = ivals[i];
}
break;
case kShort:
for( UInt_t i = 0; i < nelem; i++ ) {
CheckLimits( Short_t, ivals[i] );
((Short_t*)item->var)[i] = ivals[i];
}
break;
case kUShort:
for( UInt_t i = 0; i < nelem; i++ ) {
CheckLimitsUnsigned( UShort_t, ivals[i] );
((UShort_t*)item->var)[i] = ivals[i];
}
break;
case kChar:
for( UInt_t i = 0; i < nelem; i++ ) {
CheckLimits( Char_t, ivals[i] );
((Char_t*)item->var)[i] = ivals[i];
}
break;
case kByte:
for( UInt_t i = 0; i < nelem; i++ ) {
CheckLimitsUnsigned( Byte_t, ivals[i] );
((Byte_t*)item->var)[i] = ivals[i];
}
break;
default:
goto badtype;
}
}
}
} else if( item->type == kString ) {
ret = LoadDBvalue( f, date, key, *((string*)item->var) );
} else if( item->type == kTString ) {
ret = LoadDBvalue( f, date, key, *((TString*)item->var) );
} else if( item->type == kFloatV ) {
ret = LoadDBarray( f, date, key, *((vector<float>*)item->var) );
if( ret == 0 && nelem > 0 && nelem !=
static_cast<UInt_t>(((vector<float>*)item->var)->size()) ) {
nelem = ((vector<float>*)item->var)->size();
ret = -130;
}
} else if( item->type == kDoubleV ) {
ret = LoadDBarray( f, date, key, *((vector<double>*)item->var) );
if( ret == 0 && nelem > 0 && nelem !=
static_cast<UInt_t>(((vector<double>*)item->var)->size()) ) {
nelem = ((vector<double>*)item->var)->size();
ret = -130;
}
} else if( item->type == kIntV ) {
ret = LoadDBarray( f, date, key, *((vector<Int_t>*)item->var) );
if( ret == 0 && nelem > 0 && nelem !=
static_cast<UInt_t>(((vector<Int_t>*)item->var)->size()) ) {
nelem = ((vector<Int_t>*)item->var)->size();
ret = -130;
}
} else if( item->type == kFloatM ) {
ret = LoadDBmatrix( f, date, key,
*((vector<vector<float> >*)item->var), nelem );
} else if( item->type == kDoubleM ) {
ret = LoadDBmatrix( f, date, key,
*((vector<vector<double> >*)item->var), nelem );
} else if( item->type == kIntM ) {
ret = LoadDBmatrix( f, date, key,
*((vector<vector<Int_t> >*)item->var), nelem );
} else {
badtype:
if( item->type >= kDouble && item->type <= kObject2P )
::Error( ::Here(here,loaddb_prefix.c_str()),
"Key \"%s\": Reading of data type \"%s\" not implemented",
key, THaVar::GetEnumName(item->type) );
else
::Error( ::Here(here,loaddb_prefix.c_str()),
"Key \"%s\": Reading of data type \"(#%d)\" not implemented",
key, item->type );
ret = -2;
break;
rangeerr:
::Error( ::Here(here,loaddb_prefix.c_str()),
"Key \"%s\": Value %s out of range for requested type \"%s\"",
key, errtxt.c_str(), THaVar::GetEnumName(item->type) );
ret = -3;
break;
}
if( ret == 0 ) {
goto nextitem;
} else if( ret > 0 ) {
Int_t newsearch = (item->search != 0) ? item->search : search;
if( newsearch != 0 && *prefix ) {
string newprefix(prefix);
Int_t newlevel = ChopPrefix(newprefix) + 1;
if( newsearch < 0 || newlevel >= newsearch ) {
DBRequest newreq[2];
newreq[0] = *item;
memset( newreq+1, 0, sizeof(DBRequest) );
newreq->search = 0;
if( newsearch < 0 )
newsearch++;
ret = LoadDB( f, date, newreq, newprefix.c_str(), newsearch, here );
if( ret != 0 )
break;
goto nextitem;
}
}
if( item->optional )
ret = 0;
else {
if( item->descript ) {
::Error( ::Here(here,loaddb_prefix.c_str()),
"Required key \"%s\" (%s) missing in the database.",
key, item->descript );
} else {
::Error( ::Here(here,loaddb_prefix.c_str()),
"Required key \"%s\" missing in the database.", key );
}
ret = 1+(item-req);
break;
}
} else if( ret == -128 ) {
::Error( ::Here(here,loaddb_prefix.c_str()),
"Text line too long. Fix the database!\n\"%s...\"",
errtxt.c_str() );
break;
} else if( ret == -129 ) {
::Error( ::Here(here,loaddb_prefix.c_str()),
"Number of matrix elements not evenly divisible by requested "
"number of columns. Fix the database!\n\"%s...\"",
errtxt.c_str() );
break;
} else if( ret == -130 ) {
::Error( ::Here(here,loaddb_prefix.c_str()),
"Incorrect number of array elements found for key = %s. "
"%u requested, %u found. Fix database.", keystr.c_str(),
item->nelem, nelem );
break;
} else {
::Error( ::Here(here,loaddb_prefix.c_str()),
"Program error when trying to read database key \"%s\". "
"CALL EXPERT!", key );
break;
}
}
nextitem:
item++;
}
if( --loaddb_depth == 0 )
loaddb_prefix.clear();
return ret;
}
Int_t THaAnalysisObject::SeekDBconfig( FILE* file, const char* tag,
const char* label,
Bool_t end_on_tag )
{
if( !file || !tag || !*tag ) return 0;
string _label("[");
if( label && *label ) {
_label.append(label); _label.append("=");
}
ssiz_t llen = _label.size();
bool found = false;
errno = 0;
off_t pos = ftello(file);
if( pos != -1 ) {
bool quit = false;
const int LEN = 256;
char buf[LEN];
while( !errno && !found && !quit && fgets( buf, LEN, file)) {
size_t len = strlen(buf);
if( len<2 || buf[0] == '#' ) continue;
if( buf[len-1] == '\n') buf[len-1] = 0;
char* cbuf = ::Compress(buf);
string line(cbuf); delete [] cbuf;
ssiz_t lbrk = line.find(_label);
if( lbrk != string::npos && lbrk+llen < line.size() ) {
ssiz_t rbrk = line.find(']',lbrk+llen);
if( rbrk == string::npos ) continue;
if( line.substr(lbrk+llen,rbrk-lbrk-llen) == tag ) {
found = true;
break;
}
} else if( end_on_tag && IsTag(buf) )
quit = true;
}
}
if( errno ) {
perror( "THaAnalysisObject::SeekDBconfig" );
found = false;
}
if( !found && pos >= 0 )
fseeko( file, pos, SEEK_SET );
return found;
}
Int_t THaAnalysisObject::SeekDBdate( FILE* file, const TDatime& date,
Bool_t end_on_tag )
{
static const char* const here = "THaAnalysisObject::SeekDBdateTag";
if( !file ) return 0;
const int LEN = 256;
char buf[LEN];
TDatime tagdate(950101,0), prevdate(950101,0);
const bool kNoWarn = false;
errno = 0;
off_t pos = ftello(file);
if( pos == -1 ) {
if( errno )
perror(here);
return 0;
}
off_t foundpos = -1;
bool found = false, quit = false;
while( !errno && !quit && fgets( buf, LEN, file)) {
size_t len = strlen(buf);
if( len<2 || buf[0] == '#' ) continue;
if( buf[len-1] == '\n') buf[len-1] = 0;
string line(buf);
if( IsDBdate( line, tagdate, kNoWarn )
&& tagdate<=date && tagdate>=prevdate ) {
prevdate = tagdate;
foundpos = ftello(file);
found = true;
} else if( end_on_tag && IsTag(buf))
quit = true;
}
if( errno ) {
perror(here);
found = false;
}
fseeko( file, (found ? foundpos: pos), SEEK_SET );
return found;
}
vector<string> THaAnalysisObject::vsplit(const string& s)
{
vector<string> ret;
typedef string::size_type ssiz_t;
ssiz_t i = 0;
while ( i != s.size()) {
while (i != s.size() && isspace(s[i])) ++i;
ssiz_t j = i;
while (j != s.size() && !isspace(s[j])) ++j;
if (i != j) {
ret.push_back(s.substr(i, j-i));
i = j;
}
}
return ret;
}
TString& THaAnalysisObject::GetObjArrayString( const TObjArray* array, Int_t i )
{
return (static_cast<TObjString*>(array->At(i)))->String();
}
void THaAnalysisObject::Print( Option_t* ) const
{
cout << "AOBJ: " << IsA()->GetName()
<< "\t" << GetName()
<< "\t\"";
if( fPrefix )
cout << fPrefix;
cout << "\"\t" << GetTitle()
<< endl;
}
void THaAnalysisObject::PrintObjects( Option_t* opt )
{
TIter next(fgModules);
TObject* obj;
while( (obj = next()) ) {
obj->Print(opt);
}
}
ClassImp(THaAnalysisObject)