StRoot  1
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Groups Pages
StMessageManager.cxx
1 // //
3 // StMessageManager //
4 // //
5 // This class manages the messages in STAR software. It is a singleton. //
6 // It inherits from StMessMgr, which provides the external interface. //
7 // Messages are stored in a vector, and come in several types //
8 // (i.e. info, error, debug ). The types "I" (info), "W" (warning), //
9 // "E" (error), "D" (debug), "Q" (QAInfo), and "U" (UCMInfo)
10 // are predefined.
11 //
12 // Message finding and summary tools are also available. //
13 // //
15 
16 #ifdef __ROOT__
17 #include "TROOT.h"
18 #endif
19 
20 #include "StMessageManager.h"
21 #include "StMessageStream.h"
22 #include <string.h>
23 #ifdef __linux__
24 #include <math.h>
25 #endif
26 
27 //________________________________________
28 // ostream& operator<<(ostream& os, StMessage* stm)
29 std::ostream& StMessageManager::OperatorShift(std::ostream& os, StMessage* stm)
30 {
31  if (((&os) == (ostream*) gMessMgr) && (stm == endm)) {
32  gMessMgr->Print(); // This was a StMessage terminator
33  } else {
34  if (stm) os << stm->GetMessage(); // Output this message to the ostream
35  }
36  return os;
37 }
38 
39 static const char defaultMessType = 'I';
40 static char emptyString[] = "";
41 static char oOpt [] = "O";
42 // static char otsOpt [] = "OTS";
43 static char eOpt [] = "E";
44 
45 #ifdef __linux__
46 static int sMessLength;
47 static const int maxLOMP = 65536;
48 static const int maxLOMP1 = (maxLOMP-1);
49 static int lastLOMP = 0;
50 static char* listOfMessPtrs[maxLOMP];
51 static size_t listOfMessLens[maxLOMP];
52 #endif
53 
54 StMessMgr* StMessageManager::mInstance = 0;
55 
56 //
57 // C++ routines:
58 //_____________________________________________________________________________
59 StMessageManager::StMessageManager() : StMessMgr()
60 {
61 //
62 // Constructor - only called once when the library is loaded to
63 // instantiate the global message manager.
64 //
65 // assert(0);
66  messTypeList=0;
67  messCounter =0;
68  curType = new char[ 2]; curType[0] = 0; curType[1] = 0;
69  curOpt = new char[32]; curOpt [0] = 0;
70  building =0;
71  remember =0;
72  gMessMgr = (StMessMgr*) this;
73  messTypeList = StMessTypeList::Instance();
74  messCounter = StMessageCounter::Instance();
75  messCounter->AddType(emptyString);
76  // First messVec on collection is list of all messages
77  messCollection.push_back(&messList);
78  AddType("I","Info");
79  AddType("W","Warning");
80  AddType("E","Error");
81  AddType("D","Debug");
82  AddType("Q","QAInfo");
83  AddType("U","UCMInfo");
84  SwitchOff("D");
85 #ifdef __linux__
86  memset(listOfMessPtrs,0,(maxLOMP * sizeof(char*)));
87 #endif
88 }
89 //_____________________________________________________________________________
90 StMessageManager::~StMessageManager() {
91 //
92 // Destructor - must delete the message lists
93 //
94  messVecIter current;
95  for (current=messList.begin(); current!=messList.end(); current++)
96  delete (*current);
97  for (size_t i=1; i<messCollection.size(); i++)
98  delete (messCollection[i]);
99  myout << "WARNING!!! DELETING StMessageManager!" << endl;
100  gMessMgr = 0;
101 }
102 //_____________________________________________________________________________
103 StMessMgr* StMessageManager::Instance() {
104 //
105 // Allows anyone to get a pointer to the single message manager:
106 // StMessageManager::Instance()->(member function)
107 //
108  if (gMessMgr) return gMessMgr;
109  if (!mInstance) {
110  mInstance = (StMessMgr*) new StMessageManager;
111  }
112  return mInstance;
113 }
114 //_____________________________________________________________________________
115 std::ostringstream& StMessageManager::Message(const char* mess, const char* type,
116  const char* opt,const char *,int) {
117 //
118 // Message declarator - creates a new message if mess is not empty,
119 // otherwise, prepares for << input.
120 //
121  if (!opt) opt = "";
122  size_t messSize = strlen(mess);
123  if (messSize) {
124 #ifdef __linux__
125  if (sMessLength == 1) { // Check for re-used mess ptr
126  for (int i=lastLOMP; i>=0; i--) {
127  if (mess == listOfMessPtrs[i]) { // mess ptr found
128  (listOfMessPtrs[i])[(listOfMessLens[i]-1)]=0;
129  lastLOMP = i;
130  break;
131  }
132  if (i==0) { // mess ptr not found
133  if (lastLOMP==maxLOMP1) {
134  BuildMessage("StMessageManager - maximum depth reached on ptr list",
135  "W","E");
136  } else {
137  lastLOMP++;
138  listOfMessPtrs[lastLOMP] = const_cast<char*> (mess);
139  listOfMessLens[lastLOMP] = messSize;
140  }
141  }
142  }
143  }
144 #endif
145  BuildMessage(mess, type, opt); // comes back with curType=0
146  } else {
147  building = 1;
148  *curType = *type;
149  strcpy(curOpt,opt);
150  seekp(0);
151  }
152  return *((StMessMgr*) this);
153 }
154 //_____________________________________________________________________________
155 void StMessageManager::BuildMessage(const char* mess, const char* type,
156  const char* opt) {
157 //
158 // Instantiate an StMessage and place on the lists of known messages
159 //
160  if (!opt) opt = "";
161  if (!(*type)) {
162  static char dash = '-'; // if no type supplied,
163  const char* cptr = strchr(mess,dash); // search for type within message
164  if (cptr)
165  *curType = *(++cptr);
166  else
167  *curType = defaultMessType;
168  } else {
169  if (!building) *curType = *type;
170  }
171  if (!(opt[0])) {
172  if ((*type == 'E') || (*type == 'W')) // Error and Warning messages
173  strcpy(curOpt,eOpt); // default to stderr,
174  else // otherwise
175  strcpy(curOpt,oOpt); // default to stdout
176  } else
177  if (!building) strcpy(curOpt,opt);
178  int typeN = messTypeList->FindTypeNum(curType);
179  if (!typeN) {
180  *curType = defaultMessType; // default type is Info
181  typeN = 1; // type number for Info is 1
182  }
183  if ((!remember) || strchr(curOpt,'-')) {
184  StMessage tmp(mess, curType, curOpt);
185  gMessage = endm;
186  } else {
187  gMessage = new StMessage(mess, curType, curOpt);
188 #ifndef i386_redhat60
189  messList.push_back(gMessage); // add to message lists
190  messCollection[typeN]->push_back(gMessage);
191 #endif
192  endm = gMessage;
193  }
194 }
195 //_____________________________________________________________________________
196 void StMessageManager::Print() {
197 //
198 // Empty the buffer into the current message and print it.
199 // If not currenty building a message, print the last one created.
200 //
201  if (building) {
202  *this << std::ends;
203 
204  BuildMessage(str().c_str(), curType, curOpt);
205  building = 0;
206 
207  } else {
208 
209  if (gMessage) {
210  gMessage->Print(-1);
211  } else {
212  myout << "No current message." << endl;
213  }
214  }
215 }
216 //_____________________________________________________________________________
217 int StMessageManager::PrintList(messVec* list) {
218 //
219 // Print a list of messages from a messVec list.
220 //
221  messVecIter current;
222  int i=0;
223  for (current=list->begin(); current!=list->end(); current++)
224  {(*current)->Print(-1); i++;}
225  return i;
226 }
227 //_____________________________________________________________________________
228 messVecIter StMessageManager::FindMessageIter(const char* s1, const char* s2,
229  const char* s3, const char* s4, messVec* list) {
230 //
231 // Obtain an iterator for a particular StMessage on a list of messages.
232 // First message which contains matches to the strings s1,s2,s3,s4 is returned.
233 //
234  if (!list) list = &messList;
235  messVecIter current;
236  const char* curMess;
237  for (current=list->begin(); current!=list->end(); current++) {
238  curMess = (*current)->GetMessage();
239  if ((strstr(curMess,s1)) && (strstr(curMess,s2)) &&
240  (strstr(curMess,s3)) && (strstr(curMess,s4))) return current;
241  }
242  return list->end();
243 }
244 //_____________________________________________________________________________
245 StMessage* StMessageManager::FindMessage(const char* s1, const char* s2,
246  const char* s3, const char* s4, messVec* list) {
247 //
248 // Obtain a pointer to a particular StMessage on a list of messages.
249 // First message which contains matches to the strings s1,s2,s3,s4 is returned.
250 //
251  messVecIter current = FindMessageIter(s1,s2,s3,s4,list);
252  return (current!=list->end()) ? (*current) : 0 ;
253 }
254 //_____________________________________________________________________________
255 messVec* StMessageManager::FindMessageList(const char* s1, const char* s2,
256  const char* s3, const char* s4, messVec* list) {
257 //
258 // Obtain a list (messVec) of StMessage pointers for all messages
259 // which contain matches to the strings s1,s2,s3,s4.
260 //
261  size_t s1_len = strlen(s1);
262  if ((s1_len==1) && (!list)) {
263  int typeN = messTypeList->FindTypeNum(s1);
264  if (typeN) {
265  list = messCollection[typeN];
266  s1_len = 0;
267  }
268  }
269  if (!list) list = &messList;
270  if (!((s1_len) || (strlen(s2)) || (strlen(s3)) || (strlen(s4))))
271  return list;
272  messVec* newList = new messVec();
273  messVecIter current;
274  const char* curMess;
275  for (current=list->begin(); current!=list->end(); current++) {
276  curMess = (*current)->GetMessage();
277  if ((strstr(curMess,s1)) && (strstr(curMess,s2)) &&
278  (strstr(curMess,s3)) && (strstr(curMess,s4)))
279  newList->push_back(*current);
280  }
281  return newList;
282 }
283 //_____________________________________________________________________________
284 int StMessageManager::RemoveMessage(StMessage* mess) {
285 //
286 // Delete a message and remove it from all lists.
287 //
288  if (!mess) return 3;
289  const char* curMess = mess->GetMessage();
290  messVecIter current = FindMessageIter(curMess);
291  if (current==messList.end()) return 1;
292  messList.erase(current);
293  int typeN = messTypeList->FindTypeNum(mess->GetType());
294  current = FindMessageIter(curMess,emptyString,emptyString,
295  emptyString,messCollection[typeN]);
296  if (current==messCollection[typeN]->end()) return 2;
297  messCollection[typeN]->erase(current);
298  delete mess;
299  if (mess==gMessage) gMessage = 0;
300  return 0;
301 }
302 //_____________________________________________________________________________
303 void StMessageManager::Summary(size_t nTerms) {
304 //
305 // Output a summary of the messages printed so far.
306 // nTerms - number of tokens (text separated by spaces) to use in
307 // comparisons between messages (default is 1). Messages are
308 // compared only if they are of the same message type, and
309 // only the message string (not the message type) is included
310 // in the number of tokens compared. For example, Summary(0)
311 // would give the number of each type of message with no
312 // differentiation based on the message string.
313 //
314  const size_t mmax = 81;
315  size_t max = mmax - 12;
316  size_t messmax = mmax - 1;
317  size_t nMess = messList.size();
318  intVector done;
319  typedef StVector(char*) CharPtrVec;
320  CharPtrVec mType;
321  CharPtrVec messBlocks;
322  StVector(CharPtrVec) toks;
323  size_t i;
324  size_t j;
325  size_t k;
326  int agree;
327  char* temp;
328  myout << " ***** StMessageManager message summary *****" << endl;
329  toks.resize(nMess);
330  for (i=0; i<nMess; i++) {
331  done.push_back(0);
332  temp = const_cast<char*> (messList[i]->GetType());
333  mType.push_back(temp);
334  messBlocks.push_back(new char[mmax]);
335  temp = strncpy(messBlocks[i],(messList[i]->GetMessage()),messmax);
336  temp = strtok(temp, " ");
337  toks[i].push_back(temp);
338  while (temp != NULL) {
339  temp = strtok(NULL, " ");
340  toks[i].push_back(temp);
341  }
342  for (j=toks[i].size(); j<nTerms; j++) toks[i].push_back(temp);
343  }
344  for (i=0; i<nMess; i++) {
345  int count = 1;
346  if (!(done[i])) {
347  for (j=(i+1); j<nMess; j++) {
348  if ((*(mType[i]))==(*(mType[j]))) {
349  agree = 1;
350  for (k=0; k<nTerms; k++) {
351  if (toks[i][k] != NULL) {
352  if ((toks[j][k] == NULL) ||
353  strcmp(toks[i][k],toks[j][k])) agree = 0;
354  }
355  else if (toks[j][k] != NULL) agree = 0;
356  }
357  if (agree) {
358  done[j] = 1;
359  count++;
360  }
361  }
362  }
363  done[i] = 1;
364  for (j = messList[i]->Print(max); j<max; j++) myout << ".";
365  myout << "..";
366  seekp(0);
367  *this << count << std::ends;
368  if (tellp() > 6) {
369  myout << ">999999";
370  } else {
371  for (j=tellp(); j<6; j++) myout << ".";
372  myout << " " << count << endl;
373  }
374  }
375  mType[i] = NULL;
376  memset(messBlocks[i],0,mmax);
377  delete [] messBlocks[i];
378  }
379  MemorySummary();
380  return;
381 }
382 //_____________________________________________________________________________
383 void StMessageManager::MemorySummary() {
384 //
385 // Output a summary of the memory usage of the message manager so far.
386 // Loops over all stored messages to calculate message sizes and overhead.
387 //
388  unsigned int gsize=0;
389  size_t nMess = messList.size();
390  for (size_t i=0; i<nMess; i++) {
391  gsize += (messList[i]->GetMemoryUsage() + 2*sizeof(messList[i]));
392  }
393  printf(" ***** StMessageManager memory usage = %u bytes (%u kb) *****\n",
394  gsize,(gsize/1024));
395  return;
396 }
397 //_____________________________________________________________________________
398 int StMessageManager::AddType(const char* type, const char* text) {
399 //
400 // Add an additional message type. ListTypes() will return a list of all
401 // currently defined message types. AddType returns a integer which is zero
402 // if type has already been defined, otherwise returns the number of types
403 // defined (including the new one).
404 // type - a single character string which will represent the message type.
405 // text - a short charact string which will be printed with all messages
406 // of this type.
407 //
408  int typeN = messTypeList->AddType(type,text);
409  if (typeN) {
410  messVec* temp = new messVec(); // Add a new messVec for each message type
411  messCollection.push_back(temp);
412  messCounter->AddType(type);
413  }
414  return typeN;
415 }
416 //_____________________________________________________________________________
417 void StMessageManager::PrintInfo() {
418  printf("**************************************************************\n");
419  printf("* $Id: StMessageManager.cxx,v 1.51 2016/06/14 06:25:45 genevb Exp $\n");
420 // printf("* %s *\n",m_VersionCVS);
421  printf("**************************************************************\n");
422 }
423 //_____________________________________________________________________________
424 void StMessageManager::SetLevel(Int_t)
425 {
426  fprintf(stderr,"StMessageManager class provides no implementation SetLevel method\n");
427 }
428 //_____________________________________________________________________________
429 Int_t StMessageManager::GetLevel(Int_t) const
430 {
431  fprintf(stderr,"StMessageManager class provides no implementation GetLevel method\n");
432  return -999;
433 }
434 //_____________________________________________________________________________
435 const char *StMessageManager::GetName() const
436 {
437  fprintf(stderr,"StMessageManager class provides no implementation GetName method\n");
438  return 0;
439 }
440 
441 
442 // Instantiate the (singleton) class upon loading
443 //
444 static StMessMgr* temp=StMessageManager::Instance();
445 // StMessMgr& gMess = (*temp);
446 
447 
448 //_____________________________________________________________________________
449 // $Id: StMessageManager.cxx,v 1.51 2016/06/14 06:25:45 genevb Exp $
450 // $Log: StMessageManager.cxx,v $
451 // Revision 1.51 2016/06/14 06:25:45 genevb
452 // Infrequently used memory leak (Coverity)
453 //
454 // Revision 1.50 2015/05/21 21:22:40 genevb
455 // Fix memory leak: unnecessary char array in FindMessageList()
456 //
457 // Revision 1.49 2012/06/11 15:05:34 fisyak
458 // std namespace
459 //
460 // Revision 1.48 2009/06/22 22:36:01 fine
461 // Add the new dedicated UCM logger, It should force the recompilation of many STAR packages
462 //
463 // Revision 1.47 2008/05/15 23:40:24 fine
464 // Change the abstarct class return type to separate the different STAR streams
465 //
466 // Revision 1.46 2007/01/25 06:28:06 fine
467 // connect Logger and Maker debug levels
468 //
469 // Revision 1.45 2007/01/25 06:11:37 fine
470 // Add the new StMess abstarct interfaces GetLevel/SetLevel
471 //
472 // Revision 1.44 2005/02/04 21:35:09 genevb
473 // Fixed bug with remember from v. 1.43 (used pointer before assignment)
474 //
475 // Revision 1.43 2004/09/25 03:01:04 perev
476 // Improved correction with remember messages
477 //
478 // Revision 1.42 2004/09/16 02:25:54 perev
479 // typo fixed, memory leak off
480 //
481 // Revision 1.41 2004/04/15 21:28:02 fine
482 // Remove the redundant StMessageManager RootCint dictionary. User shoudl use the base StMessMgr class anyway
483 //
484 // Revision 1.40 2004/04/15 16:03:38 fine
485 // move StMessMgr class to St_base and change the interface
486 //
487 // Revision 1.39 2003/10/28 20:58:32 perev
488 // Linux ==> __linux__
489 //
490 // Revision 1.38 2003/10/10 23:28:43 genevb
491 // Trust line length argument from Fortran, works better than algorithm now
492 //
493 // Revision 1.37 2003/10/01 20:06:50 genevb
494 // Initialize and test ostrstream buffer sizes (support for gcc before 3.2)
495 //
496 // Revision 1.36 2003/09/25 21:19:22 genevb
497 // Some new cout-like functions and friend functions, some doxygen-ization
498 //
499 // Revision 1.35 2003/09/24 22:02:48 perev
500 // Back to Gene solution of operator<<
501 //
502 // Revision 1.34 2003/09/22 01:30:41 perev
503 // some cleanup
504 //
505 // Revision 1.33 2003/09/02 17:59:20 perev
506 // gcc 3.2 updates + WarnOff
507 //
508 // Revision 1.32 2001/05/14 20:53:20 genevb
509 // Add features to examine memory use, switch from TDatime to time_t
510 //
511 // Revision 1.31 2000/05/23 19:03:38 genevb
512 // Correct interface for MessageOut(), update docs
513 //
514 // Revision 1.30 2000/03/01 05:54:59 genevb
515 // Further refinements to FORTRAN routines
516 //
517 // Revision 1.29 2000/02/29 16:41:57 genevb
518 // Fortran-compliant interface
519 //
520 // Revision 1.28 2000/01/05 19:53:46 genevb
521 // Fixed CC5 warnings, and several other small improvements under the hood
522 //
523 // Revision 1.27 1999/12/07 19:47:02 genevb
524 // Increased length of mess ptr list for __linux__
525 //
526 // Revision 1.26 1999/10/28 16:06:58 genevb
527 // Fixed bug in C msg_enable routine - same as earlier fix for StMessage routines
528 //
529 // Revision 1.25 1999/09/16 15:50:25 genevb
530 // Fixed a bug in over-writing memory when calling from FORTRAN, use char=0 instead of strcpy
531 //
532 // Revision 1.24 1999/09/14 16:57:56 genevb
533 // Forgot to remove a debug print statement
534 //
535 // Revision 1.23 1999/09/14 15:42:03 genevb
536 // Some bug fixes, workaround for nulls in strings
537 //
538 // Revision 1.22 1999/09/10 21:05:55 genevb
539 // Some workarounds for RedHat6.0
540 //
541 // Revision 1.21 1999/08/12 22:34:28 genevb
542 // Additional crash protection for __linux__ when omitting parameter strings (opt=strlen(mess))
543 //
544 // Revision 1.20 1999/08/10 22:07:35 genevb
545 // Added QAInfo message types
546 //
547 // Revision 1.19 1999/07/25 05:27:45 genevb
548 // Better protection against empty option strings in FORTRAN
549 //
550 // Revision 1.18 1999/07/23 16:56:40 genevb
551 // Fix extern C prototypes, default options for omitted types, __linux__ bug with multi-line messages
552 //
553 // Revision 1.17 1999/07/22 00:19:31 genevb
554 // Add MessageOut(), fix __linux__ bugs with character array lengths passed from FORTRAN
555 //
556 // Revision 1.16 1999/07/17 00:23:24 genevb
557 // Fixed bug when option fields are empty in FORTRAN, and let type limits be set before types are even added
558 //
559 // Revision 1.15 1999/07/08 22:58:18 genevb
560 // Created an abstract interface with StMessMgr.h hiding template implementation from others, a few other small fixes
561 //
562 // Revision 1.14 1999/07/01 23:32:52 genevb
563 // Change default message typing
564 //
565 // Revision 1.13 1999/07/01 15:58:44 genevb
566 // Fixed __linux__ crash with Summary
567 //
568 // Revision 1.12 1999/07/01 01:24:46 genevb
569 // Fixed FORTRAN character string bug on __linux__, removed a memory leak from Summary()
570 //
571 // Revision 1.11 1999/06/30 17:24:50 genevb
572 // Better limit management, remove Bool_t
573 //
574 // Revision 1.10 1999/06/30 04:18:45 genevb
575 // Fixes: summary wrap-around, unsigned ints, last character of message, <> for time; no KNOWN remaining bugs
576 //
577 // Revision 1.9 1999/06/29 23:32:42 genevb
578 // Handle multi-line calls to fortran routines better
579 //
580 // Revision 1.8 1999/06/29 17:37:31 genevb
581 // Lots of fixes...
582 //
583 // Revision 1.7 1999/06/28 15:42:12 genevb
584 // Added Debug message class
585 //
586 // Revision 1.6 1999/06/28 02:40:56 genevb
587 // Additional backward compatibilit with MSG (msg_enable, msg_enabled, msg_disable
588 //
589 // Revision 1.5 1999/06/26 00:24:53 genevb
590 // Fixed const type mismatches
591 //
592 // Revision 1.4 1999/06/25 22:57:58 genevb
593 // Fixed a small bug in MSG compatibiliti
594 //
595 // Revision 1.3 1999/06/24 23:23:58 genevb
596 // Added message call for compatibility with old fortran code
597 //
598 // Revision 1.2 1999/06/24 16:30:42 genevb
599 // Fixed some memory leaks
600 //
601 // Revision 1.1 1999/06/23 15:17:52 genevb
602 // Introduction of StMessageManager
603 //