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