ROOT logo
//-*- Mode: C++ -*-
// $Id$

/// @file   run-macro.C
/// @author Matthias.Richter@ift.uib.no
/// @date   2012-04-06
/// @brief  Compile and run a macro
///
/// Dependency header files and classes are automatically searched in the
/// current directory and in all AliRoot libraries

#if defined(__CINT__) && !defined(__MAKECINT__)
TString GetIncludeHeaders(const char* filename, TString& headers, TString& libs, bool loadClass=true);

void run_macro(const char* macro, bool bExecute=true, const char* includePath=NULL, const char* libraries=NULL)
{
  gSystem->AddIncludePath("-I$ROOTSYS/include -I$ALICE_ROOT -I$ALICE_ROOT/include ");
  if (includePath) gSystem->AddIncludePath(includePath);

  TString strLibraries(libraries);
  TObjArray* tokens=strLibraries.Tokenize(" ");
  if (tokens) {
    TIter next(tokens);
    TObject* object=NULL;
    while ((object=next())!=NULL) {
      gSystem->Load(object->GetName());
    }
    delete tokens;
  }

  TString dependencyHeader;
  TString dependencyLibraries;
  GetIncludeHeaders(macro, dependencyHeader, dependencyLibraries, true);

  TString command(macro);
  Int_t error=0;
  command+="+g";
  if (bExecute) {
    gROOT->Macro(command); 
  } else {
    gROOT->LoadMacro(command);
  }
}

TString GetIncludeHeaders(const char* filename, TString& headers, TString& libs, bool loadClass)
{
  // scan the file and add all include headers found by path
  // to the parameter headers
  ifstream input(filename);
  
  if (input.bad()) {
    cerr << "failed to open file " << filename << endl;
    return headers;
  }
  TString line; 
  while (!line.ReadLine(input).eof()) {
    if (!line.Contains("#include") || !line.Contains(".h")) continue;
    line=line(0, line.Index(".h"));line+=".h";
    line.Replace(0, line.Index("#include"), "");
    line.ReplaceAll("#include", "");
    line.ReplaceAll(" ", "");
    line.ReplaceAll("\"", "");
    if (!line.BeginsWith("Ali") && !line.BeginsWith("T")) continue;
    if (gSystem->AccessPathName(line)!=0) {
      // not an include file in the current directory, check if class
      // is available or find library
      line.ReplaceAll(".h","");
      //cout << "checking class " << line << endl;
      if (TClass::GetClass(line)==NULL) {
	TString command;
	TString resfilename(gSystem->TempDirectory()); resfilename+="/findlib.txt";
	command.Form("for lib in $ALICE_ROOT/lib/*/lib*.so; do (nm $lib | grep %s | grep ' T ' | grep Class_Name > /dev/null) && echo $lib > %s; done", line.Data(), resfilename.Data());
	gSystem->Exec(command);
	ifstream resfile(resfilename.Data());
	if (resfile.good()) {
	  TString result;
	  if (!result.ReadLine(resfile).eof()) {
	    Ssiz_t haveSlash=-1;
	    while ((haveSlash=result.First('/'))>=0) result.Replace(0, haveSlash+1, "");
	    if (!libs.Contains(result)) {
	      cout << "loading dependency library '" << result << "' for class '" << line << "'" << endl;
	      gSystem->Load(result);
	      if (!libs.IsNull()) libs+=" ";
	      libs+=result;
	    }
	  }
	  command="rm "; command+=resfilename;
	  gSystem->Exec(command);
	}
      }
    } else {
      if (headers.Contains(line)) {
        if (!headers.BeginsWith(line)) {
          headers.ReplaceAll(line, "");
          if (!headers.IsNull()) headers.Insert(0, " ");
          headers.Insert(0, line);
        }
        continue;
      }
      if (!headers.IsNull()) headers.Insert(0, " ");
      headers.Insert(0, line);
      TString source=line; source.ReplaceAll(".h", ".cxx");
      if (gSystem->AccessPathName(source)==0) {
	GetIncludeHeaders(source, headers, libs);
      }
      GetIncludeHeaders(line, headers, libs);
      if (loadClass && gSystem->AccessPathName(source)==0) {
	line.ReplaceAll(".h", "");
	if (TClass::GetClass(line)==NULL) {
	  source+="+g";
	  gROOT->LoadMacro(source);
	}
      }
    }
  }
  return headers;
}

