// @(#)root/base:$Id$
// Author: Rene Brun   16/08/2005

/*************************************************************************
 * Copyright (C) 1995-2005, Rene Brun and Fons Rademakers.               *
 * All rights reserved.                                                  *
 *                                                                       *
 * For the licensing terms see $ROOTSYS/LICENSE.                         *
 * For the list of contributors see $ROOTSYS/README/CREDITS.             *
 *************************************************************************/


//////////////////////////////////////////////////////////////////////////
//                                                                      //
// TMacro                                                               //
//                                                                      //
// Class supporting a collection of lines with C++ code.                //
// A TMacro can be executed, saved to a ROOT file, edited, etc.         //
//                                                                      //
// A macro can be built line by line by calling the AddLine function.   //
// or it can be created directly from a file via the special constructor//
// when the first argument is a file name.                              //
//                                                                      //
// A macro can be executed via the Exec function.                       //
// Arguments can be specified when calling Exec.                        //
//                                                                      //
// A macro can be drawn in a pad. When the pad is updated, the macro is //
// automatically executed.                                              //
//                                                                      //
// The code in the macro can be saved via the SaveSource function.      //
// If the macro is in the list of primitives of a pad/canvas, the macro //
// will be saved in the script generated by TCanvas::SaveSource.        //
//                                                                      //
// A macro can be written to a ROOT file via TObject::Write.            //
//                                                                      //
// Examples:                                                            //
//   TMacro m("Peaks.C");  //macro m with name "Peaks" is created       //
//                         //from file  Peaks.C                         //
//   m.Exec();             //macro executed with default arguments      //
//   m.Exec("4");          //macro executed with argument               //
//   m.SaveSource("newPeaks.C");                                        //
//   TFile f("mymacros.root","recreate");                               //
//   m.Write();   //macro saved to file with name "Peaks"               //
//                                                                      //
//////////////////////////////////////////////////////////////////////////

#include "Riostream.h"
#include "TEnv.h"
#include "TList.h"
#include "TMacro.h"
#include "TMD5.h"
#include "TObjString.h"
#include "TROOT.h"
#include "TSystem.h"
#include <sstream>

ClassImp(TMacro)

//______________________________________________________________________________
TMacro::TMacro(): TNamed(), fLines(0)
{
   // Create an empty macro, use AddLine() or ReadFile() to fill this macro.
}

//______________________________________________________________________________
TMacro::TMacro(const char *name, const char *title): TNamed(name,title)
{
   // Create a macro with a name and a title.
   // If name contains a '.' it is assumed to be the name of a file, and
   // * the macro is automatically filled by reading all the lines in the file,
   // * if the title is empty, it will be set to the name of the file,
   // * the name will be set to the filename without path or extension.

   fLines  = new TList();
   if (!name) return;
   Int_t nch = strlen(name);
   char *s = new char[nch+1];
   strlcpy(s,name,nch+1);
   char *slash = (char*)strrchr(s,'/');
   if (!slash) slash = s;
   else ++slash;
   char *dot   = (char*)strchr(slash,'.');
   if (dot) {
      *dot = 0;
      fName = slash;
      if (fTitle.Length() == 0) fTitle = name;
      ReadFile(name);
   }
   delete [] s;
}

//______________________________________________________________________________
TMacro::TMacro(const TMacro &macro): TNamed(macro)
{
   // Copy constructor.

   fLines = new TList();
   TIter next(macro.GetListOfLines());
   TObjString *obj;
   while ((obj = (TObjString*) next())) {
      fLines->Add(new TObjString(obj->GetName()));
   }
   fParams = macro.fParams;
}

//______________________________________________________________________________
TMacro::~TMacro()
{
   // Delete this macro.

   if (fLines) fLines->Delete();
   delete fLines;
}

//______________________________________________________________________________
TMacro& TMacro::operator=(const TMacro &macro)
{
   // Copy constructor.

   if(this!=&macro) {
      TNamed::operator=(macro);
      if (fLines) fLines->Delete();
      delete fLines;
      fLines = new TList();
      TIter next(macro.GetListOfLines());
      TObjString *obj;
      while ((obj = (TObjString*) next())) {
         fLines->Add(new TObjString(obj->GetName()));
      }
      fParams = macro.fParams;
   }
   return *this;
}

