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