// $Id: Obj.h,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.

#ifndef obj_h
#define obj_h

#include "input.h"
#include "Desc.h"

class Serializer;

class Location {
public:
	Location(const char* fname, int line_f, int line_l, int col_f, int col_l)
		{
		filename = fname;
		first_line = line_f;
		last_line = line_l;
		first_column = col_f;
		last_column = col_l;
		delete_data = false;

		timestamp = 0;
		text = 0;
		}

	Location()
		{
		filename = 0;
		first_line = last_line = first_column = last_column = 0;
		delete_data = false;
		timestamp = 0;
		text = 0;
		}

	~Location()
		{
		if ( delete_data )
			delete [] filename;
		}

	bool Serialize(Serializer* s);
	bool Unserialize(Serializer* s);

	const char* filename;
	int first_line, last_line;
	int first_column, last_column;
	bool delete_data;

	// Timestamp and text for compatibility with Bison's default yyltype.
	int timestamp;
	char* text;
};

#define YYLTYPE yyltype
typedef Location yyltype;
YYLTYPE GetCurrentLocation();

// Used to mean "no location associated with this object".
extern Location no_location;

// Current start/end location.
extern Location start_location;
extern Location end_location;

// Used by parser to set the above.
inline void set_location(const Location loc)
	{
	start_location = end_location = loc;
	}

inline void set_location(const Location start, const Location end)
	{
	start_location = start;
	end_location = end;
	}

class BroObj {
public:
	BroObj()
		{ ref_cnt = 1; location = 0; }

	virtual ~BroObj();

	// Report user warnings/errors.  If obj2 is given, then it's
	// included in the message, though if pinpoint_only is non-zero,
	// then obj2 is only used to pinpoint the location.
	void Warn(const char* msg, const BroObj* obj2 = 0,
			int pinpoint_only = 0) const;
	void Error(const char* msg, const BroObj* obj2 = 0,
			int pinpoint_only = 0) const;
	void RunTime(const char* msg, const BroObj* obj2 = 0,
			int pinpoint_only = 0) const;

	// Report internal errors.
	void BadTag(const char* msg) const;
	void Internal(const char* msg) const;

	virtual void Describe(ODesc* d) const = 0;

	void AddLocation(ODesc* d) const;

	// Get location info for debugging.
	const Location* GetLocationInfo() const
		{ return location ? location : &no_location; }

	virtual bool SetLocationInfo(const Location* loc)
		{ return SetLocationInfo(loc, loc); }

	// Location = range from start to end.
	virtual bool SetLocationInfo(const Location* start, const Location* end);

protected:
	int RefCnt() const	{ return ref_cnt; }

	Location* location;	// all that matters in real estate

private:
	void DoMsg(const char s1[], const char s2[], const BroObj* obj2 = 0,
			int pinpoint_only = 0) const;
	void PinPoint(ODesc* d, const BroObj* obj2 = 0,
			int pinpoint_only = 0) const;
	void Fatal() const;

	friend inline void Ref(BroObj* o);
	friend inline void Unref(BroObj* o);

	int ref_cnt;
};

// Prints obj to stderr, primarily for debugging.
extern void print(const BroObj* obj);

extern void bad_ref();

// Sometimes useful when dealing with BroObj subclasses that have their
// own (protected) versions of Error.
inline void Error(const BroObj* o, const char* msg)
	{
	o->Error(msg);
	}

inline void Ref(BroObj* o)
	{
	if ( ++o->ref_cnt <= 1 )
		bad_ref();
	}

inline void Unref(BroObj* o)
	{
	if ( o && --o->ref_cnt <= 0 )
		{
		if ( o->ref_cnt < 0 )
			bad_ref();
		delete o;

		// We could do the following if o were passed by reference.
		// o = (BroObj*) 0xcd;
		}
	}

// A dict_delete_func that knows to Unref() dictionary entries.
extern void bro_obj_delete_func(void* v);

#endif
