MakeClass ( 103 )

From: Jacek M. Holeczek (holeczek@us.edu.pl)
Date: Tue Jun 15 1999 - 11:00:49 MEST


Hi,
Please find attached a new version of my MakeClass suite.
It's divided into two parts.
The first part ( this mail ) contains the MakeClass.cxx macro itself.
The second part will contain example files and notes how to use them.
Why a new MakeClass macro when we already have TTree:MakeClass ?
Usually during "rapid prototyping" I modify my code a lot, switch some
parts on, some off, ... . Unfortunately, I usually ( very often ) forget
to SetBranchStatus, enabling/disabling appropriate ( currently used )
ntuple branches. This leads to very difficult to find bugs ( if currently
used branches are "off" ), or slows down the analysis ( if currently
unneeded branches are "on" ).
I finally decided to implement a new MakeClass routine which generates
analysis code that reads the appropriate branches on demand ( during first
use of any leaf that belongs to the branch ).
For every "leaf" there is an automatically generated function in form :
    leaf_type &leaf() {
		      if (leaf_branch_already_read) return leaf_value;
		      read_branch_that_contains_this_leaf;
		      mark_leaf_branch_as_already_read;
		      //
		      // here you can place a piece of code which will
		      // modify the leaf_value after it is read, but
		      // before it is returned to the user, for example :
		      // leaf_value = sqrt(leaf_value)
		      //
		      return leaf_value;
		      }
These functions return a "reference/pointer" to the current leaf_value.
( Note that you don't have to know to which "branch" the "leaf" belongs,
it's managed automatically. )
You can simply write, for example :
    x = leaf();
You can also write :
    leaf() = x;
which will modify the leaf_value for the current entry number ( as soon
as you call the GetEntry function for a different entry number, the new
leaf_value will be read ). Note that you can modify the "leaf()"
function itself to perform any required leaf_value modifications, as
shown above in the "leaf()" function body itself ( "Not a bad trick,
Doc !" ). This feature is extremely useful if you are not interested
in the "leaf_value" as it is stored in the TTree, but in some kind of
a "function" of this value ( for example, "leaf" stored in the TTree,
but you are interested in "sqrt(leaf)" ).
The only "disadvantage" that I see is that accessing a "leaf" requires to
call a function "leaf()" ( instead of accessing a variable "leaf", as in
the original TTree::MakeClass ).
Of course, I know, calling a function is always slower then accessing
directly a variable, but ... if I subtract the time spent to find missing
SetBranchStatus ( it's managed internally by the generated code, you
shouldn't change it ) and the time spent to read unneeded branches ... .
Moreover, the decision to "read" ( or not ) a branch, happens on an "entry
by entry" basis. One "reads" only these branches that are currently
required. Of course, if one uses a specific "leaf" many times in one's
routine, it's just enough to write "register leaf_type leafleaf;
leafleaf = leaf(); ...", and then one can use the "leafleaf" as many
times as one wants in the routine. The "performance penalty" of
calling a function once is negligible.
Last, but not least, the additional advantage of my macro is that one
can easily build a shared library from the analysis code that it
produces ( which is impossible if one uses code generated by the
original TTree::MakeClass ). So, you can get the full compiled code
speed in accessing your ntuple ( also mixed with CINT flexibility, see
the second part that contains example files ).
Warning : CINT shipped with root 2.21/08 has some problems with leaves
that are pointers to arrays ( one cannot write "x = leaf()[1];
leaf()[1] = x", one must say "leaf_type *tmp; tmp = leaf(); x = tmp[1];
tmp[1] = x" ), but the new CINT, starting with root 2.22/04, works well.
Also, due to current CINT limitations, one cannot use code generated by
this macro for leaves that are pointers to multi-dimensional arrays
directly in CINT ( as a CINT macro ). One needs to compile the analysis
code and create the shared library.
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,"%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