//______________________________________________________________________________
TObjString *TMacro::AddLine(const char *text)
{
   // Add line with text in the list of lines of this macro.

   if (!fLines) fLines = new TList();
   TObjString *obj = new TObjString(text);
   fLines->Add(obj);
   return obj;
}

//______________________________________________________________________________
void TMacro::Browse(TBrowser * /*b*/)
{
   // When clicking in the browser, the following action is performed
   // on this macro, depending the content of the variable TMacro.Browse.
   // TMacro.Browse can be set in the system.rootrc or .rootrc file like
   //     TMacro.Browse   :  Action
   // or set via gEnv->SetValue, eg
   //     gEnv->SetValue("TMacro.Browse","Print");
   // By default TMacro.Browse=""
   // -if TMacro.Browse ="" the macro is executed
   // -if TMacro.Browse ="Print" the macro is printed in stdout
   // -if TMacro.Browse is of the form "mymacro.C"
   //     the macro void mymacro.C(TMacro *m) is called where m=this macro
   //     An example of macro.C saving the macro into a file and viewing it
   //     with emacs is shown below:
   //        void mymacro(TMacro *m) {
   //           m->SaveSource("xx.log");
   //           gSystem->Exec("emacs xx.log&");
   //        }

   TString opt = gEnv->GetValue("TMacro.Browse","");
   if (opt.IsNull()) {
      Exec();
      return;
   }
   if (opt == "Print") {
      Print();
      return;
   }
   if (opt.Contains(".C")) {
      const char *cmd = Form(".x %s((TMacro*)0x%lx)",opt.Data(),(ULong_t)this);
      gROOT->ProcessLine(cmd);
      return;
   }
}

//______________________________________________________________________________
TMD5 *TMacro::Checksum()
{
   // Returns checksum of the current content. The returned TMD5 object must
   // be deleted by the user. Returns 0 in case of error.

   if (!fLines || fLines->GetSize() <= 0)
      return (TMD5 *)0;

   TMD5 *md5 = new TMD5;

   // Fill (same params as in TMD5::FileChecksum)
   const Int_t bufSize = 8192;
   UChar_t buf[bufSize];
   Long64_t pos = 0;
   Long64_t left = bufSize;

   TIter nxl(fLines);
   TObjString *l;
   while ((l = (TObjString *) nxl())) {
      TString line = l->GetString();
      line += '\n';
      Int_t len = line.Length();
      char *p = (char *) line.Data();
      if (left > len) {
         strlcpy((char *)&buf[pos], p, len+1);
         pos += len;
         left -= len;
      } else if (left == len) {
         strlcpy((char *)&buf[pos], p, len+1);
         md5->Update(buf, bufSize);
         pos = 0;
         left = bufSize;
      } else {
         strlcpy((char *)&buf[pos], p, left+1);
         md5->Update(buf, bufSize);
         len -= left;
         p += left;
         pos = 0;
         left = bufSize;
         strlcpy((char *)&buf[pos], p, len+1);
         pos += len;
         left -= len;
      }
   }
   md5->Update(buf, pos);

   // Finalize
   md5->Final();

   return md5;
}

//______________________________________________________________________________
Bool_t TMacro::Load() const
{
   // Load the macro into the interpreter.
   // Return true in case the loading was successful.

   std::stringstream ss;

   TIter next(fLines);
   TObjString *obj;
   while ((obj = (TObjString*) next())) {
      ss << obj->GetName() << std::endl;
   }
   return gInterpreter->LoadText(ss.str().c_str());
}

