291 lines
10 KiB
C++
291 lines
10 KiB
C++
//
|
|
// The developer of the original code and/or files is Tripwire, Inc.
|
|
// Portions created by Tripwire, Inc. are copyright (C) 2000-2018 Tripwire,
|
|
// Inc. Tripwire is a registered trademark of Tripwire, Inc. All rights
|
|
// reserved.
|
|
//
|
|
// This program is free software. The contents of this file are subject
|
|
// to the terms of the GNU General Public License as published by the
|
|
// Free Software Foundation; either version 2 of the License, or (at your
|
|
// option) any later version. You may redistribute it and/or modify it
|
|
// only in compliance with the GNU General Public License.
|
|
//
|
|
// This program is distributed in the hope that it will be useful.
|
|
// However, this program is distributed AS-IS WITHOUT ANY
|
|
// WARRANTY; INCLUDING THE IMPLIED WARRANTY OF MERCHANTABILITY OR FITNESS
|
|
// FOR A PARTICULAR PURPOSE. Please see the GNU General Public License
|
|
// for more details.
|
|
//
|
|
// You should have received a copy of the GNU General Public License
|
|
// along with this program; if not, write to the Free Software
|
|
// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
|
|
// USA.
|
|
//
|
|
// Nothing in the GNU General Public License or any other license to use
|
|
// the code or files shall permit you to use Tripwire's trademarks,
|
|
// service marks, or other intellectual property without Tripwire's
|
|
// prior written consent.
|
|
//
|
|
// If you have any questions, please contact Tripwire, Inc. at either
|
|
// info@tripwire.org or www.tripwire.org.
|
|
//
|
|
// errorbucketimpl.cpp
|
|
#include "stdcore.h"
|
|
#include "errorbucketimpl.h"
|
|
#include "errortable.h"
|
|
#include "serializer.h"
|
|
#include "corestrings.h"
|
|
#include "displayencoder.h"
|
|
|
|
//#############################################################################
|
|
// cErrorBucket
|
|
//#############################################################################
|
|
void cErrorBucket::AddError(const eError& error)
|
|
{
|
|
HandleError(error);
|
|
if (mpChild)
|
|
mpChild->AddError(error);
|
|
}
|
|
|
|
//#############################################################################
|
|
// cErrorReporter
|
|
//#############################################################################
|
|
void cErrorReporter::PrintErrorMsg(const eError& error, const TSTRING& strExtra)
|
|
{
|
|
cDisplayEncoder e((cDisplayEncoder::Flags)(cDisplayEncoder::NON_ROUNDTRIP | cDisplayEncoder::ALLOW_WHITESPACE));
|
|
TSTRING errStr;
|
|
|
|
//
|
|
// if the ID is zero, just return.
|
|
// this should only occur at the top level of a program (ie -- twcmdline.cpp) and
|
|
// indicates that an error occurred and an error message has already been printed out.
|
|
// Therefore, we will do nothing here but return.
|
|
//
|
|
|
|
// TODO: Having an error with an ID of 0 is legacy. The only place it happens at this
|
|
// point is when we throw ePoly() with no constructor arguments. At some point we want
|
|
// to stop using the mechanism have non-printing errors, thus we leave in the ASSERT below.
|
|
// But we don't want to break any release code, thus we return on the next line - June 2, 1999 DMB.
|
|
ASSERT(error.GetID() != 0);
|
|
|
|
if (error.GetID() == 0)
|
|
return;
|
|
|
|
// "First Part" header
|
|
errStr = TSS_GetString(cCore, error.IsFatal() ? core::STR_ERROR_ERROR : core::STR_ERROR_WARNING);
|
|
|
|
if (errStr.empty())
|
|
{
|
|
TOSTRINGSTREAM strm;
|
|
ASSERT(sizeof(uint32) == sizeof(unsigned int)); // for cast on next line
|
|
strm << _T("Unknown Error ID ") << (unsigned int)error.GetID();
|
|
errStr = strm.str();
|
|
}
|
|
|
|
//int len = errStr.length(); // save for later
|
|
TCERR << errStr;
|
|
|
|
// "First Part" error string
|
|
TSTRING prependToSecond;
|
|
|
|
// #pragma message("errorbucketimpl.cpp needs a little help in the mb arena, with the findfirst/last and such")
|
|
|
|
errStr = cErrorTable::GetInstance()->Get(error.GetID());
|
|
if (!errStr.empty())
|
|
{
|
|
// If the first part has a '\n' in it, we take everything following and prepend it to the
|
|
// second part. This was added to allow specifing a verbose string as the second part
|
|
// of an error message when building the error table. This change was made on July 27, 1999
|
|
TSTRING::size_type firstLF;
|
|
if ((firstLF = errStr.find_first_of(_T('\n'))) != TSTRING::npos)
|
|
{
|
|
prependToSecond = errStr.substr(firstLF + 1); // don't include '\n' in new string
|
|
errStr.erase(firstLF);
|
|
}
|
|
|
|
ASSERT(errStr.length() + len + 6 < 80); // line too big for terminal?
|
|
// Add 6 to account for "### ' and ': '
|
|
TCERR << TSS_GetString(cCore, core::STR_ERROR_COLON) << _T(" ") << errStr;
|
|
TCERR << std::endl;
|
|
}
|
|
|
|
// "Second Part" error string
|
|
const int WIDTH = 80 - 4; // allow for "### " prefix to every error line
|
|
const TCHAR SPACE = _T(' ');
|
|
|
|
errStr = prependToSecond + error.GetMsg() + strExtra;
|
|
e.Encode(errStr);
|
|
if (!errStr.empty())
|
|
{
|
|
do
|
|
{
|
|
// look for newline chars
|
|
TSTRING::size_type firstNewLine;
|
|
TSTRING currentStr = errStr.substr(0, (firstNewLine = errStr.find_first_of(_T('\n'))));
|
|
errStr.erase(0, (firstNewLine < errStr.length() ? firstNewLine + 1 : firstNewLine));
|
|
|
|
// break up the error string in case it is larger than screen width
|
|
do
|
|
{
|
|
if (currentStr.length() <= (unsigned int)WIDTH)
|
|
{
|
|
TCERR << TSS_GetString(cCore, core::STR_ERROR_HEADER) << currentStr << std::endl;
|
|
break;
|
|
}
|
|
|
|
TSTRING::size_type lastSpace =
|
|
currentStr.find_last_of(SPACE, currentStr.length() >= WIDTH - 1 ? WIDTH - 1 : TSTRING::npos);
|
|
if (lastSpace == TSTRING::npos)
|
|
{
|
|
// can't find space to break at so this string will just have to be longer than screen width.
|
|
// search forward for a space so we break at the next even word boundry.
|
|
lastSpace = currentStr.find_first_of(SPACE, 0);
|
|
if (lastSpace == TSTRING::npos)
|
|
// Well, there is no space before the end of the string.
|
|
// So print the whole string out.
|
|
lastSpace = currentStr.length();
|
|
}
|
|
|
|
TCERR << TSS_GetString(cCore, core::STR_ERROR_HEADER) << currentStr.substr(0, lastSpace) << std::endl;
|
|
|
|
currentStr.erase(0, lastSpace + 1);
|
|
} while (!currentStr.empty());
|
|
} while (!errStr.empty());
|
|
}
|
|
|
|
// "Third Part" print 'exiting' or 'continuing'
|
|
// note that we supress this part if the appropriate flag is set...
|
|
//
|
|
if ((error.GetFlags() & eError::SUPRESS_THIRD_MSG) == 0)
|
|
{
|
|
TCERR << TSS_GetString(cCore, core::STR_ERROR_HEADER)
|
|
<< TSS_GetString(cCore, error.IsFatal() ? core::STR_ERROR_EXITING : core::STR_ERROR_CONTINUING)
|
|
<< std::endl;
|
|
}
|
|
}
|
|
|
|
void cErrorReporter::HandleError(const eError& error)
|
|
{
|
|
PrintErrorMsg(error);
|
|
}
|
|
|
|
//#############################################################################
|
|
// cErrorTracer
|
|
//#############################################################################
|
|
void cErrorTracer::HandleError(const eError& error)
|
|
{
|
|
cDebug d("cErrorTracer::HandleError");
|
|
|
|
d.TraceError(_T("%s : %s\n"), cErrorTable::GetInstance()->Get(error.GetID()).c_str(), error.GetMsg().c_str());
|
|
}
|
|
|
|
//#############################################################################
|
|
// cErrorQueue
|
|
//#############################################################################
|
|
IMPLEMENT_TYPEDSERIALIZABLE(cErrorQueue, _T("cErrorQueue"), 0, 1);
|
|
|
|
void cErrorQueue::Clear()
|
|
{
|
|
mList.clear();
|
|
}
|
|
|
|
int cErrorQueue::GetNumErrors() const
|
|
{
|
|
return mList.size();
|
|
}
|
|
|
|
void cErrorQueue::HandleError(const eError& error)
|
|
{
|
|
mList.push_back(ePoly(error));
|
|
}
|
|
|
|
cErrorQueueIter::cErrorQueueIter(cErrorQueue& queue) : mList(queue.mList)
|
|
{
|
|
SeekBegin();
|
|
}
|
|
|
|
cErrorQueueIter::cErrorQueueIter(const cErrorQueue& queue) : mList(((cErrorQueue*)&queue)->mList)
|
|
{
|
|
SeekBegin();
|
|
}
|
|
|
|
|
|
void cErrorQueueIter::SeekBegin()
|
|
{
|
|
mIter = mList.begin();
|
|
}
|
|
|
|
void cErrorQueueIter::Next()
|
|
{
|
|
++mIter;
|
|
}
|
|
|
|
bool cErrorQueueIter::Done() const
|
|
{
|
|
return (mIter == mList.end());
|
|
}
|
|
|
|
const ePoly& cErrorQueueIter::GetError() const
|
|
{
|
|
ASSERT(!Done());
|
|
return (*mIter);
|
|
}
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
// Read
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
void cErrorQueue::Read(iSerializer* pSerializer, int32 version)
|
|
{
|
|
if (version > Version())
|
|
ThrowAndAssert(eSerializerVersionMismatch(_T("ErrorQueue Read")));
|
|
|
|
int32 size;
|
|
mList.clear();
|
|
pSerializer->ReadInt32(size);
|
|
for (int i = 0; i < size; ++i)
|
|
{
|
|
int32 errorNumber;
|
|
TSTRING errorString;
|
|
int32 flags;
|
|
|
|
pSerializer->ReadInt32(errorNumber);
|
|
pSerializer->ReadString(errorString);
|
|
pSerializer->ReadInt32(flags);
|
|
|
|
mList.push_back(ePoly(errorNumber, errorString, flags));
|
|
}
|
|
}
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
// Write
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
void cErrorQueue::Write(iSerializer* pSerializer) const
|
|
{
|
|
pSerializer->WriteInt32(mList.size());
|
|
ListType::const_iterator i;
|
|
for (i = mList.begin(); i != mList.end(); ++i)
|
|
{
|
|
pSerializer->WriteInt32((*i).GetID());
|
|
pSerializer->WriteString((*i).GetMsg());
|
|
pSerializer->WriteInt32((*i).GetFlags());
|
|
}
|
|
}
|
|
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
// TraceContents
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
void cErrorQueue::TraceContents(int dl) const
|
|
{
|
|
if (dl < 0)
|
|
dl = cDebug::D_DEBUG;
|
|
|
|
cDebug d("cFCOErrorQueue::TraceContents");
|
|
ListType::const_iterator i;
|
|
int counter = 0;
|
|
for (i = mList.begin(); i != mList.end(); i++, counter++)
|
|
{
|
|
d.Trace(dl, _T("Error[%d]: num = %x string = %s\n"), counter, (*i).GetID(), (*i).GetMsg().c_str());
|
|
}
|
|
}
|