// Copyright (C) 2002, International Business Machines
// Corporation and others. All Rights Reserved.
#include "CoinFinite.hpp"
#include "CoinMessageHandler.hpp"
#include "CoinHelperFunctions.hpp"
#include <cassert>
#include <map>
/* Default constructor. */
CoinOneMessage::CoinOneMessage()
{
externalNumber_=-1;
message_[0]='\0';
severity_='I';
detail_=0;
}
/* Destructor */
CoinOneMessage::~CoinOneMessage()
{
}
/* The copy constructor */
CoinOneMessage::CoinOneMessage(const CoinOneMessage & rhs)
{
externalNumber_=rhs.externalNumber_;
strcpy(message_,rhs.message_);
severity_=rhs.severity_;
detail_=rhs.detail_;
}
/* assignment operator. */
CoinOneMessage&
CoinOneMessage::operator=(const CoinOneMessage & rhs)
{
if (this != &rhs) {
externalNumber_=rhs.externalNumber_;
strcpy(message_,rhs.message_);
severity_=rhs.severity_;
detail_=rhs.detail_;
}
return *this;
}
/* Normal constructor */
CoinOneMessage::CoinOneMessage(int externalNumber, char detail,
const char * message)
{
externalNumber_=externalNumber;
strcpy(message_,message);
if (externalNumber<3000)
severity_='I';
else if (externalNumber<6000)
severity_='W';
else if (externalNumber<9000)
severity_='E';
else
severity_='S';
detail_=detail;
}
// Replaces messages (i.e. a different language)
void
CoinOneMessage::replaceMessage( const char * message)
{
strcpy(message_,message);
}
/* Constructor with number of messages. */
CoinMessages::CoinMessages(int numberMessages)
{
numberMessages_=numberMessages;
language_=us_en;
strcpy(source_,"Unk");
class_=1;
lengthMessages_=-1;
if (numberMessages_) {
message_ = new CoinOneMessage * [numberMessages_];
int i;
for (i=0;i<numberMessages_;i++)
message_[i]=NULL;
} else {
message_=NULL;
}
}
/* Destructor */
CoinMessages::~CoinMessages()
{
int i;
if (lengthMessages_<0) {
for (i=0;i<numberMessages_;i++)
delete message_[i];
}
delete [] message_;
}
/* The copy constructor */
CoinMessages::CoinMessages(const CoinMessages & rhs)
{
numberMessages_=rhs.numberMessages_;
language_=rhs.language_;
strcpy(source_,rhs.source_);
class_=rhs.class_;
lengthMessages_=rhs.lengthMessages_;
if (lengthMessages_<0) {
if (numberMessages_) {
message_ = new CoinOneMessage * [numberMessages_];
int i;
for (i=0;i<numberMessages_;i++)
if (rhs.message_[i])
message_[i]=new CoinOneMessage(*(rhs.message_[i]));
else
message_[i] = NULL;
} else {
message_=NULL;
}
} else {
char * temp = CoinCopyOfArray((char *) rhs.message_,lengthMessages_);
message_ = (CoinOneMessage **) temp;
long int offset = temp - (char *) rhs.message_;
int i;
//printf("new address %x(%x), rhs %x - length %d\n",message_,temp,rhs.message_,lengthMessages_);
for (i=0;i<numberMessages_;i++) {
if (message_[i]) {
char * newAddress = ((char *) message_[i]) + offset;
assert (newAddress-temp<lengthMessages_);
message_[i] = (CoinOneMessage *) newAddress;
//printf("message %d at %x is %s\n",i,message_[i],message_[i]->message());
//printf("message %d at %x wass %s\n",i,rhs.message_[i],rhs.message_[i]->message());
}
}
}
}
/* assignment operator. */
CoinMessages&
CoinMessages::operator=(const CoinMessages & rhs)
{
if (this != &rhs) {
language_=rhs.language_;
strcpy(source_,rhs.source_);
class_=rhs.class_;
if (lengthMessages_<0) {
int i;
for (i=0;i<numberMessages_;i++)
delete message_[i];
}
delete [] message_;
numberMessages_=rhs.numberMessages_;
lengthMessages_=rhs.lengthMessages_;
if (lengthMessages_<0) {
if (numberMessages_) {
message_ = new CoinOneMessage * [numberMessages_];
int i;
for (i=0;i<numberMessages_;i++)
if (rhs.message_[i])
message_[i]=new CoinOneMessage(*(rhs.message_[i]));
else
message_[i] = NULL;
} else {
message_=NULL;
}
} else {
char * temp = CoinCopyOfArray((char *) rhs.message_,lengthMessages_);
message_ = (CoinOneMessage **) temp;
long int offset = temp - (char *) rhs.message_;
int i;
//printf("new address %x(%x), rhs %x - length %d\n",message_,temp,rhs.message_,lengthMessages_);
for (i=0;i<numberMessages_;i++) {
if (message_[i]) {
char * newAddress = ((char *) message_[i]) + offset;
assert (newAddress-temp<lengthMessages_);
message_[i] = (CoinOneMessage *) newAddress;
//printf("message %d at %x is %s\n",i,message_[i],message_[i]->message());
//printf("message %d at %x wass %s\n",i,rhs.message_[i],rhs.message_[i]->message());
}
}
}
}
return *this;
}
// Puts message in correct place
void
CoinMessages::addMessage(int messageNumber, const CoinOneMessage & message)
{
if (messageNumber>=numberMessages_) {
// should not happen but allow for it
CoinOneMessage ** temp = new CoinOneMessage * [messageNumber+1];
int i;
for (i=0;i<numberMessages_;i++)
temp[i] = message_[i];
for (;i<=messageNumber;i++)
temp[i] = NULL;
delete [] message_;
message_ = temp;
}
if (lengthMessages_>=0)
fromCompact();
delete message_[messageNumber];
message_[messageNumber]=new CoinOneMessage(message);
}
// Replaces messages (i.e. a different language)
void
CoinMessages::replaceMessage(int messageNumber,
const char * message)
{
if (lengthMessages_>=0)
fromCompact();
assert(messageNumber<numberMessages_);
message_[messageNumber]->replaceMessage(message);
}
// Changes detail level for one message
void
CoinMessages::setDetailMessage(int newLevel, int messageNumber)
{
int i;
// Last message is null (corresponds to DUMMY)
for (i=0;i<numberMessages_-1;i++) {
if (message_[i]->externalNumber()==messageNumber) {
message_[i]->setDetail(newLevel);
break;
}
}
}
// Changes detail level for several messages
void
CoinMessages::setDetailMessages(int newLevel, int numberMessages,
int * messageNumbers)
{
int i;
if (numberMessages<3&&messageNumbers) {
// do one by one
int j;
for (j=0;j<numberMessages;j++) {
int messageNumber = messageNumbers[j];
for (i=0;i<numberMessages_;i++) {
if (message_[i]->externalNumber()==messageNumber) {
message_[i]->setDetail(newLevel);
break;
}
}
}
} else if (numberMessages<10000&&messageNumbers) {
// do backward mapping
int backward[10000];
for (i=0;i<10000;i++)
backward[i]=-1;
for (i=0;i<numberMessages_;i++)
backward[message_[i]->externalNumber()]=i;
for (i=0;i<numberMessages;i++) {
int iback = backward[messageNumbers[i]];
if (iback>=0)
message_[iback]->setDetail(newLevel);
}
} else {
// do all (except for dummy end)
for (i=0;i<numberMessages_-1;i++) {
message_[i]->setDetail(newLevel);
}
}
}
// Changes detail level for all messages >= low and < high
void
CoinMessages::setDetailMessages(int newLevel, int low, int high)
{
// do all (except for dummy end) if in range
for (int i=0;i<numberMessages_-1;i++) {
int iNumber = message_[i]->externalNumber();
if (iNumber>=low&&iNumber<high)
message_[i]->setDetail(newLevel);
}
}
/*
Moves to compact format
Compact format is an initial array of CoinOneMessage pointers, followed by a
bulk store that holds compressed CoinOneMessage objects, where the
message_ array is truncated to be just as large as necessary.
*/
void
CoinMessages::toCompact()
{
if (numberMessages_&&lengthMessages_<0) {
lengthMessages_=numberMessages_*sizeof(CoinOneMessage *);
int i;
for (i=0;i<numberMessages_;i++) {
if (message_[i]) {
int length = strlen(message_[i]->message());
length = (message_[i]->message()+length+1)-
(char *) message_[i];
assert (length<1000);
int leftOver = length %8;
if (leftOver)
length += 8-leftOver;
lengthMessages_+=length;
}
}
// space
char * temp = new char [lengthMessages_];
CoinOneMessage ** newMessage = (CoinOneMessage **) temp;
temp += numberMessages_*sizeof(CoinOneMessage *);
CoinOneMessage message;
//printf("new address %x(%x) - length %d\n",newMessage,temp,lengthMessages_);
lengthMessages_=numberMessages_*sizeof(CoinOneMessage *);
for (i=0;i<numberMessages_;i++) {
if (message_[i]) {
message = *message_[i];
int length = strlen(message.message());
length = (message.message()+length+1)-
(char *) (&message);
assert (length<1000);
int leftOver = length %8;
memcpy(temp,&message,length);
newMessage[i]=(CoinOneMessage *) temp;
//printf("message %d at %x is %s\n",i,newMessage[i],newMessage[i]->message());
if (leftOver)
length += 8-leftOver;
temp += length;
lengthMessages_+=length;
} else {
// null message
newMessage[i]=NULL;
}
}
for (i=0;i<numberMessages_;i++)
delete message_[i];
delete [] message_;
message_ = newMessage;
}
}
// Moves from compact format
void
CoinMessages::fromCompact()
{
if (numberMessages_&&lengthMessages_>=0) {
CoinOneMessage ** temp = new CoinOneMessage * [numberMessages_];
int i;
for (i=0;i<numberMessages_;i++) {
if (message_[i])
temp[i]=new CoinOneMessage(*(message_[i]));
else
temp[i]=NULL;
}
delete [] message_;
message_ = temp;
}
lengthMessages_=-1;
}
// Clean, print message and check severity, return 0 normally
int
CoinMessageHandler::internalPrint()
{
int returnCode=0;
if (messageOut_>messageBuffer_) {
*messageOut_=0;
//take off trailing spaces and commas
messageOut_--;
while (messageOut_>=messageBuffer_) {
if (*messageOut_==' '||*messageOut_==',') {
*messageOut_=0;
messageOut_--;
} else {
break;
}
}
// Now do print which can be overridden
returnCode=print();
// See what to do on error
checkSeverity();
}
return returnCode;
}
// Print message, return 0 normally
int
CoinMessageHandler::print()
{
fprintf(fp_,"%s\n",messageBuffer_);
return 0;
}
// Check severity
void
CoinMessageHandler::checkSeverity()
{
if (currentMessage_.severity_=='S') {
fprintf(fp_,"Stopping due to previous errors.\n");
//Should do walkback
abort();
}
}
/* Amount of print out:
0 - none
1 - minimal
2 - normal low
3 - normal high
4 - verbose
above that 8,16,32 etc just for selective debug and are for
printf messages in code
*/
void
CoinMessageHandler::setLogLevel(int value)
{
if (value>=-1)
logLevel_=value;
}
void
CoinMessageHandler::setLogLevel(int which,int value)
{
if (which>=0&&which<COIN_NUM_LOG) {
if (value>=-1)
logLevel_=value;
}
}
void
CoinMessageHandler::setPrefix(bool value)
{
if (value)
prefix_ = 255;
else
prefix_ =0;
}
bool
CoinMessageHandler::prefix() const
{
return (prefix_!=0);
}
// Constructor
CoinMessageHandler::CoinMessageHandler() :
logLevel_(1),
prefix_(255),
currentMessage_(),
internalNumber_(0),
format_(NULL),
printStatus_(0),
highestNumber_(-1),
fp_(stdout)
{
for (int i=0;i<COIN_NUM_LOG;i++)
logLevels_[i]=1;
messageBuffer_[0]='\0';
messageOut_ = messageBuffer_;
source_="Unk";
}
// Constructor
CoinMessageHandler::CoinMessageHandler(FILE * fp) :
logLevel_(1),
prefix_(255),
currentMessage_(),
internalNumber_(0),
format_(NULL),
printStatus_(0),
highestNumber_(-1),
fp_(fp)
{
for (int i=0;i<COIN_NUM_LOG;i++)
logLevels_[i]=1;
messageBuffer_[0]='\0';
messageOut_ = messageBuffer_;
source_="Unk";
}
/* Destructor */
CoinMessageHandler::~CoinMessageHandler()
{
}
void
CoinMessageHandler::gutsOfCopy(const CoinMessageHandler& rhs)
{
logLevel_=rhs.logLevel_;
prefix_ = rhs.prefix_;
if (rhs.format_ && *rhs.format_ == '\0')
{ *rhs.format_ = '%' ;
currentMessage_=rhs.currentMessage_;
*rhs.format_ = '\0' ; }
else
{ currentMessage_=rhs.currentMessage_; }
internalNumber_=rhs.internalNumber_;
int i;
for ( i=0;i<COIN_NUM_LOG;i++)
logLevels_[i]=rhs.logLevels_[i];
doubleValue_=rhs.doubleValue_;
longValue_=rhs.longValue_;
charValue_=rhs.charValue_;
stringValue_=rhs.stringValue_;
long int offset ;
if (rhs.format_)
{ offset = rhs.format_ - rhs.currentMessage_.message();
format_ = currentMessage_.message()+offset; }
else
{ format_ = NULL ; }
strcpy(messageBuffer_,rhs.messageBuffer_);
offset = rhs.messageOut_-rhs.messageBuffer_;
messageOut_= messageBuffer_+offset;
printStatus_= rhs.printStatus_;
highestNumber_= rhs.highestNumber_;
fp_ = rhs.fp_;
source_ = rhs.source_;
}
/* The copy constructor */
CoinMessageHandler::CoinMessageHandler(const CoinMessageHandler& rhs)
{
gutsOfCopy(rhs);
}
/* assignment operator. */
CoinMessageHandler &
CoinMessageHandler::operator=(const CoinMessageHandler& rhs)
{
if (this != &rhs) {
gutsOfCopy(rhs);
}
return *this;
}
// Clone
CoinMessageHandler *
CoinMessageHandler::clone() const
{
return new CoinMessageHandler(*this);
}
// Start a message
CoinMessageHandler &
CoinMessageHandler::message(int messageNumber,
const CoinMessages &normalMessage)
{
if (messageOut_!=messageBuffer_) {
// put out last message
internalPrint();
}
internalNumber_=messageNumber;
currentMessage_= *(normalMessage.message_[messageNumber]);
source_ = normalMessage.source_;
format_ = currentMessage_.message_;
messageBuffer_[0]='\0';
messageOut_=messageBuffer_;
highestNumber_ = CoinMax(highestNumber_,currentMessage_.externalNumber_);
// do we print
int detail = currentMessage_.detail_;
printStatus_=0;
if (detail>=8&&logLevel_>=0) {
// bit setting - debug
if ((detail&logLevel_)==0)
printStatus_ = 3;
} else if (logLevel_<detail) {
printStatus_ = 3;
}
if (!printStatus_) {
if (prefix_) {
sprintf(messageOut_,"%s%4.4d%c ",source_.c_str(),
currentMessage_.externalNumber_,
currentMessage_.severity_);
messageOut_ += strlen(messageOut_);
}
format_ = nextPerCent(format_,true);
}
return *this;
}
/* The following is to help existing codes interface
Starts message giving number and complete text
*/
CoinMessageHandler &
CoinMessageHandler::message(int externalNumber,const char * source,
const char * msg, char severity)
{
if (messageOut_!=messageBuffer_) {
// put out last message
internalPrint();
}
internalNumber_=externalNumber;
currentMessage_= CoinOneMessage();
currentMessage_.setExternalNumber(externalNumber);
source_ = source;
// mark so will not update buffer
printStatus_=2;
highestNumber_ = CoinMax(highestNumber_,externalNumber);
// If we get here we always print
if (prefix_) {
sprintf(messageOut_,"%s%4.4d%c ",source_.c_str(),
externalNumber,
severity);
}
strcat(messageBuffer_,msg);
messageOut_=messageBuffer_+strlen(messageBuffer_);
return *this;
}
/* Allows for skipping printing of part of message,
but putting in data */
CoinMessageHandler &
CoinMessageHandler::printing(bool onOff)
{
// has no effect if skipping or whole message in
if (printStatus_<2) {
assert(format_[1]=='?');
*format_ = '%' ;
if (onOff)
printStatus_=0;
else
printStatus_=1;
format_ = nextPerCent(format_+2,true);
}
return *this;
}
/* Stop (and print)
*/
int
CoinMessageHandler::finish()
{
if (messageOut_!=messageBuffer_) {
// put out last message
internalPrint();
}
internalNumber_=-1;
format_ = NULL;
messageBuffer_[0]='\0';
messageOut_=messageBuffer_;
printStatus_=true;
return 0;
}
/* Gets position of next field in format
If we're scanning the initial portion of the string (prior to the first
`%' code) the prefix will be copied to the output buffer. Normally, the
text from the current position up to and including a % code is is processed
by the relevant operator<< method.
*/
char *
CoinMessageHandler::nextPerCent(char * start , const bool initial)
{
if (start) {
bool foundNext=false;
while (!foundNext) {
char * nextPerCent = strchr(start,'%');
if (nextPerCent) {
if (initial&&!printStatus_) {
int numberToCopy=nextPerCent-start;
strncpy(messageOut_,start,numberToCopy);
messageOut_+=numberToCopy;
}
// %? is skipped over as it is just a separator
if (nextPerCent[1]!='?') {
start=nextPerCent;
if (start[1]!='%') {
foundNext=true;
if (!initial)
*start='\0'; //zap
} else {
start+=2;
if (initial) {
*messageOut_='%';
messageOut_++;
}
}
} else {
foundNext=true;
// skip to % and zap
start=nextPerCent;
*start='\0';
}
} else {
if (initial&&!printStatus_) {
strcpy(messageOut_,start);
messageOut_+=strlen(messageOut_);
}
start=0;
foundNext=true;
}
}
}
return start;
}
// Adds into message
CoinMessageHandler &
CoinMessageHandler::operator<< (int intvalue)
{
if (printStatus_==3)
return *this; // not doing this message
longValue_.push_back(intvalue);
if (printStatus_<2) {
if (format_) {
//format is at % (but may be changed to null)
*format_='%';
char * next = nextPerCent(format_+1);
// could check
if (!printStatus_) {
sprintf(messageOut_,format_,intvalue);
messageOut_+=strlen(messageOut_);
}
format_=next;
} else {
sprintf(messageOut_," %d",intvalue);
messageOut_+=strlen(messageOut_);
}
}
return *this;
}
CoinMessageHandler &
CoinMessageHandler::operator<< (double doublevalue)
{
if (printStatus_==3)
return *this; // not doing this message
doubleValue_.push_back(doublevalue);
if (printStatus_<2) {
if (format_) {
//format is at % (but changed to 0)
*format_='%';
char * next = nextPerCent(format_+1);
// could check
if (!printStatus_) {
sprintf(messageOut_,format_,doublevalue);
messageOut_+=strlen(messageOut_);
}
format_=next;
} else {
sprintf(messageOut_," %g",doublevalue);
messageOut_+=strlen(messageOut_);
}
}
return *this;
}
#if COIN_BIG_INDEX==1
CoinMessageHandler &
CoinMessageHandler::operator<< (long longvalue)
{
if (printStatus_==3)
return *this; // not doing this message
longValue_.push_back(longvalue);
if (printStatus_<2) {
if (format_) {
//format is at % (but may be changed to null)
*format_='%';
char * next = nextPerCent(format_+1);
// could check
if (!printStatus_) {
sprintf(messageOut_,format_,longvalue);
messageOut_+=strlen(messageOut_);
}
format_=next;
} else {
sprintf(messageOut_," %ld",longvalue);
messageOut_+=strlen(messageOut_);
}
}
return *this;
}
#endif
#if COIN_BIG_INDEX==2
CoinMessageHandler &
CoinMessageHandler::operator<< (long long longvalue)
{
if (printStatus_==3)
return *this; // not doing this message
longValue_.push_back(longvalue);
if (printStatus_<2) {
if (format_) {
//format is at % (but may be changed to null)
*format_='%';
char * next = nextPerCent(format_+1);
// could check
if (!printStatus_) {
sprintf(messageOut_,format_,longvalue);
messageOut_+=strlen(messageOut_);
}
format_=next;
} else {
sprintf(messageOut_," %ld",longvalue);
messageOut_+=strlen(messageOut_);
}
}
return *this;
}
#endif
CoinMessageHandler &
CoinMessageHandler::operator<< (const std::string& stringvalue)
{
if (printStatus_==3)
return *this; // not doing this message
stringValue_.push_back(stringvalue);
if (printStatus_<2) {
if (format_) {
//format is at % (but changed to 0)
*format_='%';
char * next = nextPerCent(format_+1);
// could check
if (!printStatus_) {
sprintf(messageOut_,format_,stringvalue.c_str());
messageOut_+=strlen(messageOut_);
}
format_=next;
} else {
sprintf(messageOut_," %s",stringvalue.c_str());
messageOut_+=strlen(messageOut_);
}
}
return *this;
}
CoinMessageHandler &
CoinMessageHandler::operator<< (char charvalue)
{
if (printStatus_==3)
return *this; // not doing this message
longValue_.push_back(charvalue);
if (printStatus_<2) {
if (format_) {
//format is at % (but changed to 0)
*format_='%';
char * next = nextPerCent(format_+1);
// could check
if (!printStatus_) {
sprintf(messageOut_,format_,charvalue);
messageOut_+=strlen(messageOut_);
}
format_=next;
} else {
sprintf(messageOut_," %c",charvalue);
messageOut_+=strlen(messageOut_);
}
}
return *this;
}
CoinMessageHandler &
CoinMessageHandler::operator<< (const char *stringvalue)
{
if (printStatus_==3)
return *this; // not doing this message
stringValue_.push_back(stringvalue);
if (printStatus_<2) {
if (format_) {
//format is at % (but changed to 0)
*format_='%';
char * next = nextPerCent(format_+1);
// could check
if (!printStatus_) {
sprintf(messageOut_,format_,stringvalue);
messageOut_+=strlen(messageOut_);
}
format_=next;
} else {
sprintf(messageOut_," %s",stringvalue);
messageOut_+=strlen(messageOut_);
}
}
return *this;
}
CoinMessageHandler &
CoinMessageHandler::operator<< (CoinMessageMarker marker)
{
if (printStatus_!=3) {
switch (marker) {
case CoinMessageEol:
finish();
break;
case CoinMessageNewline:
strcat(messageOut_,"\n");
messageOut_++;
break;
}
} else {
// skipping - tidy up
format_ = NULL;
}
return *this;
}
// returns current
CoinMessageHandler &
CoinMessageHandler::message()
{
return * this;
}
syntax highlighted by Code2HTML, v. 0.9.1