void run_macro()
{
  cout << endl;
  cout << "run-macro.C" << endl;
  cout << "Compile and run a macro, include header dependencies are searched in all" << endl;
  cout << "AliRoot libraries and the local directory." << endl;
  cout << endl;
  cout << "Usage:" << endl;
  cout << " aliroot -l run-macro.C'(\"macro.C\, execute, \"include\", \"libraries\")'" << endl;
  cout << endl;
  cout << "Parameters:" << endl;
  cout << " macro path (mandatory)" << endl;
  cout << " execute (optional, default 'true')" << endl;
  cout << " include (optional, e.g. -I$ALICE_ROOT/TPC)" << endl;
  cout << " libraries (optional, e.g. libTPCbase.so)" << endl;
  cout << endl;
}

#elif
{
  cerr << "this macro can not be compiled, remove option '+'" << endl;
}
#endif
 run-macro.C:1
 run-macro.C:2
 run-macro.C:3
 run-macro.C:4
 run-macro.C:5
 run-macro.C:6
 run-macro.C:7
 run-macro.C:8
 run-macro.C:9
 run-macro.C:10
 run-macro.C:11
 run-macro.C:12
 run-macro.C:13
 run-macro.C:14
 run-macro.C:15
 run-macro.C:16
 run-macro.C:17
 run-macro.C:18
 run-macro.C:19
 run-macro.C:20
 run-macro.C:21
 run-macro.C:22
 run-macro.C:23
 run-macro.C:24
 run-macro.C:25
 run-macro.C:26
 run-macro.C:27
 run-macro.C:28
 run-macro.C:29
 run-macro.C:30
 run-macro.C:31
 run-macro.C:32
 run-macro.C:33
 run-macro.C:34
 run-macro.C:35
 run-macro.C:36
 run-macro.C:37
 run-macro.C:38
 run-macro.C:39
 run-macro.C:40
 run-macro.C:41
 run-macro.C:42
 run-macro.C:43
 run-macro.C:44
 run-macro.C:45
 run-macro.C:46
 run-macro.C:47
 run-macro.C:48
 run-macro.C:49
 run-macro.C:50
 run-macro.C:51
 run-macro.C:52
 run-macro.C:53
 run-macro.C:54
 run-macro.C:55
 run-macro.C:56
 run-macro.C:57
 run-macro.C:58
 run-macro.C:59
 run-macro.C:60
 run-macro.C:61
 run-macro.C:62
 run-macro.C:63
 run-macro.C:64
 run-macro.C:65
 run-macro.C:66
 run-macro.C:67
 run-macro.C:68
 run-macro.C:69
 run-macro.C:70
 run-macro.C:71
 run-macro.C:72
 run-macro.C:73
 run-macro.C:74
 run-macro.C:75
 run-macro.C:76
 run-macro.C:77
 run-macro.C:78
 run-macro.C:79
 run-macro.C:80
 run-macro.C:81
 run-macro.C:82
 run-macro.C:83
 run-macro.C:84
 run-macro.C:85
 run-macro.C:86
 run-macro.C:87
 run-macro.C:88
 run-macro.C:89
 run-macro.C:90
 run-macro.C:91
 run-macro.C:92
 run-macro.C:93
 run-macro.C:94
 run-macro.C:95
 run-macro.C:96
 run-macro.C:97
 run-macro.C:98
 run-macro.C:99
 run-macro.C:100
 run-macro.C:101
 run-macro.C:102
 run-macro.C:103
 run-macro.C:104
 run-macro.C:105
 run-macro.C:106
 run-macro.C:107
 run-macro.C:108
 run-macro.C:109
 run-macro.C:110
 run-macro.C:111
 run-macro.C:112
 run-macro.C:113
 run-macro.C:114
 run-macro.C:115
 run-macro.C:116
 run-macro.C:117
 run-macro.C:118
 run-macro.C:119
 run-macro.C:120
 run-macro.C:121
 run-macro.C:122
 run-macro.C:123
 run-macro.C:124
 run-macro.C:125
 run-macro.C:126
 run-macro.C:127
 run-macro.C:128
 run-macro.C:129
 run-macro.C:130
 run-macro.C:131
 run-macro.C:132
 run-macro.C:133
 run-macro.C:134
 run-macro.C:135
 run-macro.C:136
 run-macro.C:137
 run-macro.C:138
 run-macro.C:139
 run-macro.C:140
 run-macro.C:141
 run-macro.C:142