//______________________________________________________________________________
Long_t TMacro::Exec(const char *params, Int_t* error)
{
   // Execute this macro with params, if params is 0, default parameters
   // (set via SetParams) are used.
   // error is set to an TInterpreter::EErrorCode by TApplication::ProcessLine().
   // Returns the result of the macro (return value or value of the last
   // expression), cast to a Long_t.

   if ( !gROOT->GetGlobalFunction(GetName(), 0, kTRUE) ) {
      if (!Load()) {
         if (error) *error = 1;
         return 0;
      }
   }

   // if macro has been executed, look for global function with name
   // of macro and re-execute this global function, if not found then
   // macro is unnamed macro, which we re-execute from file
   if ( gROOT->GetGlobalFunction(GetName(), 0, kTRUE) ) {
      gROOT->SetExecutingMacro(kTRUE);
      TString exec = GetName();
      TString p = params;
      if (p == "") p = fParams;
      if (p != "")
         exec += "(" + p + ")";
      else
         exec += "()";
      Long_t ret = gROOT->ProcessLine(exec, error);
      //enable gROOT->Reset
      gROOT->SetExecutingMacro(kFALSE);
      return ret;
   }

   Error("Exec","Macro does not contains function named %s.",GetName());
   if (error) *error = 1;
   return 0;
}

//______________________________________________________________________________
TObjString *TMacro::GetLineWith(const char *text) const
{
   // Search the first line containing text.

   if (!fLines) return 0;
   TIter next(fLines);
   TObjString *obj;
   while ((obj = (TObjString*) next())) {
      if (strstr(obj->GetName(),text)) return obj;
   }
   return 0;
}

//______________________________________________________________________________
void TMacro::Paint(Option_t *option)
{
   // Execute this macro (called by TPad::Paint).

   Exec(option);
}

//______________________________________________________________________________
void TMacro::Print(Option_t * /*option*/) const
{
   // Print contents of this macro.

   if (!fLines) return;
   TIter next(fLines);
   TObjString *obj;
   while ((obj = (TObjString*) next())) {
      printf("%s\n",obj->GetName());
   }
}

//______________________________________________________________________________
Int_t TMacro::ReadFile(const char *filename)
{
   // Read lines in filename in this macro.

   if (!fLines) fLines = new TList();
   std::ifstream in;
   in.open(filename);
   if (!in.good()) {
      Error("ReadFile","Cannot open file: %s",filename);
      return 0;
   }
   char *line = new char[10000];
   Int_t nlines = 0;
   while (1) {
      in.getline(line,10000);
      if (!in.good()) break;
      if (in.eof()) break;
      fLines->Add(new TObjString(line));
      nlines++;
   }
   delete [] line;
   return nlines;
}

//______________________________________________________________________________
void TMacro::SaveSource(const char *filename)
{
   // Save macro source in filename.

   std::ofstream out;
   out.open(filename, std::ios::out);
   if (!out.good ()) {
      Printf("SaveSource cannot open file: %s",filename);
      return;
   }
   if (!fLines) {out.close(); return;}
   TIter next(fLines);
   TObjString *obj;
   while ((obj = (TObjString*) next())) {
      out<<obj->GetName()<<std::endl;
   }
   out.close();
}

//______________________________________________________________________________
void TMacro::SaveSource(FILE *fp)
{
   // Save macro source in file pointer fp.

   if (!fLines) {fclose(fp); return;}
   TIter next(fLines);
   TObjString *obj;
   while ((obj = (TObjString*) next())) {
      fprintf(fp, "%s\n", obj->GetName());
   }
   fclose(fp);
}

//______________________________________________________________________________
void TMacro::SavePrimitive(std::ostream &out, Option_t *option /*= ""*/)
{
   // Save macro source on stream out.

   char quote = '"';
   out<<"   "<<std::endl;
   if (gROOT->ClassSaved(TMacro::Class())) {
      out<<"   ";
   } else {
      out<<"   "<<ClassName()<<" *";
   }
   out<<"macro = new "<<ClassName()<<"("<<quote<<GetName()<<quote<<","<<quote<<GetTitle()<<quote<<");"<<std::endl;
   if (!fLines) return;
   TIter next(fLines);
   TObjString *obj;
   while ((obj = (TObjString*) next())) {
      TString s = obj->GetName();
      s.ReplaceAll("\"","\\\"");
      out<<"   macro->AddLine("<<quote<<s.Data()<<quote<<");"<<std::endl;
   }
   out<<"   macro->Draw("<<quote<<option<<quote<<");"<<std::endl;
}

