error.cc #1

  • //
  • guest/
  • perforce_software/
  • p4/
  • 2014-2/
  • support/
  • error.cc
  • View
  • Commits
  • Open Download .zip Download (7 KB)
/*
 * Copyright 1995, 2002 Perforce Software.  All rights reserved.
 */

/*
 * Error.cc - accumulate and report layered errors
 *
 * This module containts the manipulation of Error, mostly wrappers
 * of methods to the private ErrorPrivate, which are are managed in 
 * erroritms.cc.
 */

# include <stdhdrs.h>
# include <strbuf.h>
# include <strdict.h>
# include <strtable.h>
# include <strops.h>
# include <error.h>
# include <errorpvt.h>

const char *
Error::severityText[] = { "empty", "info", "warning", "error", "error" };

/*
 * Error::Error() - cheaply initialize error struct 
 *
 * Note that setting severity = E_EMPTY is all that is needed
 * to indicate no error.  Things get initialized when severity
 * gets upgraded.
 */

Error::~Error()
{
	delete ep;
}

/*
 * Error::=() - copy an Error struct, piece by piece

 * Note that this makes a shallow copy.  Use Snap() if you need a deep copy.
 */

void
Error::operator =( const Error &s )
{
	// Only severity needed if empty

	severity = s.severity;

	if( severity == E_EMPTY )
	    return;

	// Copy underbelly.

	if( !ep )
	    ep = new ErrorPrivate;

	genericCode = s.genericCode;
	if( s.ep )
	    *ep = *s.ep;
}

/*
 * Error::Set() - add an error message into an Error struct
 */

Error &		
Error::Set( const ErrorId &id )
{ 
	/* First access?  Set private. */

	if( !ep )
	    ep = new ErrorPrivate;

	/* First error?  Clear things out */

	if( severity == E_EMPTY )
	    ep->Clear();

	/* If error more severe that previous, save severity & generic */

	ErrorSeverity s = (ErrorSeverity)id.Severity();

	if( s >= severity )
	{
	    severity = s;
	    genericCode = id.Generic();
	}

	/* Now prepare the error message for formatting. */

	ep->Set( id );

	return *this;
}

Error &
Error::operator <<( const StrPtr &arg )
{
	ep->SetArg( arg );
	return *this;
}

Error &
Error::operator <<( const char *arg )
{
	ep->SetArg( StrRef( arg ) );
	return *this;
}

Error &
Error::operator <<( const StrPtr *arg )
{
	ep->SetArg( *arg );
	return *this;
}

Error &
Error::operator <<( int arg )
{
	ep->SetArg( StrNum( arg ) );
	return *this;
}

/*
 * Error::Get() - get an individual Error item
 */

ErrorId *
Error::GetId( int i ) const
{
	return !ep || i < 0 || i >= ep->errorCount ? 0 : &ep->ids[i];
}

int
Error::GetErrorCount() const
{
	return ep ? ep->errorCount : 0;
}

void
Error::LimitErrorCount()
{
	if( ep && ep->errorCount > OldErrorMax )
	    ep->errorCount = OldErrorMax;
}

/*
 * Error::GetDict() - get StrDict of error parameters
 */

StrDict *
Error::GetDict()
{
	return ep ? ep->whichDict : 0;
}

/*
 * Error::Fmt() - format an error message
 *
 * Error messages are already formatted by Set() and <<.
 */

void
Error::Fmt( StrBuf &buf, int opts ) const
{
	Fmt( -1, buf, opts );
}
void
Error::Fmt( int eno, StrBuf &buf, int opts ) const
{
	if( !severity )
	    return;

	if( !IsInfo() ) 
	    buf.Clear();

	StrBuf lfmt;
	StrPtr *l = 0;

	if( !( opts & EF_NOXLATE ) )
	{
	    lfmt.Set( "lfmt" );
	    l = &lfmt;
	}

	for( int i = ep->errorCount; i-- > 0; )
	{
	    if( eno != -1 && eno != (i+1) )
		continue;

	    if( opts & EF_CODE )
	    {
		buf << StrNum( ep->ids[ i ].UniqueCode() );
		buf.Extend( ':' );
	    }

	    if( opts & EF_INDENT ) buf.Append( "\t", 1 );

	    StrPtr *s;
	    StrRef fmt;

	    if( !l || !( s = ep->whichDict->GetVar( *l, i ) ) )
	    {
		fmt.Set( (char *)ep->ids[i].fmt );
		s = &fmt;
	    }

	    StrOps::Expand2( buf, *s, *ep->whichDict ); 

	    // Always insert; sometimes append

	    if( eno == -1 && ( i || opts & EF_NEWLINE ) )
		buf.Append( "\n", 1 );
	}
}

/*
 * Error::Snap() - after UnMarshall1, copy all data into Error
 *
 * Resulting data is local:
 *
 *	whichDict is ErrorPrivate::errorDict
 *	ids[].fmt in ErrorPrivate::marshall
 */

void
Error::Snap()
{
	// ErrorPrivate::operator = handles snapping.
	if (ep)
	    *ep = *ep;
}

