Always return error messages if not successful
[u/mrichter/AliRoot.git] / HLT / trigger / AliHLTGlobalTriggerComponent.cxx
1 // $Id$
2 /**************************************************************************
3  * This file is property of and copyright by the ALICE HLT Project        *
4  * ALICE Experiment at CERN, All rights reserved.                         *
5  *                                                                        *
6  * Primary Authors: Artur Szostak <artursz@iafrica.com>                   *
7  *                  for The ALICE HLT Project.                            *
8  *                                                                        *
9  * Permission to use, copy, modify and distribute this software and its   *
10  * documentation strictly for non-commercial purposes is hereby granted   *
11  * without fee, provided that the above copyright notice appears in all   *
12  * copies and that both the copyright notice and this permission notice   *
13  * appear in the supporting documentation. The authors make no claims     *
14  * about the suitability of this software for any purpose. It is          *
15  * provided "as is" without express or implied warranty.                  *
16  **************************************************************************/
17
18 /// @file   AliHLTGlobalTriggerComponent.cxx
19 /// @author Artur Szostak <artursz@iafrica.com>
20 /// @date   26 Nov 2008
21 /// @brief  Implementation of the AliHLTGlobalTriggerComponent component class.
22 ///
23 /// The AliHLTGlobalTriggerComponentComponent class applies the global HLT trigger to all
24 /// trigger information produced by components deriving from AliHLTTrigger.
25
26 #include "AliHLTGlobalTriggerComponent.h"
27 #include "AliHLTGlobalTriggerDecision.h"
28 #include "AliHLTGlobalTrigger.h"
29 #include "AliHLTGlobalTriggerConfig.h"
30 #include "AliHLTTriggerMenu.h"
31 #include "AliCDBManager.h"
32 #include "AliCDBStorage.h"
33 #include "AliCDBEntry.h"
34 #include "TUUID.h"
35 #include "TROOT.h"
36 #include "TSystem.h"
37 #include "TRegexp.h"
38 #include "TClonesArray.h"
39 #include "TObjString.h"
40 #include "TSystem.h"
41 #include "TInterpreter.h"
42 #include <fstream>
43 #include <cerrno>
44
45 ClassImp(AliHLTGlobalTriggerComponent)
46
47 const char* AliHLTGlobalTriggerComponent::fgkTriggerMenuCDBPath = "HLT/ConfigHLT/HLTGlobalTrigger";
48
49
50 AliHLTGlobalTriggerComponent::AliHLTGlobalTriggerComponent() :
51         AliHLTTrigger(),
52         fTrigger(NULL),
53         fDebugMode(false),
54         fCodeFileName()
55 {
56   // Default constructor.
57   
58   ClearInfoForNewEvent(false);
59 }
60
61
62 AliHLTGlobalTriggerComponent::~AliHLTGlobalTriggerComponent()
63 {
64   // Default destructor.
65   
66   if (fTrigger != NULL) delete fTrigger;
67 }
68
69
70 void AliHLTGlobalTriggerComponent::GetOutputDataSize(unsigned long& constBase, double& inputMultiplier)
71 {
72   // Returns the output data size estimate.
73
74   constBase = sizeof(AliHLTGlobalTriggerDecision);
75   inputMultiplier = 1;
76 }
77
78
79 Int_t AliHLTGlobalTriggerComponent::DoInit(int argc, const char** argv)
80 {
81   // Initialises the global trigger component.
82   
83   fDebugMode = false;
84   const char* configFileName = NULL;
85   const char* codeFileName = NULL;
86   TString classname;
87   TClonesArray includePaths(TObjString::Class());
88   TClonesArray includeFiles(TObjString::Class());
89   
90   for (int i = 0; i < argc; i++)
91   {
92     if (strcmp(argv[i], "-config") == 0)
93     {
94       if (configFileName != NULL)
95       {
96         HLTWarning("Trigger configuration macro was already specified."
97                    " Will replace previous value given by -config."
98         );
99       }
100       if (argc <= i+1)
101       {
102         HLTError("The trigger configuration macro filename was not specified." );
103         return -EINVAL;
104       }
105       configFileName = argv[i+1];
106       i++;
107       continue;
108     }
109     
110     if (strcmp(argv[i], "-includepath") == 0)
111     {
112       if (argc <= i+1)
113       {
114         HLTError("The include path was not specified." );
115         return -EINVAL;
116       }
117       new (includePaths[includePaths.GetEntriesFast()]) TObjString(argv[i+1]);
118       i++;
119       continue;
120     }
121     
122     if (strcmp(argv[i], "-include") == 0)
123     {
124       if (argc <= i+1)
125       {
126         HLTError("The include file name was not specified." );
127         return -EINVAL;
128       }
129       new (includeFiles[includeFiles.GetEntriesFast()]) TObjString(argv[i+1]);
130       i++;
131       continue;
132     }
133     
134     if (strcmp(argv[i], "-debug") == 0)
135     {
136       if (fDebugMode == true)
137       {
138         HLTWarning("The debug flag was already specified. Ignoring this instance.");
139       }
140       fDebugMode = true;
141       i++;
142       continue;
143     }
144     
145     if (strcmp(argv[i], "-usecode") == 0)
146     {
147       if (codeFileName != NULL)
148       {
149         HLTWarning("Custom trigger code file was already specified."
150                    " Will replace previous value given by -usecode."
151         );
152       }
153       if (argc <= i+1)
154       {
155         HLTError("The custom trigger code filename was not specified." );
156         return -EINVAL;
157       }
158       codeFileName = argv[i+1];
159       if (argc <= i+2)
160       {
161         HLTError("The custom trigger class name was not specified." );
162         return -EINVAL;
163       }
164       classname = argv[i+2];
165       i += 2;
166       continue;
167     }
168     
169     HLTError("Unknown option '%s'.", argv[i]);
170     return -EINVAL;
171   } // for loop
172   
173   const AliHLTTriggerMenu* menu = NULL;
174   if (configFileName != NULL)
175   {
176     TString cmd = ".x ";
177     cmd += configFileName;
178     gROOT->ProcessLine(cmd);
179     menu = AliHLTGlobalTriggerConfig::Menu();
180   }
181   
182   // Try load the trigger menu from the CDB if it is not loaded yet with the
183   // -config option
184   if (menu == NULL and AliCDBManager::Instance() != NULL)
185   {
186     AliCDBStorage* store = AliCDBManager::Instance()->GetDefaultStorage();
187     if (store == NULL)
188     {
189       HLTError("Could not get the the default storage for the CDB.");
190       return -EIO;
191     }
192     Int_t version = store->GetLatestVersion(fgkTriggerMenuCDBPath, GetRunNo());
193     Int_t subVersion = store->GetLatestSubVersion(fgkTriggerMenuCDBPath, GetRunNo(), version);
194     AliCDBEntry* entry = AliCDBManager::Instance()->Get(fgkTriggerMenuCDBPath, GetRunNo(), version, subVersion);
195     if (entry == NULL)
196     {
197       HLTError("Could not get the CDB entry for \"%s\".", fgkTriggerMenuCDBPath);
198       return -EIO;
199     }
200     TObject* obj = entry->GetObject();
201     if (obj == NULL)
202     {
203       HLTError("Configuration object for \"%s\" is missing.", fgkTriggerMenuCDBPath);
204       return -ENOENT;
205     }
206     if (obj->IsA() != AliHLTTriggerMenu::Class())
207     {
208       HLTError("Wrong type for configuration object in \"%s\". Found a %s but we expect a AliHLTTriggerMenu.",
209                fgkTriggerMenuCDBPath, obj->ClassName()
210       );
211       return -EPROTO;
212     }
213     menu = dynamic_cast<AliHLTTriggerMenu*>(obj);
214   }
215   
216   if (menu == NULL)
217   {
218     HLTError("No trigger menu configuration found or specified.");
219     return -ENOENT;
220   }
221   
222   int result = 0;
223   if (codeFileName == NULL)
224   {
225     HLTDebug("Generating custom HLT trigger class.");
226     result = GenerateTrigger(menu, classname, includePaths, includeFiles);
227   }
228   else
229   {
230     HLTDebug("Loading HLT trigger class from file '%s'.", codeFileName);
231     result = LoadTriggerClass(codeFileName, includePaths);
232   }
233   if (result != 0) return result;
234   
235   fTrigger = AliHLTGlobalTrigger::CreateNew(classname.Data());
236   if (fTrigger == NULL)
237   {
238     HLTError("Could not create a new instance of '%s'.", classname.Data());
239     return -EIO;
240   }
241   
242   fTrigger->FillFromMenu(*menu);
243   fTrigger->ResetCounters(menu->NumberOfItems());
244   
245   // Set the default values from the trigger menu.
246   SetDescription(menu->DefaultDescription());
247   SetTriggerDomain(menu->DefaultTriggerDomain());
248   
249   return 0;
250 }
251
252
253 Int_t AliHLTGlobalTriggerComponent::DoDeinit()
254 {
255   // Cleans up the global trigger component.
256   
257   if (fTrigger != NULL)
258   {
259     delete fTrigger;
260     fTrigger = NULL;
261   }
262
263   if (!fCodeFileName.IsNull() && gSystem->AccessPathName(fCodeFileName)==0) {
264     TString command="rm "; command+=fCodeFileName;
265     gSystem->Exec(command);
266   }
267   
268   return 0;
269 }
270
271
272 AliHLTComponent* AliHLTGlobalTriggerComponent::Spawn()
273 {
274   // Creates a new object instance.
275   
276   return new AliHLTGlobalTriggerComponent;
277 }
278
279
280 int AliHLTGlobalTriggerComponent::DoTrigger()
281 {
282   // This method will apply the global trigger decision.
283
284   if (fTrigger == NULL)
285   {
286     HLTFatal("Global trigger implementation object is NULL!");
287     return -EIO;
288   }
289   
290   fTrigger->NewEvent();
291   
292   // Fill in the input data.
293   const TObject* obj = GetFirstInputObject();
294   while (obj != NULL)
295   {
296     fTrigger->Add(obj, GetDataType(), GetSpecification());
297     obj = GetNextInputObject();
298   }
299
300   // Calculate the global trigger result and trigger domain, then create and push
301   // back the new global trigger decision object.
302   TString description;
303   AliHLTTriggerDomain triggerDomain;
304   bool triggerResult = fTrigger->CalculateTriggerDecision(triggerDomain, description);
305   
306   AliHLTGlobalTriggerDecision decision(
307       triggerResult,
308       // The following will cause the decision to be generated with default values
309       // (set in fTriggerDomain and fDescription) if the trigger result is false.
310       (triggerResult == true) ? triggerDomain : GetTriggerDomain(),
311       (triggerResult == true) ? description.Data() : GetDescription()
312     );
313   decision.SetCounters(fTrigger->Counters());
314   
315   // Add the input objects used to the global decision.
316   obj = GetFirstInputObject();
317   while (obj != NULL)
318   {
319     if (obj->IsA() == AliHLTTriggerDecision::Class())
320     {
321       decision.AddTriggerInput( *static_cast<const AliHLTTriggerDecision*>(obj) );
322     }
323     else
324     {
325       decision.AddInputObject(obj);
326     }
327     obj = GetNextInputObject();
328   }
329   
330   TriggerEvent(&decision);
331   return 0;
332 }
333
334
335 int AliHLTGlobalTriggerComponent::GenerateTrigger(
336     const AliHLTTriggerMenu* menu, TString& name,
337     const TClonesArray& includePaths, const TClonesArray& includeFiles
338   )
339 {
340   // Generates the global trigger class that will implement the specified trigger menu.
341   // See header for more details.
342   
343   // Create a new UUID and replace the '-' characters with '_' to make it a valid
344   // C++ symbol name.
345   TUUID uuid;
346   TString uuidstr = uuid.AsString();
347   for (Int_t i = 0; i < uuidstr.Length(); i++)
348   {
349     if (uuidstr[i] == '-') uuidstr[i] = '_';
350   }
351   
352   // Create the name of the new class.
353   name = "AliHLTGlobalTriggerImpl_";
354   name += uuidstr;
355   fCodeFileName = name + ".cxx";
356   
357   // Open a text file to write the code and generate the new class.
358   fstream code(fCodeFileName.Data(), ios_base::out | ios_base::trunc);
359   if (not code.good())
360   {
361     HLTError("Could not open file '%s' for writing.", fCodeFileName.Data());
362     return -EIO;
363   }
364   
365   TClonesArray symbols(AliHLTTriggerMenuSymbol::Class());
366   int result = BuildSymbolList(menu, symbols);
367   if (result != 0) return result;
368   
369   code << "#include <cstring>" << endl;
370   code << "#include \"TString.h\"" << endl;
371   code << "#include \"TClonesArray.h\"" << endl;
372   code << "#include \"AliHLTGlobalTrigger.h\"" << endl;
373   code << "#include \"AliHLTGlobalTriggerDecision.h\"" << endl;
374   code << "#include \"AliHLTDomainEntry.h\"" << endl;
375   code << "#include \"AliHLTTriggerDomain.h\"" << endl;
376   code << "#include \"AliHLTReadoutList.h\"" << endl;
377   code << "#include \"AliHLTTriggerMenu.h\"" << endl;
378   code << "#include \"AliHLTTriggerMenuItem.h\"" << endl;
379   code << "#include \"AliHLTTriggerMenuSymbol.h\"" << endl;
380   
381   // Add any include files that were specified on the command line.
382   for (Int_t i = 0; i < includeFiles.GetEntriesFast(); i++)
383   {
384     TString file = static_cast<const TObjString*>(includeFiles.UncheckedAt(i))->String();
385     code << "#include \"" << file.Data() << "\"" << endl;
386   }
387   
388   code << "class " << name << " : public AliHLTGlobalTrigger" << endl;
389   code << "{" << endl;
390   code << "public:" << endl;
391   
392   code << "  " << name << "() : AliHLTGlobalTrigger()";
393   // Write the symbols in the trigger menu in the initialisation list.
394   for (Int_t i = 0; i < symbols.GetEntriesFast(); i++)
395   {
396     code << "," << endl;
397     AliHLTTriggerMenuSymbol* symbol = static_cast<AliHLTTriggerMenuSymbol*>( symbols.UncheckedAt(i) );
398     code << "    " << symbol->Name() << "()," << endl;
399     if (strcmp(symbol->ObjectClass(), "AliHLTTriggerDecision") == 0)
400     {
401       code << "    " << symbol->Name() << "TriggerDomain()," << endl;
402     }
403     code << "    " << symbol->Name() << "DomainEntry(kAliHLTAnyDataType)";
404   }
405   for (UInt_t i = 0; i < menu->NumberOfItems(); i++)
406   {
407     code << "," << endl << "    fMenuItemDescription" << i << "()";
408   }
409   code << endl << "  {" << endl;
410   if (fDebugMode)
411   {
412     code << "    SetLocalLoggingLevel(kHLTLogAll);" << endl;
413     code << "    HLTInfo(\"Creating new instance at %p.\", this);" << endl;
414   }
415   code << "  }" << endl;
416   
417   code << "  virtual ~" << name << "() {" << endl;
418   if (fDebugMode)
419   {
420     code << "    HLTInfo(\"Deleting instance at %p.\", this);" << endl;
421   }
422   code << "  }" << endl;
423   
424   // Generate the FillFromMenu method.
425   code << "  virtual void FillFromMenu(const AliHLTTriggerMenu& menu) {" << endl;
426   if (fDebugMode)
427   {
428     code << "    HLTDebug(\"Filling description entries from trigger menu for global trigger %p.\", this);" << endl;
429   }
430   for (UInt_t i = 0; i < menu->NumberOfItems(); i++)
431   {
432     code << "    fMenuItemDescription" << i << " = (menu.Item(" << i
433          << ") != NULL) ? menu.Item(" << i << ")->Description() : \"\";" << endl;
434   }
435   if (fDebugMode)
436   {
437     code << "    HLTDebug(\"Finished filling description entries from trigger menu.\");" << endl;
438     code << "    HLTDebug(\"Filling domain entries from trigger menu symbols for global trigger %p.\", this);" << endl;
439   }
440   code << "    for (Int_t i = 0; i < menu.SymbolArray().GetEntriesFast(); i++) {" << endl;
441   code << "      const AliHLTTriggerMenuSymbol* symbol = dynamic_cast<const"
442            " AliHLTTriggerMenuSymbol*>(menu.SymbolArray().UncheckedAt(i));" << endl;
443   code << "      if (symbol == NULL) continue;" << endl;
444   for (Int_t i = 0; i < symbols.GetEntriesFast(); i++)
445   {
446     AliHLTTriggerMenuSymbol* symbol = static_cast<AliHLTTriggerMenuSymbol*>( symbols.UncheckedAt(i) );
447     code << "      if (strcmp(symbol->Name(), \"" << symbol->Name() << "\") == 0) {" << endl;
448     if (fDebugMode)
449     {
450       code << "        HLTDebug(\"Assinging domain entry value to match for symbol '%s' to '%s'.\","
451               " symbol->Name(), symbol->BlockType().AsString().Data());" << endl;
452     }
453     code << "        " << symbol->Name() << "DomainEntry = symbol->BlockType();" << endl;
454     code << "        continue;" << endl;
455     code << "      }" << endl;
456   }
457   code << "    }" << endl;
458   if (fDebugMode)
459   {
460     code << "    HLTDebug(\"Finished filling domain entries from trigger menu symbols.\");" << endl;
461   }
462   code << "  }" << endl;
463   
464   // Generate the NewEvent method.
465   code << "  virtual void NewEvent() {" << endl;
466   if (fDebugMode)
467   {
468     code << "    HLTDebug(\"New event for global trigger object %p, initialising variables to default values.\", this);" << endl;
469   }
470   // Write code to initialise the symbols in the trigger menu to their default values.
471   for (Int_t i = 0; i < symbols.GetEntriesFast(); i++)
472   {
473     AliHLTTriggerMenuSymbol* symbol = static_cast<AliHLTTriggerMenuSymbol*>( symbols.UncheckedAt(i) );
474     code << "    " << symbol->Name() << " = " << symbol->DefaultValue() << ";" << endl;
475     if (strcmp(symbol->ObjectClass(), "AliHLTTriggerDecision") == 0)
476     {
477       code << "    " << symbol->Name() << "TriggerDomain.Clear();" << endl;
478     }
479   }
480   if (fDebugMode)
481   {
482     code << "    HLTDebug(\"Finished initialising variables.\");" << endl;
483   }
484   code << "  }" << endl;
485   
486   // Generate the Add method.
487   code << "  virtual void Add(const TObject* _object_, const AliHLTComponentDataType& _type_, AliHLTUInt32_t _spec_) {" << endl;
488   code << "    AliHLTDomainEntry _type_spec_(_type_, _spec_);" << endl;
489   if (fDebugMode)
490   {
491     code << "    HLTDebug(\"Adding TObject %p, with class name '%s' from data block"
492             " '%s', to global trigger object %p\", _object_, _object_->ClassName(),"
493             " _type_spec_.AsString().Data(), this);" << endl;
494     code << "    _object_->Print();" << endl;
495     code << "    bool _object_assigned_ = false;" << endl;
496   }
497   for (Int_t i = 0; i < symbols.GetEntriesFast(); i++)
498   {
499     // Write code to check if the block type, specification and class name is correct.
500     // Then write code to assign the variable from the input object.
501     AliHLTTriggerMenuSymbol* symbol = static_cast<AliHLTTriggerMenuSymbol*>( symbols.UncheckedAt(i) );
502     TString expr = symbol->AssignExpression();
503     if (expr == "") continue; // Skip entries that have no assignment expression.
504     bool isTrigDecision = strcmp(symbol->ObjectClass(), "AliHLTTriggerDecision") == 0;
505     if (fDebugMode)
506     {
507       if (isTrigDecision)
508       {
509         code << "    HLTDebug(\"Trying to match input object to class '"
510              << symbol->ObjectClass() << "', trigger name '" << symbol->Name()
511              << "' and block type '%s'\", " << symbol->Name()
512              << "DomainEntry.AsString().Data());" << endl;
513       }
514       else
515       {
516         code << "    HLTDebug(\"Trying to match input object to class '"
517              << symbol->ObjectClass() << "' and block type '%s'\", "
518              << symbol->Name() << "DomainEntry.AsString().Data());" << endl;
519       }
520     }
521     code << "    const " << symbol->ObjectClass() << "* " << symbol->Name()
522          << "_object_ = dynamic_cast<const " << symbol->ObjectClass()
523          << "*>(_object_);" << endl;
524     code << "    if (" << symbol->Name() << "_object_ != NULL and ";
525     if (isTrigDecision)
526     {
527       code << "strcmp(" << symbol->Name() << "_object_->Name(), \""
528            << symbol->Name() << "\") == 0 and ";
529     }
530     code << symbol->Name() << "DomainEntry == _type_spec_) {" << endl;
531     TString fullname = symbol->Name();
532     fullname += "_object_";
533     expr.ReplaceAll("this", fullname);
534     code << "      this->" << symbol->Name() << " = " << expr.Data() << ";" << endl;
535     if (isTrigDecision)
536     {
537       code << "      this->" << symbol->Name() << "TriggerDomain = "
538            << fullname.Data() << "->TriggerDomain();" << endl;
539     }
540     if (fDebugMode)
541     {
542       code << "      HLTDebug(\"Added TObject %p with class name '%s' to variable "
543            << symbol->Name() << "\", _object_, _object_->ClassName());" << endl;
544       code << "      _object_assigned_ = true;" << endl;
545     }
546     code << "    }" << endl;
547   }
548   if (fDebugMode)
549   {
550     code << "    if (not _object_assigned_) HLTDebug(\"Did not assign TObject %p"
551             " with class name '%s' to any variable.\", _object_, _object_->ClassName());"
552          << endl;
553   }
554   code << "  }" << endl;
555   
556   // Generate the CalculateTriggerDecision method.
557   code << "  virtual bool CalculateTriggerDecision(AliHLTTriggerDomain& _domain_, TString& _description_) {" << endl;
558   if (fDebugMode)
559   {
560     code << "    HLTDebug(\"Calculating global HLT trigger result with trigger object at %p.\", this);" << endl;
561   }
562   for (UInt_t i = 0; i < menu->NumberOfItems(); i++)
563   {
564     const AliHLTTriggerMenuItem* item = menu->Item(i);
565     TString mergeExpr = item->MergeExpression();
566     for (Int_t j = 0; j < symbols.GetEntriesFast(); j++)
567     {
568       AliHLTTriggerMenuSymbol* symbol = static_cast<AliHLTTriggerMenuSymbol*>( symbols.UncheckedAt(j) );
569       if (strcmp(symbol->ObjectClass(), "AliHLTTriggerDecision") != 0) continue;
570       TString newname = symbol->Name();
571       newname += "TriggerDomain";
572       mergeExpr.ReplaceAll(symbol->Name(), newname);
573     }
574     if (fDebugMode)
575     {
576       code << "    HLTDebug(\"Trying trigger condition " << i
577            << " (Description = '%s').\", fMenuItemDescription" << i << ".Data());"
578            << endl;
579     }
580     code << "    if (" << item->TriggerCondision() << ") {" << endl;
581     code << "      IncrementCounter(" << i << ");" << endl;
582     const char* indentation = "";
583     if (item->PreScalar() != 0)
584     {
585       indentation = "  ";
586       code << "      if ((GetCounter(" << i << ") % " << item->PreScalar() << ") == 1) {" << endl;
587     }
588     code << indentation << "      _domain_ = " << mergeExpr.Data() << ";" << endl;
589     code << indentation << "      _description_ = fMenuItemDescription" << i << ";" << endl;
590     if (fDebugMode)
591     {
592       code << indentation << "      HLTDebug(\"Matched trigger condition " << i
593            << " (Description = '%s').\", fMenuItemDescription" << i << ".Data());" << endl;
594     }
595     code << indentation << "      return true;" << endl;
596     if (item->PreScalar() != 0)
597     {
598       code << "      }" << endl;
599     }
600     code << "    }" << endl;
601   }
602   code << "    return false;" << endl;
603   code << "  }" << endl;
604   
605   // Generate the custom Factory class.
606   code << "  class FactoryImpl : public AliHLTGlobalTrigger::Factory" << endl;
607   code << "  {" << endl;
608   code << "  public:" << endl;
609   code << "    virtual const char* ClassName() const {" << endl;
610   code << "      return \"" << name << "\";" << endl;
611   code << "    }" << endl;
612   code << "    virtual AliHLTGlobalTrigger* New() const {" << endl;
613   code << "      return new " << name << "();" << endl;
614   code << "    }" << endl;
615   code << "  };" << endl;
616   
617   code << "private:" << endl;
618   // Add the symbols in the trigger menu to the list of private variables.
619   for (Int_t i = 0; i < symbols.GetEntriesFast(); i++)
620   {
621     AliHLTTriggerMenuSymbol* symbol = static_cast<AliHLTTriggerMenuSymbol*>( symbols.UncheckedAt(i) );
622     code << "  " << symbol->Type() << " " << symbol->Name() << ";" << endl;
623     if (strcmp(symbol->ObjectClass(), "AliHLTTriggerDecision") == 0)
624     {
625       code << "  AliHLTTriggerDomain " << symbol->Name() << "TriggerDomain;" << endl;
626     }
627     code << "  AliHLTDomainEntry " << symbol->Name() << "DomainEntry;" << endl;
628   }
629   for (UInt_t i = 0; i < menu->NumberOfItems(); i++)
630   {
631     code << "  TString fMenuItemDescription" << i << ";" << endl;
632   }
633   code << "};" << endl;
634   
635   // Write a global object for the Factory class for automatic registration.
636   code << "namespace {" << endl;
637   code << "  const " << name << "::FactoryImpl gkFactoryImpl;" << endl;
638   code << "};" << endl;
639   
640   code.close();
641   
642   // Now we need to compile and load the new class.
643   result = LoadTriggerClass(fCodeFileName, includePaths);
644   return result;
645 }
646
647
648 int AliHLTGlobalTriggerComponent::LoadTriggerClass(
649     const char* filename, const TClonesArray& includePaths
650   )
651 {
652   // Loads the code for a custom global trigger class implementation on the fly.
653   
654   TString compiler = gSystem->GetBuildCompilerVersion();
655   if (compiler.Contains("gcc") or compiler.Contains("icc"))
656   {
657     TString includePath = "-I${ALICE_ROOT}/include -I${ALICE_ROOT}/HLT/BASE -I${ALICE_ROOT}/HLT/trigger";
658     // Add any include paths that were specified on the command line.
659     for (Int_t i = 0; i < includePaths.GetEntriesFast(); i++)
660     {
661       TString path = static_cast<const TObjString*>(includePaths.UncheckedAt(i))->String();
662       includePath += " ";
663       includePath += path;
664     }
665     gSystem->SetIncludePath(includePath);
666     gSystem->SetFlagsOpt("-O3 -DNDEBUG");
667     gSystem->SetFlagsDebug("-g3 -DDEBUG -D__DEBUG");
668     
669     int result = kTRUE;
670     if (fDebugMode)
671     {
672       result = gSystem->CompileMacro(filename, "g");
673     }
674     else
675     {
676       result = gSystem->CompileMacro(filename, "O");
677     }
678     if (result != kTRUE)
679     {
680       HLTFatal("Could not compile and load global trigger menu implementation.");
681       return -ENOENT;
682     }
683   }
684   else
685   {
686     // If we do not support the compiler then try interpret the class instead.
687     TString cmd = ".L ";
688     cmd += filename;
689     Int_t errorcode = TInterpreter::kNoError;
690     gROOT->ProcessLine(cmd, &errorcode);
691     if (errorcode != TInterpreter::kNoError)
692     {
693       HLTFatal("Could not load interpreted global trigger menu implementation"
694                " (Interpreter error code = %d).",
695                errorcode
696       );
697       return -ENOENT;
698     }
699   }
700   
701   return 0;
702 }
703
704
705 int AliHLTGlobalTriggerComponent::FindSymbol(const char* name, const TClonesArray& list)
706 {
707   // Searches for the named symbol in the given list.
708   // See header for more details.
709   
710   for (int i = 0; i < list.GetEntriesFast(); i++)
711   {
712     const AliHLTTriggerMenuSymbol* symbol = dynamic_cast<const AliHLTTriggerMenuSymbol*>( list.UncheckedAt(i) );
713     if (symbol == NULL) continue;
714     if (strcmp(symbol->Name(), name) == 0) return i;
715   }
716   return -1;
717 }
718
719
720 int AliHLTGlobalTriggerComponent::BuildSymbolList(const AliHLTTriggerMenu* menu, TClonesArray& list)
721 {
722   // Builds the list of symbols to use in the custom global trigger menu
723   // implementation class.
724   // See header for more details.
725   
726   for (UInt_t i = 0; i < menu->NumberOfSymbols(); i++)
727   {
728     const AliHLTTriggerMenuSymbol* symbol = menu->Symbol(i);
729     if (FindSymbol(symbol->Name(), list) != -1)
730     {
731       HLTError("Multiple symbols with the name '%s' defined in the trigger menu.", symbol->Name());
732       return -EIO;
733     }
734     new (list[list.GetEntriesFast()]) AliHLTTriggerMenuSymbol(*symbol);
735   }
736   
737   TRegexp exp("[_a-zA-Z][_a-zA-Z0-9]*");
738   TRegexp hexexp("x[a-fA-F0-9]+");
739   for (UInt_t i = 0; i < menu->NumberOfItems(); i++)
740   {
741     const AliHLTTriggerMenuItem* item = menu->Item(i);
742     TString str = item->TriggerCondision();
743     Ssiz_t start = 0;
744     do
745     {
746       Ssiz_t length = 0;
747       Ssiz_t pos = exp.Index(str, &length, start);
748       if (pos == kNPOS) break;
749       start = pos+length;
750       
751       // Check if there is a numerical character before the found
752       // regular expression. If so, then the symbol is not a valid one
753       // and should be skipped.
754       if (pos > 0)
755       {
756         bool notValid = false;
757         switch (str[pos-1])
758         {
759         case '0': case '1': case '2': case '3': case '4':
760         case '5': case '6': case '7': case '8': case '9':
761           notValid = true;
762           break;
763         default:
764           notValid = false;
765           break;
766         }
767         if (notValid) continue;
768       }
769       TString s = str(pos, length);
770       
771       if (s == "and" or s == "and_eq" or s == "bitand" or s == "bitor" or
772           s == "compl" or s == "not" or s == "not_eq" or s == "or" or
773           s == "or_eq" or s == "xor" or s == "xor_eq" or s == "true" or
774           s == "false"
775          )
776       {
777         // Ignore iso646.h and other keywords.
778         continue;
779       }
780
781       if (FindSymbol(s.Data(), list) == -1)
782       {
783         AliHLTTriggerMenuSymbol newSymbol;
784         newSymbol.Name(s.Data());
785         newSymbol.Type("bool");
786         newSymbol.ObjectClass("AliHLTTriggerDecision");
787         newSymbol.AssignExpression("this->Result()");
788         newSymbol.DefaultValue("false");
789         new (list[list.GetEntriesFast()]) AliHLTTriggerMenuSymbol(newSymbol);
790       }
791     }
792     while (start < str.Length());
793   }
794   
795   return 0;
796 }
797