1 /* $Id: CoinMessageHandler.cpp 1448 2011-06-19 15:34:41Z stefan $ */
2 // Copyright (C) 2002, International Business Machines
3 // Corporation and others.  All Rights Reserved.
4 // This code is licensed under the terms of the Eclipse Public License (EPL).
5 
6 #include "CoinMessageHandler.hpp"
7 #include "CoinHelperFunctions.hpp"
8 #include <cassert>
9 #include <cstdlib>
10 #include <cstddef>
11 #include <map>
12 
13 /* Default constructor. */
CoinOneMessage()14 CoinOneMessage::CoinOneMessage()
15 {
16   externalNumber_=-1;
17   message_[0]='\0';
18   severity_='I';
19   detail_=0;
20 }
21 /* Destructor */
~CoinOneMessage()22 CoinOneMessage::~CoinOneMessage()
23 {
24 }
25 /* The copy constructor */
CoinOneMessage(const CoinOneMessage & rhs)26 CoinOneMessage::CoinOneMessage(const CoinOneMessage & rhs)
27 {
28   externalNumber_=rhs.externalNumber_;
29   strcpy(message_,rhs.message_);
30   severity_=rhs.severity_;
31   detail_=rhs.detail_;
32 }
33 /* assignment operator. */
34 CoinOneMessage&
operator =(const CoinOneMessage & rhs)35 CoinOneMessage::operator=(const CoinOneMessage & rhs)
36 {
37   if (this != &rhs) {
38     externalNumber_=rhs.externalNumber_;
39     strcpy(message_,rhs.message_);
40     severity_=rhs.severity_;
41     detail_=rhs.detail_;
42   }
43   return *this;
44 }
45 /* Normal constructor */
CoinOneMessage(int externalNumber,char detail,const char * message)46 CoinOneMessage::CoinOneMessage(int externalNumber, char detail,
47 		const char * message)
48 {
49   externalNumber_=externalNumber;
50   strcpy(message_,message);
51   if (externalNumber<3000)
52     severity_='I';
53   else if (externalNumber<6000)
54     severity_='W';
55   else if (externalNumber<9000)
56     severity_='E';
57   else
58     severity_='S';
59   detail_=detail;
60 }
61 // Replaces messages (i.e. a different language)
62 void
replaceMessage(const char * message)63 CoinOneMessage::replaceMessage( const char * message)
64 {
65   strcpy(message_,message);
66 }
67 
68 
69 /* Constructor with number of messages. */
CoinMessages(int numberMessages)70 CoinMessages::CoinMessages(int numberMessages)
71 {
72   numberMessages_=numberMessages;
73   language_=us_en;
74   strcpy(source_,"Unk");
75   class_=1;
76   lengthMessages_=-1;
77   if (numberMessages_) {
78     message_ = new CoinOneMessage * [numberMessages_];
79     int i;
80     for (i=0;i<numberMessages_;i++)
81       message_[i]=NULL;
82   } else {
83     message_=NULL;
84   }
85 }
86 /* Destructor */
~CoinMessages()87 CoinMessages::~CoinMessages()
88 {
89   int i;
90   if (lengthMessages_<0) {
91     for (i=0;i<numberMessages_;i++)
92       delete message_[i];
93   }
94   delete [] message_;
95 }
96 /* The copy constructor */
CoinMessages(const CoinMessages & rhs)97 CoinMessages::CoinMessages(const CoinMessages & rhs)
98 {
99   numberMessages_=rhs.numberMessages_;
100   language_=rhs.language_;
101   strcpy(source_,rhs.source_);
102   class_=rhs.class_;
103   lengthMessages_=rhs.lengthMessages_;
104   if (lengthMessages_<0) {
105     if (numberMessages_) {
106       message_ = new CoinOneMessage * [numberMessages_];
107       int i;
108       for (i=0;i<numberMessages_;i++)
109 	if (rhs.message_[i])
110 	  message_[i]=new CoinOneMessage(*(rhs.message_[i]));
111 	else
112 	  message_[i] = NULL;
113     } else {
114       message_=NULL;
115     }
116   } else {
117     char * temp = CoinCopyOfArray(reinterpret_cast<char *> (rhs.message_),lengthMessages_);
118     message_ = reinterpret_cast<CoinOneMessage **> (temp);
119     std::ptrdiff_t offset = temp - reinterpret_cast<char *> (rhs.message_);
120     int i;
121     //printf("new address %x(%x), rhs %x - length %d\n",message_,temp,rhs.message_,lengthMessages_);
122     for (i=0;i<numberMessages_;i++) {
123       if (message_[i]) {
124 	char * newAddress = (reinterpret_cast<char *> (message_[i])) + offset;
125 	assert (newAddress-temp<lengthMessages_);
126 	message_[i] = reinterpret_cast<CoinOneMessage *> (newAddress);
127 	//printf("message %d at %x is %s\n",i,message_[i],message_[i]->message());
128 	//printf("message %d at %x wass %s\n",i,rhs.message_[i],rhs.message_[i]->message());
129       }
130     }
131   }
132 }
133 /* assignment operator. */
134 CoinMessages&
operator =(const CoinMessages & rhs)135 CoinMessages::operator=(const CoinMessages & rhs)
136 {
137   if (this != &rhs) {
138     language_=rhs.language_;
139     strcpy(source_,rhs.source_);
140     class_=rhs.class_;
141     if (lengthMessages_<0) {
142       int i;
143       for (i=0;i<numberMessages_;i++)
144 	delete message_[i];
145     }
146     delete [] message_;
147     numberMessages_=rhs.numberMessages_;
148     lengthMessages_=rhs.lengthMessages_;
149     if (lengthMessages_<0) {
150       if (numberMessages_) {
151 	message_ = new CoinOneMessage * [numberMessages_];
152 	int i;
153 	for (i=0;i<numberMessages_;i++)
154 	  if (rhs.message_[i])
155 	    message_[i]=new CoinOneMessage(*(rhs.message_[i]));
156 	  else
157 	    message_[i] = NULL;
158       } else {
159 	message_=NULL;
160       }
161     } else {
162       char * temp = CoinCopyOfArray(reinterpret_cast<char *> (rhs.message_),lengthMessages_);
163       message_ = reinterpret_cast<CoinOneMessage **> (temp);
164       std::ptrdiff_t offset = temp - reinterpret_cast<char *> (rhs.message_);
165       int i;
166       //printf("new address %x(%x), rhs %x - length %d\n",message_,temp,rhs.message_,lengthMessages_);
167       for (i=0;i<numberMessages_;i++) {
168 	if (message_[i]) {
169 	  char * newAddress = (reinterpret_cast<char *> (message_[i])) + offset;
170 	  assert (newAddress-temp<lengthMessages_);
171 	  message_[i] = reinterpret_cast<CoinOneMessage *> (newAddress);
172 	  //printf("message %d at %x is %s\n",i,message_[i],message_[i]->message());
173 	  //printf("message %d at %x wass %s\n",i,rhs.message_[i],rhs.message_[i]->message());
174 	}
175       }
176     }
177   }
178   return *this;
179 }
180 // Puts message in correct place
181 void
addMessage(int messageNumber,const CoinOneMessage & message)182 CoinMessages::addMessage(int messageNumber, const CoinOneMessage & message)
183 {
184   if (messageNumber>=numberMessages_) {
185     // should not happen but allow for it
186     CoinOneMessage ** temp = new CoinOneMessage * [messageNumber+1];
187     int i;
188     for (i=0;i<numberMessages_;i++)
189       temp[i] = message_[i];
190     for (;i<=messageNumber;i++)
191       temp[i] = NULL;
192     delete [] message_;
193     message_ = temp;
194   }
195   if (lengthMessages_>=0)
196     fromCompact();
197   delete message_[messageNumber];
198   message_[messageNumber]=new CoinOneMessage(message);
199 }
200 // Replaces messages (i.e. a different language)
201 void
replaceMessage(int messageNumber,const char * message)202 CoinMessages::replaceMessage(int messageNumber,
203 			     const char * message)
204 {
205   if (lengthMessages_>=0)
206     fromCompact();
207   assert(messageNumber<numberMessages_);
208   message_[messageNumber]->replaceMessage(message);
209 }
210 // Changes detail level for one message
211 void
setDetailMessage(int newLevel,int messageNumber)212 CoinMessages::setDetailMessage(int newLevel, int messageNumber)
213 {
214   int i;
215   // Last message is null (corresponds to DUMMY)
216   for (i=0;i<numberMessages_-1;i++) {
217     if (message_[i]->externalNumber()==messageNumber) {
218       message_[i]->setDetail(newLevel);
219       break;
220     }
221   }
222 }
223 // Changes detail level for several messages
224 void
setDetailMessages(int newLevel,int numberMessages,int * messageNumbers)225 CoinMessages::setDetailMessages(int newLevel, int numberMessages,
226 			       int * messageNumbers)
227 {
228   int i;
229   if (numberMessages<3&&messageNumbers) {
230     // do one by one
231     int j;
232     for (j=0;j<numberMessages;j++) {
233       int messageNumber = messageNumbers[j];
234       for (i=0;i<numberMessages_;i++) {
235 	if (message_[i]->externalNumber()==messageNumber) {
236 	  message_[i]->setDetail(newLevel);
237 	  break;
238 	}
239       }
240     }
241   } else if (numberMessages<10000&&messageNumbers) {
242     // do backward mapping
243     int backward[10000];
244     for (i=0;i<10000;i++)
245       backward[i]=-1;
246     for (i=0;i<numberMessages_;i++)
247       backward[message_[i]->externalNumber()]=i;
248     for (i=0;i<numberMessages;i++) {
249       int iback = backward[messageNumbers[i]];
250       if (iback>=0)
251 	message_[iback]->setDetail(newLevel);
252     }
253   } else {
254     // do all (except for dummy end)
255     for (i=0;i<numberMessages_-1;i++) {
256       message_[i]->setDetail(newLevel);
257     }
258   }
259 }
260 
261 // Changes detail level for all messages >= low and < high
262 void
setDetailMessages(int newLevel,int low,int high)263 CoinMessages::setDetailMessages(int newLevel, int low, int high)
264 {
265   // do all (except for dummy end) if in range
266   for (int i=0;i<numberMessages_-1;i++) {
267     int iNumber = message_[i]->externalNumber();
268     if (iNumber>=low&&iNumber<high)
269       message_[i]->setDetail(newLevel);
270   }
271 }
272 /*
273   Moves to compact format
274 
275   Compact format is an initial array of CoinOneMessage pointers, followed by a
276   bulk store that holds compressed CoinOneMessage objects, where the
277   message_ array is truncated to be just as large as necessary.
278 */
279 void
toCompact()280 CoinMessages::toCompact()
281 {
282   if (numberMessages_&&lengthMessages_<0) {
283     lengthMessages_=numberMessages_*CoinSizeofAsInt(CoinOneMessage *);
284     int i;
285     for (i=0;i<numberMessages_;i++) {
286       if (message_[i]) {
287 	int length = static_cast<int>(strlen(message_[i]->message()));
288 	length = static_cast<int>((message_[i]->message()+length+1)-
289 				      reinterpret_cast<char *> (message_[i]));
290 	assert (length<COIN_MESSAGE_HANDLER_MAX_BUFFER_SIZE);
291 	int leftOver = length %8;
292 	if (leftOver)
293 	  length += 8-leftOver;
294 	lengthMessages_+=length;
295       }
296     }
297     // space
298     char * temp = new char [lengthMessages_];
299     CoinOneMessage ** newMessage = reinterpret_cast<CoinOneMessage **> (temp);
300     temp += numberMessages_*CoinSizeofAsInt(CoinOneMessage *);
301     CoinOneMessage message;
302     //printf("new address %x(%x) - length %d\n",newMessage,temp,lengthMessages_);
303     lengthMessages_=numberMessages_*CoinSizeofAsInt(CoinOneMessage *);
304     for (i=0;i<numberMessages_;i++) {
305       if (message_[i]) {
306 	message = *message_[i];
307 	int length = static_cast<int>(strlen(message.message()));
308 	length = static_cast<int>((message.message()+length+1)-
309 				  reinterpret_cast<char *> (&message));
310 	assert (length<COIN_MESSAGE_HANDLER_MAX_BUFFER_SIZE);
311 	int leftOver = length %8;
312 	memcpy(temp,&message,length);
313 	newMessage[i]=reinterpret_cast<CoinOneMessage *> (temp);
314 	//printf("message %d at %x is %s\n",i,newMessage[i],newMessage[i]->message());
315 	if (leftOver)
316 	  length += 8-leftOver;
317 	temp += length;
318 	lengthMessages_+=length;
319       } else {
320 	// null message
321 	newMessage[i]=NULL;
322       }
323     }
324     for (i=0;i<numberMessages_;i++)
325       delete message_[i];
326     delete [] message_;
327     message_ = newMessage;
328   }
329 }
330 // Moves from compact format
331 void
fromCompact()332 CoinMessages::fromCompact()
333 {
334   if (numberMessages_&&lengthMessages_>=0) {
335     CoinOneMessage ** temp = new CoinOneMessage * [numberMessages_];
336     int i;
337     for (i=0;i<numberMessages_;i++) {
338       if (message_[i])
339 	temp[i]=new CoinOneMessage(*(message_[i]));
340       else
341 	temp[i]=NULL;
342     }
343     delete [] message_;
344     message_ = temp;
345   }
346   lengthMessages_=-1;
347 }
348 
349 // Clean, print message and check severity, return 0 normally
350 int
internalPrint()351 CoinMessageHandler::internalPrint()
352 {
353   int returnCode=0;
354   if (messageOut_>messageBuffer_) {
355     *messageOut_=0;
356     //take off trailing spaces and commas
357     messageOut_--;
358     while (messageOut_>=messageBuffer_) {
359       if (*messageOut_==' '||*messageOut_==',') {
360 	*messageOut_=0;
361 	messageOut_--;
362       } else {
363 	break;
364       }
365     }
366     // Now do print which can be overridden
367     returnCode=print();
368     // See what to do on error
369     checkSeverity();
370   }
371   return returnCode;
372 }
373 // Print message, return 0 normally
374 int
print()375 CoinMessageHandler::print()
376 {
377 #ifndef NDEBUG
378   fprintf(fp_,"%s\n",messageBuffer_);
379 #endif
380   return 0;
381 }
382 // Check severity
383 void
checkSeverity()384 CoinMessageHandler::checkSeverity()
385 {
386   if (currentMessage_.severity_=='S') {
387     fprintf(fp_,"Stopping due to previous errors.\n");
388     //Should do walkback
389     abort();
390   }
391 }
392 /* Amount of print out:
393    0 - none
394    1 - minimal
395    2 - normal low
396    3 - normal high
397    4 - verbose
398    above that 8,16,32 etc just for selective debug and are for
399    printf messages in code
400 */
401 void
setLogLevel(int value)402 CoinMessageHandler::setLogLevel(int value)
403 {
404   if (value>=-1)
405     logLevel_=value;
406 }
407 void
setLogLevel(int which,int value)408 CoinMessageHandler::setLogLevel(int which,int value)
409 {
410   if (which>=0&&which<COIN_NUM_LOG) {
411     if (value>=-1)
412       logLevels_[which]=value;
413   }
414 }
415 void
setPrecision(unsigned int new_precision)416 CoinMessageHandler::setPrecision(unsigned int new_precision) {
417 
418   char new_string[8] = {'%','.','8','f','\0','\0','\0','\0'};
419 
420   //we assume that the precision is smaller than one thousand
421   new_precision = std::min<unsigned int>(999,new_precision);
422   if (new_precision == 0)
423     new_precision = 1;
424   g_precision_ = new_precision ;
425   int idx = 2;
426   int base = 100;
427   bool print = false;
428   while (base > 0) {
429 
430     char c = static_cast<char>(new_precision / base);
431     new_precision = new_precision % base;
432     if (c != 0)
433       print = true;
434     if (print) {
435       new_string[idx] = static_cast<char>(c +  '0');
436       idx++;
437     }
438     base /= 10;
439   }
440   new_string[idx] = 'g';
441   strcpy(g_format_,new_string);
442 }
443 void
setPrefix(bool value)444 CoinMessageHandler::setPrefix(bool value)
445 {
446   if (value)
447     prefix_ = 255;
448   else
449     prefix_ =0;
450 }
451 bool
prefix() const452 CoinMessageHandler::prefix() const
453 {
454   return (prefix_!=0);
455 }
456 // Constructor
CoinMessageHandler()457 CoinMessageHandler::CoinMessageHandler() :
458   logLevel_(1),
459   prefix_(255),
460   currentMessage_(),
461   internalNumber_(0),
462   format_(NULL),
463   printStatus_(0),
464   highestNumber_(-1),
465   fp_(stdout)
466 {
467   const char* g_default = "%.8g";
468 
469   strcpy(g_format_,g_default);
470   g_precision_ = 8 ;
471 
472   for (int i=0;i<COIN_NUM_LOG;i++)
473     logLevels_[i]=-1000;
474   messageBuffer_[0]='\0';
475   messageOut_ = messageBuffer_;
476   source_="Unk";
477 }
478 // Constructor
CoinMessageHandler(FILE * fp)479 CoinMessageHandler::CoinMessageHandler(FILE * fp) :
480   logLevel_(1),
481   prefix_(255),
482   currentMessage_(),
483   internalNumber_(0),
484   format_(NULL),
485   printStatus_(0),
486   highestNumber_(-1),
487   fp_(fp)
488 {
489   const char* g_default = "%.8g";
490 
491   strcpy(g_format_,g_default);
492   g_precision_ = 8 ;
493 
494   for (int i=0;i<COIN_NUM_LOG;i++)
495     logLevels_[i]=-1000;
496   messageBuffer_[0]='\0';
497   messageOut_ = messageBuffer_;
498   source_="Unk";
499 }
500 /* Destructor */
~CoinMessageHandler()501 CoinMessageHandler::~CoinMessageHandler()
502 {
503 }
504 
505 void
gutsOfCopy(const CoinMessageHandler & rhs)506 CoinMessageHandler::gutsOfCopy(const CoinMessageHandler& rhs)
507 {
508   logLevel_=rhs.logLevel_;
509   prefix_ = rhs.prefix_;
510   if (rhs.format_ && *rhs.format_ == '\0')
511   { *rhs.format_ = '%' ;
512     currentMessage_=rhs.currentMessage_;
513     *rhs.format_ = '\0' ; }
514   else
515   { currentMessage_=rhs.currentMessage_; }
516   internalNumber_=rhs.internalNumber_;
517   int i;
518   for ( i=0;i<COIN_NUM_LOG;i++)
519     logLevels_[i]=rhs.logLevels_[i];
520   doubleValue_=rhs.doubleValue_;
521   longValue_=rhs.longValue_;
522   charValue_=rhs.charValue_;
523   stringValue_=rhs.stringValue_;
524   std::ptrdiff_t offset ;
525   if (rhs.format_)
526   { offset = rhs.format_ - rhs.currentMessage_.message();
527     format_ = currentMessage_.message()+offset; }
528   else
529   { format_ = NULL ; }
530   std::memcpy(messageBuffer_,rhs.messageBuffer_,
531 	      COIN_MESSAGE_HANDLER_MAX_BUFFER_SIZE);
532   offset = rhs.messageOut_-rhs.messageBuffer_;
533   messageOut_= messageBuffer_+offset;
534   printStatus_= rhs.printStatus_;
535   highestNumber_= rhs.highestNumber_;
536   fp_ = rhs.fp_;
537   source_ = rhs.source_;
538   strcpy(g_format_,rhs.g_format_);
539   g_precision_ = rhs.g_precision_ ;
540 }
541 /* The copy constructor */
CoinMessageHandler(const CoinMessageHandler & rhs)542 CoinMessageHandler::CoinMessageHandler(const CoinMessageHandler& rhs)
543 {
544   gutsOfCopy(rhs);
545 }
546 /* assignment operator. */
547 CoinMessageHandler &
operator =(const CoinMessageHandler & rhs)548 CoinMessageHandler::operator=(const CoinMessageHandler& rhs)
549 {
550   if (this != &rhs) {
551     gutsOfCopy(rhs);
552   }
553   return *this;
554 }
555 // Clone
556 CoinMessageHandler *
clone() const557 CoinMessageHandler::clone() const
558 {
559   return new CoinMessageHandler(*this);
560 }
561 // Start a message
562 CoinMessageHandler &
message(int messageNumber,const CoinMessages & normalMessage)563 CoinMessageHandler::message(int messageNumber,
564 			   const CoinMessages &normalMessage)
565 {
566   if (messageOut_!=messageBuffer_) {
567     // put out last message
568     internalPrint();
569   }
570   internalNumber_=messageNumber;
571   currentMessage_= *(normalMessage.message_[messageNumber]);
572   source_ = normalMessage.source_;
573   format_ = currentMessage_.message_;
574   messageBuffer_[0]='\0';
575   messageOut_=messageBuffer_;
576   highestNumber_ = CoinMax(highestNumber_,currentMessage_.externalNumber_);
577   // do we print
578   int detail = currentMessage_.detail_;
579   printStatus_=0;
580   if (logLevels_[0]==-1000) {
581     if (detail>=8&&logLevel_>=0) {
582       // bit setting - debug
583       if ((detail&logLevel_)==0)
584 	printStatus_ = 3;
585     } else if (logLevel_<detail) {
586       printStatus_ = 3;
587     }
588   } else if (logLevels_[normalMessage.class_]<detail) {
589     printStatus_ = 3;
590   }
591   if (!printStatus_) {
592     if (prefix_) {
593       sprintf(messageOut_,"%s%4.4d%c ",source_.c_str(),
594 	      currentMessage_.externalNumber_,
595 	      currentMessage_.severity_);
596       messageOut_ += strlen(messageOut_);
597     }
598     format_ = nextPerCent(format_,true);
599   }
600   return *this;
601 }
602 /* The following is to help existing codes interface
603    Starts message giving number and complete text
604 */
605 CoinMessageHandler &
message(int externalNumber,const char * source,const char * msg,char severity)606 CoinMessageHandler::message(int externalNumber,const char * source,
607 			   const char * msg, char severity)
608 {
609   if (messageOut_!=messageBuffer_) {
610     // put out last message
611     internalPrint();
612   }
613   internalNumber_=externalNumber;
614   currentMessage_= CoinOneMessage();
615   currentMessage_.setExternalNumber(externalNumber);
616   source_ = source;
617   // mark so will not update buffer
618   printStatus_=2;
619   highestNumber_ = CoinMax(highestNumber_,externalNumber);
620   // If we get here we always print
621   if (prefix_) {
622     sprintf(messageOut_,"%s%4.4d%c ",source_.c_str(),
623 	    externalNumber,
624 	    severity);
625   }
626   strcat(messageBuffer_,msg);
627   messageOut_=messageBuffer_+strlen(messageBuffer_);
628   return *this;
629 }
630   /* Allows for skipping printing of part of message,
631       but putting in data */
632   CoinMessageHandler &
printing(bool onOff)633 CoinMessageHandler::printing(bool onOff)
634 {
635   // has no effect if skipping or whole message in
636   if (printStatus_<2) {
637     assert(format_[1]=='?');
638     *format_ = '%' ;
639     if (onOff)
640       printStatus_=0;
641     else
642       printStatus_=1;
643     format_ = nextPerCent(format_+2,true);
644   }
645   return *this;
646 }
647 /* Stop (and print)
648 */
649 int
finish()650 CoinMessageHandler::finish()
651 {
652   if (messageOut_!=messageBuffer_) {
653     // put out last message
654     internalPrint();
655   }
656   internalNumber_=-1;
657   format_ = NULL;
658   messageBuffer_[0]='\0';
659   messageOut_=messageBuffer_;
660   printStatus_=0;
661   doubleValue_.clear();
662   longValue_.clear();
663   charValue_.clear();
664   stringValue_.clear();
665   return 0;
666 }
667 /* Gets position of next field in format
668    If we're scanning the initial portion of the string (prior to the first
669    `%' code) the prefix will be copied to the output buffer. Normally, the
670    text from the current position up to and including a % code is is processed
671    by the relevant operator<< method.
672 */
673 char *
nextPerCent(char * start,const bool initial)674 CoinMessageHandler::nextPerCent(char * start , const bool initial)
675 {
676   if (start) {
677     bool foundNext=false;
678     while (!foundNext) {
679       char * nextPerCent = strchr(start,'%');
680       if (nextPerCent) {
681 	if (initial&&!printStatus_) {
682 	  int numberToCopy=static_cast<int>(nextPerCent-start);
683 	  strncpy(messageOut_,start,numberToCopy);
684 	  messageOut_+=numberToCopy;
685 	}
686 	// %? is skipped over as it is just a separator
687 	if (nextPerCent[1]!='?') {
688 	  start=nextPerCent;
689 	  if (start[1]!='%') {
690 	    foundNext=true;
691 	    if (!initial)
692 	      *start='\0'; //zap
693 	  } else {
694 	    start+=2;
695 	    if (initial) {
696 	      *messageOut_='%';
697 	      messageOut_++;
698 	    }
699 	  }
700 	} else {
701 	  foundNext=true;
702 	  // skip to % and zap
703 	  start=nextPerCent;
704 	  *start='\0';
705 	}
706       } else {
707         if (initial&&!printStatus_) {
708           strcpy(messageOut_,start);
709           messageOut_+=strlen(messageOut_);
710         }
711         start=0;
712         foundNext=true;
713       }
714     }
715   }
716   return start;
717 }
718 // Adds into message
719 CoinMessageHandler &
operator <<(int intvalue)720 CoinMessageHandler::operator<< (int intvalue)
721 {
722   if (printStatus_==3)
723     return *this; // not doing this message
724   longValue_.push_back(intvalue);
725   if (printStatus_<2) {
726     if (format_) {
727       //format is at % (but may be changed to null)
728       *format_='%';
729       char * next = nextPerCent(format_+1);
730       // could check
731       if (!printStatus_) {
732 	sprintf(messageOut_,format_,intvalue);
733 	messageOut_+=strlen(messageOut_);
734       }
735       format_=next;
736     } else {
737       sprintf(messageOut_," %d",intvalue);
738       messageOut_+=strlen(messageOut_);
739     }
740   }
741   return *this;
742 }
743 CoinMessageHandler &
operator <<(double doublevalue)744 CoinMessageHandler::operator<< (double doublevalue)
745 {
746   if (printStatus_==3)
747     return *this; // not doing this message
748   doubleValue_.push_back(doublevalue);
749 
750   if (printStatus_<2) {
751     if (format_) {
752       //format is at \0 (but changed to %)
753       *format_='%';
754       char * next = nextPerCent(format_+1);
755       // could check
756       if (!printStatus_) {
757 	if (format_[1] == '.' && format_[2] >= '0' && format_[2] <= '9') {
758 	  // an explicitly specified precision currently overrides the
759 	  // precision of the message handler
760 	  sprintf(messageOut_,format_,doublevalue);
761 	}
762 	else {
763 	  sprintf(messageOut_,g_format_,doublevalue);
764 	  if (next != format_+2) {
765 	    messageOut_+=strlen(messageOut_);
766 	    sprintf(messageOut_,format_+2);
767 	  }
768 	}
769 	messageOut_+=strlen(messageOut_);
770       }
771       format_=next;
772     } else {
773       sprintf(messageOut_," ");
774       messageOut_ += 1;
775       sprintf(messageOut_,g_format_,doublevalue);
776       messageOut_+=strlen(messageOut_);
777     }
778   }
779   return *this;
780 }
781 #if COIN_BIG_INDEX==1
782 CoinMessageHandler &
operator <<(long longvalue)783 CoinMessageHandler::operator<< (long longvalue)
784 {
785   if (printStatus_==3)
786     return *this; // not doing this message
787   longValue_.push_back(longvalue);
788   if (printStatus_<2) {
789     if (format_) {
790       //format is at % (but may be changed to null)
791       *format_='%';
792       char * next = nextPerCent(format_+1);
793       // could check
794       if (!printStatus_) {
795 	sprintf(messageOut_,format_,longvalue);
796 	messageOut_+=strlen(messageOut_);
797       }
798       format_=next;
799     } else {
800       sprintf(messageOut_," %ld",longvalue);
801       messageOut_+=strlen(messageOut_);
802     }
803   }
804   return *this;
805 }
806 #endif
807 #if COIN_BIG_INDEX==2
808 CoinMessageHandler &
operator <<(long long longvalue)809 CoinMessageHandler::operator<< (long long longvalue)
810 {
811   if (printStatus_==3)
812     return *this; // not doing this message
813   longValue_.push_back(longvalue);
814   if (printStatus_<2) {
815     if (format_) {
816       //format is at % (but may be changed to null)
817       *format_='%';
818       char * next = nextPerCent(format_+1);
819       // could check
820       if (!printStatus_) {
821 	sprintf(messageOut_,format_,longvalue);
822 	messageOut_+=strlen(messageOut_);
823       }
824       format_=next;
825     } else {
826       sprintf(messageOut_," %ld",longvalue);
827       messageOut_+=strlen(messageOut_);
828     }
829   }
830   return *this;
831 }
832 #endif
833 CoinMessageHandler &
operator <<(const std::string & stringvalue)834 CoinMessageHandler::operator<< (const std::string& stringvalue)
835 {
836   if (printStatus_==3)
837     return *this; // not doing this message
838   stringValue_.push_back(stringvalue);
839   if (printStatus_<2) {
840     if (format_) {
841       //format is at % (but changed to 0)
842       *format_='%';
843       char * next = nextPerCent(format_+1);
844       // could check
845       if (!printStatus_) {
846 	sprintf(messageOut_,format_,stringvalue.c_str());
847 	messageOut_+=strlen(messageOut_);
848       }
849       format_=next;
850     } else {
851       sprintf(messageOut_," %s",stringvalue.c_str());
852       messageOut_+=strlen(messageOut_);
853     }
854   }
855   return *this;
856 }
857 CoinMessageHandler &
operator <<(char charvalue)858 CoinMessageHandler::operator<< (char charvalue)
859 {
860   if (printStatus_==3)
861     return *this; // not doing this message
862   charValue_.push_back(charvalue);
863   if (printStatus_<2) {
864     if (format_) {
865       //format is at % (but changed to 0)
866       *format_='%';
867       char * next = nextPerCent(format_+1);
868       // could check
869       if (!printStatus_) {
870 	sprintf(messageOut_,format_,charvalue);
871 	messageOut_+=strlen(messageOut_);
872       }
873       format_=next;
874     } else {
875       sprintf(messageOut_," %c",charvalue);
876       messageOut_+=strlen(messageOut_);
877     }
878   }
879   return *this;
880 }
881 CoinMessageHandler &
operator <<(const char * stringvalue)882 CoinMessageHandler::operator<< (const char *stringvalue)
883 {
884   if (printStatus_==3)
885     return *this; // not doing this message
886   stringValue_.push_back(stringvalue);
887   if (printStatus_<2) {
888     if (format_) {
889       //format is at % (but changed to 0)
890       *format_='%';
891       char * next = nextPerCent(format_+1);
892       // could check
893       if (!printStatus_) {
894 	sprintf(messageOut_,format_,stringvalue);
895 	messageOut_+=strlen(messageOut_);
896       }
897       format_=next;
898     } else {
899       sprintf(messageOut_," %s",stringvalue);
900       messageOut_+=strlen(messageOut_);
901     }
902   }
903   return *this;
904 }
905 CoinMessageHandler &
operator <<(CoinMessageMarker marker)906 CoinMessageHandler::operator<< (CoinMessageMarker marker)
907 {
908   if (printStatus_!=3) {
909     switch (marker) {
910     case CoinMessageEol:
911       finish();
912       break;
913     case CoinMessageNewline:
914       strcat(messageOut_,"\n");
915       messageOut_++;
916       break;
917     }
918   } else {
919     // skipping - tidy up
920     format_ = NULL;
921   }
922   return *this;
923 }
924 
925 // returns current
926 CoinMessageHandler &
message()927 CoinMessageHandler::message()
928 {
929   return * this;
930 }
931