1    	//////////////////////////////////////////////////////////////////////////
2    	//                                                                      //
3    	// StMessage                                                            //
4    	//                                                                      //
5    	// This is the class of messages used by StMessageManager in STAR.      //
6    	// Messages have a type and message specified at instantiation,         //
7    	// and also include a time-date stamp and options for printing.         //
8    	//                                                                      //
9    	//////////////////////////////////////////////////////////////////////////
10   	
11   	#ifdef __ROOT__
12   	#include "TROOT.h"
13   	#endif
14   	#include <assert.h>
15   	#include <ctype.h>
16   	#include <string.h>
17   	#include "StMessage.h"
18   	#include "StMessageCounter.h"
19   	#include "Stsstream.h"
20   	#include "StMessageStream.h"
21   	using namespace std;
22   	static StMessageCounter* messCounter = StMessageCounter::Instance();
23   	
24   	static ostrstream messBuffer;
25   	static char space = ' ';
26   	static char tab = '\t';
27   	
28   	int StMessage::repeats=1;
29   	static ostrstream lastMessBuffer;
30   	
31   	#ifdef __ROOT__
32   	ClassImp(StMessage)
33   	#endif
34   	
35   	//_____________________________________________________________________________
36   	StMessage::StMessage(const char *mess, const char *ty, const char* opt) {
37   	  time(&messTime);
38   	  *type = *ty;
39   	  type[1] = 0;
40   	  SetOptions(opt);
41   	//  location = "Unknown";
42   	//  runNumber = 0;
43   	  int len = strlen(mess);
44   	  while (mess[--len] == space) {}     // remove trailing spaces
45   	  message = new char[(++len + 1)];
46   	  for (int i=0;i<len;i++) {
47   	    message[i]=mess[i];
48   	    if (mess[i]=='\n') 		continue;
49   	    if (mess[i]=='\t') 		continue;
50   	    if (!iscntrl(mess[i]))	continue;
51   	    assert(0);
52   	  }
53   	  message[len]=0;
54   	  Print(0);
55   	}
56   	//_____________________________________________________________________________
57   	StMessage::~StMessage() {
58   	  delete [] message;
59   	}
60   	//_____________________________________________________________________________
61   	int StMessage::Print(int nChars) {
62   	//_nChars_:___mode__:_printing_
63   	//   <0   : view    : as intended, no limits, use options
64   	//   =0   : normal  : as intended, use limits, use options
65   	//   >0   : summary : stdout upto nChars/first endofline, no limits, no options
66   	  static const char* leader = "St";
67   	  static const char* insert0 = "";
68   	  static const char* insert1 = ": ";
69   	  static const char* insert2 = " <";
70   	  static const char* insert3 = ">";
71   	  static const char* endofline = "\n";
72   	  int printIt=1;
73   	  if (!nChars) {
74   	    printIt = messCounter->CheckLimit(message,type);
75   	  }
76   	  messBuffer.seekp(0);
77   	  if (printIt) {
78   	    const char* insert;
79   	    if (!(option & kMessOptP)) {
80   	      if (!(option & kMessOptS)) messBuffer << leader;   // "No St" option
81   	      const char* temp(StMessTypeList::Instance()->Text(type));
82   	      if (temp) messBuffer << temp;
83   	      insert = insert1;
84   	    } else insert = insert0;
85   	    if ((nChars != 0) && (strchr(message,tab))) {        // If nChars, replace
86   	      char* message2 = new char[strlen(message)+1];      // tabs with spaces
87   	      char* m0 = message;
88   	      char* m1 = message2;
89   	      while (*m0) {                                      // Go to end of string
90   	        if (*m0==tab) *m1 = space;                       // tab => space,
91   	        else *m1 = *m0;                                  // otherwise copy
92   	        m0++; m1++;
93   	      }
94   	      *m1 = 0; 
95   	      messBuffer << insert << message2;                  // ": ",message
96   	      delete [] message2;
97   	    } else {
98   	      messBuffer << insert << message;                   // ": ",message
99   	    }
100  	    if (nChars<=0) {
101  	      if (option & kMessOptT) {                          // "time" option
102  	        char* temp2 = (ctime(&messTime) + 4);            // First 4 are day
103  	        *(temp2 + 20) = 0;                               // 24th is end-line
104  	        messBuffer << insert2 << temp2 << insert3 ;      // " (",time,")"
105  	      }
106  	      messBuffer << endofline;                           // "\n" end-line
107  	    }
108  	  }
109  	  const char* addedMessage=0;
110  	  if (nChars == 0) {
111  	    addedMessage = messCounter->str();                   // Any limit message
112  	  } else {
113  	    if (nChars>0) {
114  	      if (messBuffer.tellp() >= nChars)
115  	        messBuffer.seekp(nChars-1);   // set end-of-string at nChars
116  	      int noReturns = strcspn(messBuffer.str(),endofline);
117  	      if (noReturns < messBuffer.tellp()) messBuffer.seekp(noReturns);
118  	    } else
119  	      nChars = 0;
120  	  }
121  	  messBuffer << ends;
122  	  if (!repeats) {
123  	    if (!strcmp(messBuffer.str(),lastMessBuffer.str())) {
124  	      return messBuffer.tellp();
125  	    } else {
126  	      lastMessBuffer.seekp(0);
127  	      lastMessBuffer << messBuffer.str() << ends;
128  	    }
129  	  }
130  	  if ((option & kMessOptO) || (nChars != 0)) {
131  	    myout << messBuffer.str();
132  	    if (addedMessage) myout << addedMessage;
133  	    myout.flush();
134  	  }
135  	  if ((option & kMessOptE) && (nChars == 0)) {
136  	    myerr << messBuffer.str();
137  	    if (addedMessage) myerr << addedMessage;
138  	    myerr.flush();
139  	  }
140  	  return messBuffer.tellp();
141  	}
142  	//_____________________________________________________________________________
143  	char* StMessage::GetOptions() const {
144  	  static char optStr[32]; // Use single, static instance to avoid memory leak
145  	  char* sPtr = optStr;
146  	  if (option & kMessOptO) sprintf(sPtr++,"%c",'O');
147  	  if (option & kMessOptE) sprintf(sPtr++,"%c",'E');
148  	  if (option & kMessOptS) sprintf(sPtr++,"%c",'S');
149  	  if (option & kMessOptT) sprintf(sPtr++,"%c",'T');
150  	  if (option & kMessOptP) sprintf(sPtr++,"%c",'P');
151  	  if (option & kMessOptDash) sprintf(sPtr++,"%c",'-');
152  	  (*sPtr) = 0; // Terminate string
153  	  return optStr;
154  	}
155  	//_____________________________________________________________________________
156  	void StMessage::SetOptions(const char* opt) {
157  	  option = kMessOptNone;
158  	  if (!opt) return;
159  	  int len = strlen(opt);
160  	  while (len--) {
161  	    switch (toupper(opt[len])) {
162  	      case ('O') : { option |= kMessOptO; break; }
163  	      case ('E') : { option |= kMessOptE; break; }
164  	      case ('S') : { option |= kMessOptS; break; }
165  	      case ('T') : { option |= kMessOptT; break; }
166  	      case ('P') : { option |= kMessOptP; break; }
167  	      case ('-') : { option |= kMessOptDash; break; }
168  	      default : {}
169  	    }
170  	  }
171  	}
172  	//_____________________________________________________________________________
173  	size_t StMessage::GetMemoryUsage() {
174  	  size_t msize = strlen(message) + 1;
175  	  msize += sizeof(*this);                   // Determine overhead
176  	  return msize;
177  	}
178  	//_____________________________________________________________________________
179  	void StMessage::PrintInfo() {
180  	  printf("**************************************************************\n");
181  	  printf("* $Id: StMessage.cxx,v 1.29 2016/06/14 06:24:54 genevb Exp $\n");
182  	//  printf("* %s    *\n",m_VersionCVS);
183  	  printf("**************************************************************\n");
184  	}
185  	//_____________________________________________________________________________
186  	int StMessage::InitBuffer() {
187  	  // Initialize buffer with 1088 bytes.
188  	  messBuffer << ch64 << ch64 << ch64 << ch64 << ch64 << ch64 << ch64 << ch64
189  	     << ch64 << ch64 << ch64 << ch64 << ch64 << ch64 << ch64 << ch64 << ch64;
190  	  return messBuffer.tellp();
191  	}
192  	
193  	int tmpp = StMessage::InitBuffer();
194  	
195  	//_____________________________________________________________________________
196  	// $Id: StMessage.cxx,v 1.29 2016/06/14 06:24:54 genevb Exp $
197  	// $Log: StMessage.cxx,v $
198  	// Revision 1.29  2016/06/14 06:24:54  genevb
199  	// Very old cut-and-paste typo (Coverity)
200  	//
201  	// Revision 1.28  2012/06/11 15:05:34  fisyak
202  	// std namespace
203  	//
204  	// Revision 1.27  2004/04/02 22:17:14  genevb
205  	// Added protected Ignore/AllowRepeats() for friend StBFChain class
206  	//
207  	// Revision 1.26  2004/03/01 17:52:13  fisyak
208  	// Add include for assert (osf required)
209  	//
210  	// Revision 1.25  2004/01/28 00:09:14  genevb
211  	// Messages (except Debug) default to no time-date stamp
212  	//
213  	// Revision 1.24  2003/10/01 20:06:50  genevb
214  	// Initialize and test ostrstream buffer sizes (support for gcc before 3.2)
215  	//
216  	// Revision 1.23  2003/09/25 21:18:14  genevb
217  	// Changed option storage
218  	//
219  	// Revision 1.22  2003/09/22 01:30:41  perev
220  	//  some cleanup
221  	//
222  	// Revision 1.21  2003/09/02 17:59:20  perev
223  	// gcc 3.2 updates + WarnOff
224  	//
225  	// Revision 1.20  2001/05/14 20:53:20  genevb
226  	// Add features to examine memory use, switch from TDatime to time_t
227  	//
228  	// Revision 1.19  2000/01/05 19:53:46  genevb
229  	// Fixed CC5 warnings, and several other small improvements under the hood
230  	//
231  	// Revision 1.18  1999/12/28 21:29:55  porter
232  	// added 'using std::vector' and a (char*) cast to allow compilation
233  	// using solaris CC5.  Many warnings of const char* vs char* still
234  	// exist but will await Gene's return to fix these
235  	//
236  	// Revision 1.17  1999/09/16 15:50:25  genevb
237  	// Fixed a bug in over-writing memory when calling from FORTRAN, use char=0 instead of strcpy
238  	//
239  	// Revision 1.16  1999/09/14 15:42:03  genevb
240  	// Some bug fixes, workaround for nulls in strings
241  	//
242  	// Revision 1.15  1999/09/11 23:12:23  fisyak
243  	// Add cast for HP
244  	//
245  	// Revision 1.14  1999/09/10 21:05:55  genevb
246  	// Some workarounds for RedHat6.0
247  	//
248  	// Revision 1.13  1999/08/10 22:07:35  genevb
249  	// Added QAInfo message types
250  	//
251  	// Revision 1.12  1999/07/22 00:17:47  genevb
252  	// make messBuffer static
253  	//
254  	// Revision 1.11  1999/07/15 05:15:06  genevb
255  	// Fixed an odd bug with seekp(0) on an empty stream buffer
256  	//
257  	// Revision 1.10  1999/07/08 22:58:18  genevb
258  	// Created an abstract interface with StMessMgr.h hiding template implementation from others, a few other small fixes
259  	//
260  	// Revision 1.9  1999/07/01 01:24:46  genevb
261  	// Fixed FORTRAN character string bug on linux, removed a memory leak from Summary()
262  	//
263  	// Revision 1.7  1999/06/30 04:18:45  genevb
264  	// Fixes: summary wrap-around, unsigned ints, last character of message, <> for time; no KNOWN remaining bugs
265  	//
266  	// Revision 1.6  1999/06/29 23:32:41  genevb
267  	// Handle multi-line calls to fortran routines better
268  	//
269  	// Revision 1.5  1999/06/29 19:17:14  genevb
270  	// Lots of fixes..
271  	//
272  	// Revision 1.3  1999/06/26 00:24:52  genevb
273  	// Fixed const type mismatches
274  	//
275  	// Revision 1.2  1999/06/24 16:30:41  genevb
276  	// Fixed some memory leaks
277  	//
278  	// Revision 1.1  1999/06/23 15:17:46  genevb
279  	// Introduction of StMessageManager
280  	//
281  	// Revision 1.0  1999/01/27 10:28:29  genevb
282  	//
283