//______________________________________________________________________________
void TMacro::SetParams(const char *params)
{
   // Set default parameters to execute this macro.

   if (params) fParams = params;
}
 TMacro.cxx:1
 TMacro.cxx:2
 TMacro.cxx:3
 TMacro.cxx:4
 TMacro.cxx:5
 TMacro.cxx:6
 TMacro.cxx:7
 TMacro.cxx:8
 TMacro.cxx:9
 TMacro.cxx:10
 TMacro.cxx:11
 TMacro.cxx:12
 TMacro.cxx:13
 TMacro.cxx:14
 TMacro.cxx:15
 TMacro.cxx:16
 TMacro.cxx:17
 TMacro.cxx:18
 TMacro.cxx:19
 TMacro.cxx:20
 TMacro.cxx:21
 TMacro.cxx:22
 TMacro.cxx:23
 TMacro.cxx:24
 TMacro.cxx:25
 TMacro.cxx:26
 TMacro.cxx:27
 TMacro.cxx:28
 TMacro.cxx:29
 TMacro.cxx:30
 TMacro.cxx:31
 TMacro.cxx:32
 TMacro.cxx:33
 TMacro.cxx:34
 TMacro.cxx:35
 TMacro.cxx:36
 TMacro.cxx:37
 TMacro.cxx:38
 TMacro.cxx:39
 TMacro.cxx:40
 TMacro.cxx:41
 TMacro.cxx:42
 TMacro.cxx:43
 TMacro.cxx:44
 TMacro.cxx:45
 TMacro.cxx:46
 TMacro.cxx:47
 TMacro.cxx:48
 TMacro.cxx:49
 TMacro.cxx:50
 TMacro.cxx:51
 TMacro.cxx:52
 TMacro.cxx:53
 TMacro.cxx:54
 TMacro.cxx:55
 TMacro.cxx:56
 TMacro.cxx:57
 TMacro.cxx:58
 TMacro.cxx:59
 TMacro.cxx:60
 TMacro.cxx:61
 TMacro.cxx:62
 TMacro.cxx:63
 TMacro.cxx:64
 TMacro.cxx:65
 TMacro.cxx:66
 TMacro.cxx:67
 TMacro.cxx:68
 TMacro.cxx:69
 TMacro.cxx:70
 TMacro.cxx:71
 TMacro.cxx:72
 TMacro.cxx:73
 TMacro.cxx:74
 TMacro.cxx:75
 TMacro.cxx:76
 TMacro.cxx:77
 TMacro.cxx:78
 TMacro.cxx:79
 TMacro.cxx:80
 TMacro.cxx:81
 TMacro.cxx:82
 TMacro.cxx:83
 TMacro.cxx:84
 TMacro.cxx:85
 TMacro.cxx:86
 TMacro.cxx:87
 TMacro.cxx:88
 TMacro.cxx:89
 TMacro.cxx:90
 TMacro.cxx:91
 TMacro.cxx:92
 TMacro.cxx:93
 TMacro.cxx:94
 TMacro.cxx:95
 TMacro.cxx:96
 TMacro.cxx:97
 TMacro.cxx:98
 TMacro.cxx:99
 TMacro.cxx:100
 TMacro.cxx:101
 TMacro.cxx:102
 TMacro.cxx:103
 TMacro.cxx:104
 TMacro.cxx:105
 TMacro.cxx:106
 TMacro.cxx:107
 TMacro.cxx:108
 TMacro.cxx:109
 TMacro.cxx:110
 TMacro.cxx:111
 TMacro.cxx:112
 TMacro.cxx:113
 TMacro.cxx:114
 TMacro.cxx:115
 TMacro.cxx:116
 TMacro.cxx:117
 TMacro.cxx:118
 TMacro.cxx:119
 TMacro.cxx:120
 TMacro.cxx:121
 TMacro.cxx:122
 TMacro.cxx:123
 TMacro.cxx:124
 TMacro.cxx:125
 TMacro.cxx:126
 TMacro.cxx:127
 TMacro.cxx:128
 TMacro.cxx:129
 TMacro.cxx:130
 TMacro.cxx:131
 TMacro.cxx:132
 TMacro.cxx:133
 TMacro.cxx:134
 TMacro.cxx:135
 TMacro.cxx:136
 TMacro.cxx:137
 TMacro.cxx:138
 TMacro.cxx:139
 TMacro.cxx:140
 TMacro.cxx:141
 TMacro.cxx:142
 TMacro.cxx:143
 TMacro.cxx:144
 TMacro.cxx:145
 TMacro.cxx:146
 TMacro.cxx:147
 TMacro.cxx:148
 TMacro.cxx:149
 TMacro.cxx:150
 TMacro.cxx:151
 TMacro.cxx:152
 TMacro.cxx:153
 TMacro.cxx:154
 TMacro.cxx:155
 TMacro.cxx:156
 TMacro.cxx:157
 TMacro.cxx:158
 TMacro.cxx:159
 TMacro.cxx:160
 TMacro.cxx:161
 TMacro.cxx:162
 TMacro.cxx:163
 TMacro.cxx:164
 TMacro.cxx:165
 TMacro.cxx:166
 TMacro.cxx:167
 TMacro.cxx:168
 TMacro.cxx:169
 TMacro.cxx:170
 TMacro.cxx:171
 TMacro.cxx:172
 TMacro.cxx:173
 TMacro.cxx:174
 TMacro.cxx:175
 TMacro.cxx:176
 TMacro.cxx:177
 TMacro.cxx:178
 TMacro.cxx:179
 TMacro.cxx:180
 TMacro.cxx:181
 TMacro.cxx:182
 TMacro.cxx:183
 TMacro.cxx:184
 TMacro.cxx:185
 TMacro.cxx:186
 TMacro.cxx:187
 TMacro.cxx:188
 TMacro.cxx:189
 TMacro.cxx:190
 TMacro.cxx:191
 TMacro.cxx:192
 TMacro.cxx:193
 TMacro.cxx:194
 TMacro.cxx:195
 TMacro.cxx:196
 TMacro.cxx:197
 TMacro.cxx:198
 TMacro.cxx:199
 TMacro.cxx:200
 TMacro.cxx:201
 TMacro.cxx:202
 TMacro.cxx:203
 TMacro.cxx:204
 TMacro.cxx:205
 TMacro.cxx:206
 TMacro.cxx:207
 TMacro.cxx:208
 TMacro.cxx:209
 TMacro.cxx:210
 TMacro.cxx:211
 TMacro.cxx:212
 TMacro.cxx:213
 TMacro.cxx:214
 TMacro.cxx:215
 TMacro.cxx:216
 TMacro.cxx:217
 TMacro.cxx:218
 TMacro.cxx:219
 TMacro.cxx:220
 TMacro.cxx:221
 TMacro.cxx:222
 TMacro.cxx:223
 TMacro.cxx:224
 TMacro.cxx:225
 TMacro.cxx:226
 TMacro.cxx:227
 TMacro.cxx:228
 TMacro.cxx:229
 TMacro.cxx:230
 TMacro.cxx:231
 TMacro.cxx:232
 TMacro.cxx:233
 TMacro.cxx:234
 TMacro.cxx:235
 TMacro.cxx:236
 TMacro.cxx:237
 TMacro.cxx:238
 TMacro.cxx:239
 TMacro.cxx:240
 TMacro.cxx:241
 TMacro.cxx:242
 TMacro.cxx:243
 TMacro.cxx:244
 TMacro.cxx:245
 TMacro.cxx:246
 TMacro.cxx:247
 TMacro.cxx:248
 TMacro.cxx:249
 TMacro.cxx:250
 TMacro.cxx:251
 TMacro.cxx:252
 TMacro.cxx:253
 TMacro.cxx:254
 TMacro.cxx:255
 TMacro.cxx:256
 TMacro.cxx:257
 TMacro.cxx:258
 TMacro.cxx:259
 TMacro.cxx:260
 TMacro.cxx:261
 TMacro.cxx:262
 TMacro.cxx:263
 TMacro.cxx:264
 TMacro.cxx:265
 TMacro.cxx:266
 TMacro.cxx:267
 TMacro.cxx:268
 TMacro.cxx:269
 TMacro.cxx:270
 TMacro.cxx:271
 TMacro.cxx:272
 TMacro.cxx:273
 TMacro.cxx:274
 TMacro.cxx:275
 TMacro.cxx:276
 TMacro.cxx:277
 TMacro.cxx:278
 TMacro.cxx:279
 TMacro.cxx:280
 TMacro.cxx:281
 TMacro.cxx:282
 TMacro.cxx:283
 TMacro.cxx:284
 TMacro.cxx:285
 TMacro.cxx:286
 TMacro.cxx:287
 TMacro.cxx:288
 TMacro.cxx:289
 TMacro.cxx:290
 TMacro.cxx:291
 TMacro.cxx:292
 TMacro.cxx:293
 TMacro.cxx:294
 TMacro.cxx:295
 TMacro.cxx:296
 TMacro.cxx:297
 TMacro.cxx:298
 TMacro.cxx:299
 TMacro.cxx:300
 TMacro.cxx:301
 TMacro.cxx:302
 TMacro.cxx:303
 TMacro.cxx:304
 TMacro.cxx:305
 TMacro.cxx:306
 TMacro.cxx:307
 TMacro.cxx:308
 TMacro.cxx:309
 TMacro.cxx:310
 TMacro.cxx:311
 TMacro.cxx:312
 TMacro.cxx:313
 TMacro.cxx:314
 TMacro.cxx:315
 TMacro.cxx:316
 TMacro.cxx:317
 TMacro.cxx:318
 TMacro.cxx:319
 TMacro.cxx:320
 TMacro.cxx:321
 TMacro.cxx:322
 TMacro.cxx:323
 TMacro.cxx:324
 TMacro.cxx:325
 TMacro.cxx:326
 TMacro.cxx:327
 TMacro.cxx:328
 TMacro.cxx:329
 TMacro.cxx:330
 TMacro.cxx:331
 TMacro.cxx:332
 TMacro.cxx:333
 TMacro.cxx:334
 TMacro.cxx:335
 TMacro.cxx:336
 TMacro.cxx:337
 TMacro.cxx:338
 TMacro.cxx:339
 TMacro.cxx:340
 TMacro.cxx:341
 TMacro.cxx:342
 TMacro.cxx:343
 TMacro.cxx:344
 TMacro.cxx:345
 TMacro.cxx:346
 TMacro.cxx:347
 TMacro.cxx:348
 TMacro.cxx:349
 TMacro.cxx:350
 TMacro.cxx:351
 TMacro.cxx:352
 TMacro.cxx:353
 TMacro.cxx:354
 TMacro.cxx:355
 TMacro.cxx:356
 TMacro.cxx:357
 TMacro.cxx:358
 TMacro.cxx:359
 TMacro.cxx:360
 TMacro.cxx:361
 TMacro.cxx:362
 TMacro.cxx:363
 TMacro.cxx:364
 TMacro.cxx:365
 TMacro.cxx:366
 TMacro.cxx:367
 TMacro.cxx:368
 TMacro.cxx:369
 TMacro.cxx:370
 TMacro.cxx:371
 TMacro.cxx:372
 TMacro.cxx:373
 TMacro.cxx:374
 TMacro.cxx:375
 TMacro.cxx:376
 TMacro.cxx:377
 TMacro.cxx:378
 TMacro.cxx:379
 TMacro.cxx:380
 TMacro.cxx:381
 TMacro.cxx:382
 TMacro.cxx:383
 TMacro.cxx:384
 TMacro.cxx:385
 TMacro.cxx:386
 TMacro.cxx:387
 TMacro.cxx:388
 TMacro.cxx:389
 TMacro.cxx:390
 TMacro.cxx:391
 TMacro.cxx:392
 TMacro.cxx:393
 TMacro.cxx:394
 TMacro.cxx:395
 TMacro.cxx:396
 TMacro.cxx:397
 TMacro.cxx:398
 TMacro.cxx:399
 TMacro.cxx:400
 TMacro.cxx:401
 TMacro.cxx:402
 TMacro.cxx:403
 TMacro.cxx:404
 TMacro.cxx:405
 TMacro.cxx:406
 TMacro.cxx:407
 TMacro.cxx:408
 TMacro.cxx:409
 TMacro.cxx:410
 TMacro.cxx:411
 TMacro.cxx:412
 TMacro.cxx:413
 TMacro.cxx:414
 TMacro.cxx:415