Hi,
This is the ( completely unexpected ) fourth part of my MakeClass suite.
Please find attached a new version of the MakeClass.cxx macro.
The new root 2.22/05 ( just released ) contains a fix for a potential
problem that may arise with certain cases of ntuples. This fix is also
"imported" into the attached macro.
Users of root releases prior to 2.22/05 should comment out the line which
contains the string "SetAddress((void*)-1)", otherwise you may get
segmentation violations ( with certain cases of ntuples ).
All instructions / hints / advises / notes / warnings from previous three
parts of my MakeClass suite also apply ( there are no changes in example
files due to the newly introduced fix ).
Have fun,
Jacek.
// # MakeClass.cxx
// # How to generate and use the skeleton analysis class for a Tree.
//
// The following files are produced: classname.hxx and classname.cxx
// if classname is NULL, classname will be nameoftree.
//
// The generated code in classname.hxx includes the following:
// - Identification of the original Tree and Input File Name
// - Definition of analysis class (data and functions)
// - the following class functions:
// - classname(Char_t *filename = 0) to connect a file with Tree
// - classname(TTree *tree) to connect a Tree
// - ~classname()
// - GetEntries() to get the number of entries in Tree
// - GetEntry(Int_t entry) to prepare the filling of data from entry
// - Init(TTree *tree) to initialize with a new Tree
// - Loop(Int_t (*analysis)(classname *)) which loops over all entries
// in Tree calling the given analysis function for every entry, if
// the analysis function returns a non zero value, breaks the loop
// - Show(Int_t entry) to read and dump entry ( all branches )
//
// The generated code in classname.cxx includes only the skeleton of the
// main analysis function Loop().
//
// To use the MakeClass function:
// - connect your Tree file (eg: TFile f("myfile.root");)
// - MakeClass(T,"MyClass");
// where T is the name of the Tree in the myfile.root file, and
// MyClass.hxx, MyClass.cxx are names of files created by this function.
// Then, in a Root session, you can do, for example:
// Root > .L MyClass.cxx
// Root > MyClass t
// Root > t.GetEntry(12); // Prepare to fill t with entry number 12
// Root > t.Show(); // Show values of entry 12
// Root > t.Show(16); // Read and show values of entry 16
// Root > t.Loop(); // Loop over all entries
//
// # Int_t MakeClass(TTree *t, const char *classname = 0)
Int_t MakeClass(TTree *t, const char *classname = 0)
{
// # Check against an invalid Tree pointer
if (!t) return 1;
if (!t->IsA()->InheritsFrom("TTree")) {
printf("Attempt to MakeClass for a non-TTree object\n");
return 2;
}
// # Connect output files
char *thead = new char[256];
if (!classname) classname = t->GetName();
sprintf(thead,"%s.hxx",classname);
FILE *fp = fopen(thead,"w");
if (!fp) {
printf("Cannot open output file:%s\n",thead);
delete [] thead;
return 3;
}
char *tcimp = new char[256];
sprintf(tcimp,"%s.cxx",classname);
FILE *fpc = fopen(tcimp,"w");
if (!fpc) {
printf("Cannot open output file:%s\n",tcimp);
delete [] thead;
delete [] tcimp;
return 3;
}
char *treefile = new char[1000];
if (t->GetDirectory() && t->GetDirectory()->GetFile())
strcpy(treefile,t->GetDirectory()->GetFile()->GetName());
else strcpy(treefile,"Memory Directory");
// # *** Generate classname.hxx ***
// # Print the header
TObjArray *leaves = t->GetListOfLeaves();
Int_t nleaves = leaves->GetEntriesFast();
TDatime td;
fprintf(fp,"// # \n");
fprintf(fp,"// # This class has been automatically generated \n");
fprintf(fp,"// # (%s by ROOT version%s) \n",td.AsString(),gROOT->GetVersion());
fprintf(fp,"// # from TTree %s/%s \n",t->GetName(),t->GetTitle());
fprintf(fp,"// # found on file: %s \n",treefile);
fprintf(fp,"// # \n");
fprintf(fp,"\n");
fprintf(fp,"// # *** The %s class interface *** \n",classname);
fprintf(fp,"#ifndef %s_hxx\n",classname);
fprintf(fp,"#define %s_hxx\n",classname);
fprintf(fp,"\n");
fprintf(fp,"// # Required includes \n");
fprintf(fp,"#ifndef __CINT__\n");
fprintf(fp,"#include <stdio.h>\n");
fprintf(fp,"#include <stream.h>\n");
fprintf(fp,"#include \"TROOT.h\"\n");
fprintf(fp,"#include \"TTree.h\"\n");
fprintf(fp,"#include \"TFile.h\"\n");
fprintf(fp,"#include \"Api.h\"\n");
fprintf(fp,"#else\n");
fprintf(fp,"class TBranch;\n");
fprintf(fp,"class TTree;\n");
fprintf(fp,"class TFile;\n");
fprintf(fp,"#endif\n");
fprintf(fp,"\n");
fprintf(fp,"// # class %s \n",classname);
fprintf(fp,"class %s {\n",classname);
fprintf(fp,"public:\n");
fprintf(fp," // # public variables \n");
fprintf(fp," TTree *fTree; // pointer to the analysed TTree\n");
fprintf(fp," Int_t fEntry; // current entry number\n");
// # Loop on all leaves to generate branch and leaf declarations
fprintf(fp," // # declaration of branches and leaves \n");
Int_t len, l;
TLeaf *leafcount;
TLeafObject *leafobj;
char *bname;
const char *headOK = " ";
const char *headcom = " // ";
const char *head;
char branchname[64];
char leafname[64];
TObjArray branches(nleaves/4 + 1);
Int_t *leafStatus = new Int_t[nleaves];
for (l=0;l<nleaves;l++) {
leafStatus[l] = 0;
TLeaf *leaf = (TLeaf*)leaves->UncheckedAt(l);
len = leaf->GetLen();
leafcount = leaf->GetLeafCount();
TBranch *branch = leaf->GetBranch();
if (!branches.FindObject(branch)) {
branches.Add(branch);
strcpy(branchname,branch->GetName());
bname = strstr(branchname,"[");
if (bname) *bname = 0;
bname = branchname;
while (*bname) {if (*bname == '.') *bname='_'; bname++;}
fprintf(fp," // branch %s\n",branch->GetName());
fprintf(fp," Int_t IsRead_%s;\n",branchname);
fprintf(fp," TBranch *b_%s;\n",branchname);
} else leafStatus[l] = 1;
if (leafcount) strcpy(leafname,branch->GetName());
else strcpy(leafname,leaf->GetTitle());
bname = strstr(leafname,"[");
if (bname) *bname = 0;
bname = leafname;
while (*bname) {if (*bname == '.') *bname='_'; bname++;}
char *twodim = (char*)strstr(leaf->GetTitle(),"][");
head = headOK;
if (branch->IsA() == TBranchObject::Class()) {
if (branch->GetListOfBranches()->GetEntriesFast()) continue;
leafobj = (TLeafObject*)leaf;
if (!leafobj->GetClass()) head = headcom;
fprintf(fp,"%s%-15s *l_%s;\n",head,leafobj->GetTypeName(),leafobj->GetName());
fprintf(fp,"%s%-15s *%s() {",head,leafobj->GetTypeName(),leafobj->GetName());
fprintf(fp,"if (IsRead_%s) return l_%s;",branchname,leafobj->GetName());
fprintf(fp,"b_%s->GetEntry(fEntry);",branchname);
fprintf(fp,"IsRead_%s=1;return l_%s;}\n",branchname,leafobj->GetName());
continue;
}
if (leafcount) {
len = leafcount->GetMaximum();
if (twodim) {
fprintf(fp,"%s%-15s l_%s[%d]%s;\n",head,leaf->GetTypeName(),leafname,len,(char*)(twodim + 1));
// fprintf(fp,"%s%-15s (&%s())[%d]%s {",head,leaf->GetTypeName(),leafname,len,(char*)(twodim + 1));
fprintf(fp,"%s%-15s (*%s())%s {",head,leaf->GetTypeName(),leafname,(char*)(twodim + 1));
fprintf(fp,"if (IsRead_%s) return l_%s;",branchname,leafname);
fprintf(fp,"b_%s->GetEntry(fEntry);",branchname);
fprintf(fp,"IsRead_%s=1;return l_%s;}\n",branchname,leafname);
} else {
fprintf(fp,"%s%-15s l_%s[%d];\n",head,leaf->GetTypeName(),leafname,len);
// fprintf(fp,"%s%-15s (&%s())[%d] {",head,leaf->GetTypeName(),leafname,len);
fprintf(fp,"%s%-15s *%s() {",head,leaf->GetTypeName(),leafname);
fprintf(fp,"if (IsRead_%s) return l_%s;",branchname,leafname);
fprintf(fp,"b_%s->GetEntry(fEntry);",branchname);
fprintf(fp,"IsRead_%s=1;return l_%s;}\n",branchname,leafname);
}
} else {
fprintf(fp,"%s%-15s l_%s;\n",head,leaf->GetTypeName(),leafname);
fprintf(fp,"%s%-15s &%s() {",head,leaf->GetTypeName(),leafname);
fprintf(fp,"if (IsRead_%s) return l_%s;",branchname,leafname);
fprintf(fp,"b_%s->GetEntry(fEntry);",branchname);
fprintf(fp,"IsRead_%s=1;return l_%s;}\n",branchname,leafname);
}
}
// # Generate class member functions prototypes
fprintf(fp," \n");
fprintf(fp," // # public functions \n");
fprintf(fp," %s(Char_t *filename = 0);\n",classname);
fprintf(fp," %s(TTree *tree) {if (!tree) %s();else Init(tree);}\n",classname,classname);
fprintf(fp," ~%s() {;}\n",classname);
fprintf(fp," Stat_t GetEntries() {if (!fTree) return 0;return fTree->GetEntries();}\n");
fprintf(fp," Int_t GetEntry(Int_t entry);\n");
fprintf(fp," void Init(TTree *tree);\n");
fprintf(fp," Int_t Loop();\n");
fprintf(fp," Int_t Loop(Int_t (*analysis)(%s *));\n",classname);
fprintf(fp," void Show(Int_t entry = -1);\n");
fprintf(fp,"};\n");
fprintf(fp,"\n");
fprintf(fp,"#endif\n");
fprintf(fp,"\n");
fprintf(fp,"// # *** The %s class implementation *** \n",classname);
fprintf(fp,"#ifdef %s_cxx\n",classname);
fprintf(fp,"\n");
// # Generate class constructor classname(Char_t *filename)
fprintf(fp,"// # %s::%s(Char_t *filename) \n",classname,classname);
fprintf(fp,"%s::%s(Char_t *filename)\n",classname,classname);
fprintf(fp,"{\n");
fprintf(fp," // # If parameter filename is not specified (or zero), connect the file \n");
fprintf(fp," // # used to generate this class ( %s ). \n",treefile);
fprintf(fp," if (!filename || !(*filename)) {\n");
fprintf(fp," filename = \"%s\";\n",treefile);
fprintf(fp," }\n");
fprintf(fp," // # Find the required file in ROOT and, if not found, open it. \n");
fprintf(fp," TFile *f = (TFile*)gROOT->GetListOfFiles()->FindObject(filename);\n");
fprintf(fp," if (!f) {\n");
fprintf(fp," f = new TFile(filename);\n");
fprintf(fp," }\n");
fprintf(fp," // # Find the %s tree and initialize object. \n",t->GetName());
fprintf(fp," TTree *t = (TTree*)gDirectory->Get(\"%s\");\n",t->GetName());
fprintf(fp," Init(t);\n");
fprintf(fp,"}\n");
fprintf(fp,"\n");
// # Generate class member function GetEntry(Int_t entry)
fprintf(fp,"// # Int_t %s::GetEntry(Int_t entry) \n",classname);
fprintf(fp,"Int_t %s::GetEntry(Int_t entry)\n",classname);
fprintf(fp,"{\n");
fprintf(fp," // # Prepare to read specified entry from the Tree. \n");
fprintf(fp," // # In case the entry is already read, just return. \n");
fprintf(fp," if (!fTree) return 0;\n");
fprintf(fp," if (fEntry==entry) return 1;\n");
fprintf(fp," fEntry = entry;\n");
fprintf(fp," // # Set branch statuses to 0. \n");
for (l=0;l<nleaves;l++) {
if (leafStatus[l]) continue;
TLeaf *leaf = (TLeaf*)leaves->UncheckedAt(l);
TBranch *branch = leaf->GetBranch();
strcpy(branchname,branch->GetName());
bname = strstr(branchname,"[");
if (bname) *bname = 0;
bname = branchname;
while (*bname) {if (*bname == '.') *bname='_'; bname++;}
fprintf(fp," IsRead_%s = 0;\n",branchname);
}
fprintf(fp," // # We are done, return. \n");
fprintf(fp," return 1;\n");
fprintf(fp,"}\n");
fprintf(fp,"\n");
// # Generate class member function Init(TTree *tree)
fprintf(fp,"// # void %s::Init(TTree *tree) \n",classname);
fprintf(fp,"void %s::Init(TTree *tree)\n",classname);
fprintf(fp,"{\n");
fprintf(fp," // # Initialize public variables. \n");
fprintf(fp," fTree = tree;\n");
fprintf(fp," fEntry = -1;\n");
fprintf(fp," if (!tree) return;\n");
fprintf(fp," // # Set branch statuses to 0, get branch pointers, \n");
fprintf(fp," // # set branch addresses. \n");
fprintf(fp," fTree->SetBranchStatus(\"*\",1); // enable all branches\n");
for (l=0;l<nleaves;l++) {
if (leafStatus[l]) continue;
TLeaf *leaf = (TLeaf*)leaves->UncheckedAt(l);
len = leaf->GetLen();
leafcount = leaf->GetLeafCount();
TBranch *branch = leaf->GetBranch();
strcpy(branchname,branch->GetName());
bname = strstr(branchname,"[");
if (bname) *bname = 0;
bname = branchname;
while (*bname) {if (*bname == '.') *bname='_'; bname++;}
if (leafcount) strcpy(leafname,branch->GetName());
else strcpy(leafname,leaf->GetTitle());
bname = strstr(leafname,"[");
if (bname) *bname = 0;
bname = leafname;
while (*bname) {if (*bname == '.') *bname='_'; bname++;}
fprintf(fp," // branch %s\n",branch->GetName());
fprintf(fp," IsRead_%s = 0;\n",branchname);
head = headOK;
if (branch->IsA() == TBranchObject::Class()) {
if (branch->GetListOfBranches()->GetEntriesFast()) {
fprintf(fp,"%sb_%s = fTree->GetBranch(\"%s\");\n",head,branchname,branch->GetName());
fprintf(fp,"%sb_%s->SetAddress((void*)-1);\n",head,branchname);
fprintf(fp,"%sfTree->SetBranchStatus(\"%s\",0); // disable this branch\n",head,branch->GetName());
continue;
}
leafobj = (TLeafObject*)leaf;
if (!leafobj->GetClass()) head = headcom;
strcpy(leafname,branchname);
}
fprintf(fp,"%sb_%s = fTree->GetBranch(\"%s\");\n",head,branchname,branch->GetName());
if (leafcount) len = leafcount->GetMaximum() + 1;
if (len > 1) fprintf(fp,"%sb_%s->SetAddress(l_%s);\n",head,branchname,leafname);
else fprintf(fp,"%sb_%s->SetAddress(&l_%s);\n",head,branchname,leafname);
}
fprintf(fp,"}\n");
fprintf(fp,"\n");
// # Generate class member function Loop(Int_t (*analysis)(classname *))
fprintf(fp,"// # Int_t %s::Loop(Int_t (*analysis)(%s *)) \n",classname,classname);
fprintf(fp,"Int_t %s::Loop(Int_t (*analysis)(%s *))\n",classname,classname);
fprintf(fp,"{\n");
fprintf(fp," // # Execute the analysis function for every entry. In case the \n");
fprintf(fp," // # analysis function returns a non zero value, break the loop. \n");
fprintf(fp," if (!fTree || !analysis) return 0;\n");
fprintf(fp," \n");
fprintf(fp," // # Local variables ( common to compiled and interpreted code ). \n");
fprintf(fp," Stat_t nentries = GetEntries(); // Number of entries in the Tree.\n");
fprintf(fp," Int_t ientries = 0; // How many entries were analysed.\n");
fprintf(fp," \n");
fprintf(fp," // # This is the entry loop in compiled code. \n");
fprintf(fp,"#ifndef __CINT__\n");
fprintf(fp," \n");
fprintf(fp," // # First define some local variables and objects. \n");
fprintf(fp," char temp[64]; // INTERPRETEDFUNC\n");
fprintf(fp," long offset = 0; // INTERPRETEDFUNC\n");
fprintf(fp," G__ClassInfo globalscope; // INTERPRETEDFUNC\n");
fprintf(fp," G__CallFunc func; // INTERPRETEDFUNC, COMPILEDINTERFACEMETHOD, BYTECODEFUNC\n");
fprintf(fp," \n");
fprintf(fp," // # Then execute the loop. \n");
fprintf(fp," switch(G__isinterpretedp2f(((void*)analysis))) {\n");
fprintf(fp," // # using function call as string \n");
fprintf(fp," case G__INTERPRETEDFUNC:\n");
fprintf(fp," sprintf(temp,\"(%s *)%%p\",(void*)this);\n",classname);
fprintf(fp," func.SetFunc(&globalscope,(char*)analysis,temp,&offset);\n");
fprintf(fp," for (Int_t i=0; i<nentries; i++) {\n");
fprintf(fp," ientries += GetEntry(i);\n");
fprintf(fp," if (func.ExecInt((void*)NULL)) break;\n");
fprintf(fp," }\n");
fprintf(fp," break;\n");
fprintf(fp," // # using interface method \n");
fprintf(fp," case G__COMPILEDINTERFACEMETHOD:\n");
fprintf(fp," func.SetFunc((G__InterfaceMethod)analysis);\n");
fprintf(fp," func.SetArg(((long)this));\n");
fprintf(fp," for (Int_t i=0; i<nentries; i++) {\n");
fprintf(fp," ientries += GetEntry(i);\n");
fprintf(fp," if (func.ExecInt((void*)NULL)) break;\n");
fprintf(fp," }\n");
fprintf(fp," break;\n");
fprintf(fp," // # bytecode version of interpreted func \n");
fprintf(fp," case G__BYTECODEFUNC:\n");
fprintf(fp," func.SetBytecode((struct G__bytecodefunc*)analysis);\n");
fprintf(fp," func.SetArg(((long)this));\n");
fprintf(fp," for (Int_t i=0; i<nentries; i++) {\n");
fprintf(fp," ientries += GetEntry(i);\n");
fprintf(fp," if (func.ExecInt((void*)NULL)) break;\n");
fprintf(fp," }\n");
fprintf(fp," break;\n");
fprintf(fp," // # using true pointer to function \n");
fprintf(fp," case G__COMPILEDTRUEFUNC:\n");
fprintf(fp," // # pointer not in CINT global function table \n");
fprintf(fp," case G__UNKNOWNFUNC:\n");
fprintf(fp," for (Int_t i=0; i<nentries; i++) {\n");
fprintf(fp," ientries += GetEntry(i);\n");
fprintf(fp," if ((*analysis)(this)) break;\n");
fprintf(fp," }\n");
fprintf(fp," break;\n");
fprintf(fp," // # this should never happen ( unknown kind of pointer ) \n");
fprintf(fp," default:\n");
fprintf(fp," cerr << \"Error : Unknown kind of pointer to function\" << endl;\n");
fprintf(fp," break;\n");
fprintf(fp," }\n");
fprintf(fp," \n");
fprintf(fp," // # This is the entry loop in interpreted code. \n");
fprintf(fp,"#else\n");
fprintf(fp," \n");
fprintf(fp," // # current CINT cannot deal with this \n");
fprintf(fp,"#if 0\n");
fprintf(fp," for (Int_t i=0; i<nentries; i++) {\n");
fprintf(fp," ientries += GetEntry(i);\n");
fprintf(fp," if ((*analysis)(this)) break; // current CINT cannot deal with it\n");
fprintf(fp," }\n");
fprintf(fp," // # so we need to use this \n");
fprintf(fp,"#else\n");
fprintf(fp," Int_t result;\n");
fprintf(fp," for (Int_t i=0; i<nentries; i++) {\n");
fprintf(fp," ientries += GetEntry(i);\n");
fprintf(fp," result = (*analysis)(this);\n");
fprintf(fp," if (result) break;\n");
fprintf(fp," }\n");
fprintf(fp,"#endif\n");
fprintf(fp," \n");
fprintf(fp,"#endif\n");
fprintf(fp," \n");
fprintf(fp," // # We are done, return. \n");
fprintf(fp," return ientries;\n");
fprintf(fp,"}\n");
fprintf(fp,"\n");
// # Generate class member function Show(Int_t entry)
fprintf(fp,"// # void %s::Show(Int_t entry) \n",classname);
fprintf(fp,"void %s::Show(Int_t entry)\n",classname);
fprintf(fp,"{\n");
fprintf(fp," // # Print contents of entry ( all branches ). \n");
fprintf(fp," // # If entry is not specified, print current entry. \n");
fprintf(fp," if (!fTree) return;\n");
fprintf(fp," if (entry>=0) fEntry = entry; else entry = fEntry;\n");
fprintf(fp," if (fEntry<0) return;\n");
fprintf(fp," // # Set branch statuses to 1. \n");
fprintf(fp," fTree->SetBranchStatus(\"*\",1); // enable all branches\n");
for (l=0;l<nleaves;l++) {
if (leafStatus[l]) continue;
TLeaf *leaf = (TLeaf*)leaves->UncheckedAt(l);
TBranch *branch = leaf->GetBranch();
strcpy(branchname,branch->GetName());
bname = strstr(branchname,"[");
if (bname) *bname = 0;
bname = branchname;
while (*bname) {if (*bname == '.') *bname='_'; bname++;}
if ((branch->IsA() == TBranchObject::Class()) &&
(branch->GetListOfBranches()->GetEntriesFast())) {
fprintf(fp," IsRead_%s = 0;\n",branchname);
fprintf(fp," fTree->SetBranchStatus(\"%s\",0); // disable this branch\n",branch->GetName());
} else fprintf(fp," IsRead_%s = 1;\n",branchname);
}
fprintf(fp," // # Show entry. \n");
fprintf(fp," fTree->Show(fEntry);\n");
fprintf(fp,"}\n");
fprintf(fp,"\n");
fprintf(fp,"#endif\n");
fprintf(fp,"\n");
fprintf(fp,"// # End of file %s \n",thead);
// # *** Generate classname.cxx ***
// # Print the header
fprintf(fpc,"// # Include the %s class interface specification. \n",classname);
fprintf(fpc,"#ifndef %s_cxx\n",classname);
fprintf(fpc,"#define %s_cxx\n",classname);
fprintf(fpc,"#endif\n");
fprintf(fpc,"#include \"%s\"\n",thead);
fprintf(fpc,"#undef %s_cxx\n",classname);
fprintf(fpc,"\n");
fprintf(fpc,"// # Place here all ROOT related includes that you need. \n");
fprintf(fpc,"#ifndef __CINT__\n\n");
fprintf(fpc,"#endif\n");
fprintf(fpc,"\n");
// # Generate class member function Loop()
fprintf(fpc,"// # Int_t %s::Loop() \n",classname);
fprintf(fpc,"Int_t %s::Loop()\n",classname);
fprintf(fpc,"{\n");
// fprintf(fpc," if (!fTree) return;\n \n");
fprintf(fpc," // # Local variables. \n");
fprintf(fpc," Stat_t nentries = GetEntries(); // Number of entries in the Tree.\n");
fprintf(fpc," Int_t ientries = 0; // How many entries were analysed.\n");
fprintf(fpc," \n");
fprintf(fpc," // # This is the loop skeleton. \n");
fprintf(fpc," for (Int_t i=0; i<nentries; i++) {\n");
fprintf(fpc," ientries += GetEntry(i);\n");
fprintf(fpc," \n");
fprintf(fpc," }\n");
fprintf(fpc," \n");
fprintf(fpc," // # We are done, return. \n");
fprintf(fpc," return ientries;\n");
fprintf(fpc,"}\n");
fprintf(fpc,"\n");
fprintf(fpc,"// # End of file %s \n",tcimp);
// # We are done
printf("Files: %s and %s generated from Tree: %s\n",thead,tcimp,t->GetName());
delete [] thead;
delete [] tcimp;
delete [] treefile;
fclose(fp);
fclose(fpc);
return 0;
}
// # End of file MakeClass.cxx
This archive was generated by hypermail 2b29 : Tue Jan 04 2000 - 00:43:34 MET