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