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