const ErrorId *
Error::MapError( const struct ErrorIdMap map[] )
{
	// shortcut if there are no ErrorIds to lookup
	if( !ep ) {
	    return NULL;
	}

	for(int i = 0; map[i].incomingError.UniqueCode() != 0; i++)
	{
	    for( int j=0; j < ep->errorCount; j++)
	    {
		if (map[i].incomingError.code == ep->ids[j].code )
		{
		    return &(map[i].outgoingError);
		}
	    }
	}
	return NULL;
}


/*
 * Errorpvt.cc - private data for Error object
 */

void
ErrorPrivate::operator =( const ErrorPrivate &s )
{
	// Handle self-assign as a way of snapping data.

	int isSelf = this == &s;

	// Simple parts

	walk = 0;
	errorCount = s.errorCount;
	fmtSource = s.fmtSource;

	// Dictionary.
	// It's a little faster to use BufferDict::operator =
	// than CopyVars(), so take that shortcut if we can.

	if( s.whichDict != &s.errorDict )
	    errorDict.CopyVars( *s.whichDict );
	else if( !isSelf )
	    errorDict = s.errorDict;

	whichDict = &errorDict;

	// Copy ids over.

	if( !isSelf )
	    for( int i = 0; i < errorCount; i++ )
		ids[i] = s.ids[i];

	// Snap ids[].fmt.
	// If self-assign, we skip this if they are already in the fmtBuf.
	// Otherwise, we skip only if they are constants (via Error::Set())
	// and thus global.

	if( isSelf ? ( fmtSource != isFmtBuf ) : ( fmtSource != isConst ) )
	{
	    int i;

	    fmtbuf.Clear();

	    for( i = 0; i < errorCount; i++ )
	    {
		fmtbuf.Append( ids[i].fmt );
		fmtbuf.Extend( 0 );
	    }

	    char *p = fmtbuf.Text();

	    for( i = 0; i < errorCount; i++ )
	    {
		ids[i].fmt = p;
		p += strlen( p ) + 1;
	    }

	    fmtSource = isFmtBuf;
	}

	// Copy arg walk state as offset from last id's fmt.

	if ( s.walk )
	    walk = ids[errorCount-1].fmt + (s.walk - s.ids[errorCount-1].fmt);
}

/*
 * ErrorPrivate::SetArg() - provide formatting parameters
 */

void
ErrorPrivate::SetArg( const StrPtr &arg )
{
	/* If we've already finished walking the fmt string */
	/* we can't really format any more parameters. */

	if( !walk )
	    return;

	/* Loop past %%'s and %'stuff'% looking for %param% */

	while( ( walk = strchr( walk, '%' ) ) )
	{
	    if( *++walk == '\'' )
	    {
		walk = strchr( walk, '%' );
		if( !walk )
		    return;
	    }
	    else if( *walk == '%' )
		;
	    else
		break;
	    ++walk;
	}

	// No more %?s

	if( !walk )
	    return;

	/* The %parameter% name is in the fmt string. */
	/* Just bail if there is no ending %. */

	const char *p;
	if( !( p = strchr( walk, '%' ) ) )
	    return;

	// %var% - set variable to arg
	// %!var% - ignore arg (leave variable unset)

	if( *walk != '!' )
	    whichDict->SetVar( StrRef( walk, p - walk ), arg );

	walk = p + 1;
}

/*
 * Error::Dump()
 * ErrorPrivate::Dump() - debugging
 */

void
Error::Dump( const char *trace )
{
	printf( "Error %s %p\n", trace, this );
	printf( "\tSeverity %d (%s)\n", severity, FmtSeverity() );

	if( severity == E_EMPTY )
	    return;

	printf( "\tGeneric %d\n", genericCode );

	ep->Dump();
}

void
ErrorPrivate::Dump()
{
	int i;
	StrRef r, l;

	printf( "\tCount %d\n", errorCount );

	for( i = 0; i < errorCount; i++ )
	{
	    printf( "\t\t%d: %d (sub %d sys %d gen %d args %d sev %d code %d)\n",
		i,
		ids[i].code,
		ids[i].SubCode(),
		ids[i].Subsystem(),
		ids[i].Generic(),
		ids[i].ArgCount(),
		ids[i].Severity(),
		ids[i].UniqueCode() );
	    printf( "\t\t%d: %s\n", i, ids[i].fmt );
	}

	for( i = 0; whichDict->GetVar( i, r, l ); i++ )
	{
	    // For null termination
	    StrBuf r1, l1;
	    r1 = r; l1 = l;
	    printf( "\t\t%s = %s\n", r1.Text(), l1.Text() );
	}
}
# Change User Description Committed
#1 15903 Matt Attaway Everything should be happy now between the Workshop and the depot paths
//guest/perforce_software/p4/2014_2/support/error.cc
#1 15901 Matt Attaway Clean up code to fit modern Workshop naming standards
//guest/perforce_software/p4/2014.2/support/error.cc
#1 12189 Matt Attaway Initial (and much belated) drop of 2014.2 p4 source code