// $Id: Obj.cc,v 1.24 2003/08/31 00:38:11 vern Exp $
//
// Copyright (c) 1995, 1996, 1997, 1998, 1999, 2001, 2002
//      The Regents of the University of California.  All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that: (1) source code distributions
// retain the above copyright notice and this paragraph in its entirety, (2)
// distributions including binary code include the above copyright notice and
// this paragraph in its entirety in the documentation or other materials
// provided with the distribution, and (3) all advertising materials mentioning
// features or use of this software display the following acknowledgement:
// ``This product includes software developed by the University of California,
// Lawrence Berkeley Laboratory and its contributors.'' Neither the name of
// the University nor the names of its contributors may be used to endorse
// or promote products derived from this software without specific prior
// written permission.
// THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
// WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.

#include "config.h"

#include <stdlib.h>

#include "Obj.h"
#include "Serializer.h"

Location no_location("<no location>", 0, 0, 0, 0);
Location start_location;
Location end_location;

bool Location::Serialize(Serializer* s)
	{
	s->Write(filename, strlen(filename));
	s->Write(first_line);
	s->Write(last_line);
	s->Write(first_column);
	s->Write(last_column);

	return true;
	}

bool Location::Unserialize(Serializer* s)
	{
	filename = 0;
	delete_data = true;

	int tmp;
	return s->Read(&(char*) filename, &tmp) &&
		s->Read(&first_line) && s->Read(&last_line) &&
		s->Read(&first_column) && s->Read(&last_column);
	}

BroObj::~BroObj()
	{
	delete location;
	}

void BroObj::Warn(const char* msg, const BroObj* obj2, int pinpoint_only) const
	{
	DoMsg("warning,", msg, obj2, pinpoint_only);
	++nwarn;
	}

void BroObj::Error(const char* msg, const BroObj* obj2, int pinpoint_only) const
	{
	DoMsg("error,", msg, obj2, pinpoint_only);
	++nerr;
	}

void BroObj::RunTime(const char* msg, const BroObj* obj2, int pinpoint_only) const
	{
	DoMsg("run-time error,", msg, obj2, pinpoint_only);
	++nruntime;
	}

void BroObj::BadTag(const char* msg) const
	{
	DoMsg("bad tag in", msg);
	Fatal();
	}

void BroObj::Internal(const char* msg) const
	{
	DoMsg("internal error:", msg);
	Fatal();
	}

void BroObj::AddLocation(ODesc* d) const
	{
	if ( ! location )
		{
		d->Add("<no location>");
		return;
		}

	if ( location->filename )
		d->Add(location->filename, ", ");

	if ( location->last_line != location->first_line )
		{
		d->Add("lines ");
		d->Add(location->first_line);
		d->Add("-");
		d->Add(location->last_line);
		}
	else
		{
		d->Add("line ");
		d->Add(location->first_line);
		}
	}

bool BroObj::SetLocationInfo(const Location* start, const Location* end)
	{
	if ( ! start || ! end )
		return false;

	if ( ! streq(start->filename, end->filename) )
		return false;

	if ( location && (start == &no_location || end == &no_location) )
		// We already have a better location, so don't use this one.
		return true;

	delete location;

	location = new Location(start->filename,
				start->first_line, end->last_line,
				start->first_column, end->last_column);

	return true;
	}

void BroObj::DoMsg(const char s1[], const char s2[], const BroObj* obj2,
			int pinpoint_only) const
	{
	ODesc d;
	d.SetShort();

	PinPoint(&d, obj2, pinpoint_only);
	d.SP();
	d.Add(s1);
	d.SP();
	d.Add(s2);
	fprintf(stderr, "%s\n", d.Description());
	}

void BroObj::PinPoint(ODesc* d, const BroObj* obj2, int pinpoint_only) const
	{
	if ( network_time > 0.0 )
		{
		char time[256];
		sprintf(time, "%.6f", network_time);
		d->Add(time);
		d->SP();
		}

	AddLocation(d);
	if ( obj2 && obj2->GetLocationInfo() != &no_location )
		{
		d->Add(" and ");
		obj2->AddLocation(d);
		d->Add("\n  ");
		}

	d->Add(" (");
	Describe(d);
	if ( obj2 && ! pinpoint_only )
		{
		d->Add(" and ");
		obj2->Describe(d);
		}

	d->Add("):");
	}

void BroObj::Fatal() const
	{
	exit(1);
	}

void print(const BroObj* obj)
	{
	ODesc d(DESC_READABLE, stderr);
	obj->Describe(&d);
	d.Add("\n");
	}

void bad_ref()
	{
	internal_error("bad reference count");
	abort();
	}

void bro_obj_delete_func(void* v)
	{
	Unref((BroObj*) v);
	}
