
#define ZMALLOC(to, typ) ((to = (typ *)safemalloc(sizeof(typ))), \
				Zero(to,1,typ))

#define CALLERS_FILENAME	"Db::_filename"
#define CALLERS_LINENO		"Db::_line"

#if 0
# define DEBUG_EXC(x) \
    {									\
	int line_no;							\
	string filename ;						\
	my_get_caller(line_no, filename);				\
	cout << "Caught " << x << ": " << e.what() << " in "		\
	     << filename << ", line " << line_no << endl;		\
    }

#else
# define DEBUG_EXC(x) 
#endif

#define doCatch(real, type, name)					\
	catch(real & e)							\
	{								\
	    DEBUG_EXC(name);						\
	    type * e_copy = new type(e);				\
            SV * except = sv_newmortal();				\
            sv_setref_pv(except, name, (void*)e_copy);			\
            SV * errsv = get_sv("@", TRUE);				\
	    sv_setsv(errsv, except);					\
	    croak(Nullch);						\
	}

#define x_MY_CATCH	\

#ifdef DBXML_VERSION_MAJOR
#  define doXMLExc        doCatch(XmlException, MyXmlException, "XmlException")
#else
#  define doXMLExc        
#endif

#define MY_TRY	try {

#define MY_CATCH							\
        }								\
        doXMLExc							\
        doCatch(DbLockNotGrantedException, MyDbException, "DbLockNotGrantedException")	\
        doCatch(DbRunRecoveryException, MyDbException, "DbRunRecoveryException")	\
        doCatch(DbDeadlockException, MyDbException, "DbDeadlockException")\
        doCatch(DbException, MyDbException, "DbException")		\
        doCatch(std::exception, MyBaseException, "std::exception")	\
	catch(...)							\
	{								\
	    MyUnknownException * e_copy = new MyUnknownException();	\
            SV * except = sv_newmortal();				\
            sv_setref_pv(except, "UnknownException", (void*)e_copy);	\
            SV * errsv = get_sv("@", TRUE);				\
	    sv_setsv(errsv, except);					\
	    croak(Nullch);						\
	}								\
	{								\
	    SV* sv = perl_get_sv(CALLERS_LINENO, FALSE) ;		\
	    sv_setiv(sv, -1);						\
	}


#define String2Char(method) 						\
	    std::string tmp = THIS->method();				\
	    RETVAL = tmp.c_str() ;

#define newSVfromString(s) newSVpvn(s.c_str(), s.length())

#define getDBT(from, to, del)						\
	    if (from == &PL_sv_undef || SvTYPE(from) == SVt_NULL){	\
	        to = new Dbt;						\
		del = true ;						\
	    }								\
            else if (sv_isobject(from) && (SvTYPE(SvRV(from)) == SVt_PVMG))\
	        to = (Dbt*)SvIV((SV*)SvRV( from ));			\
	    else {							\
		char * ptr = SvPV(from, len);				\
	        to = new Dbt(ptr, len);					\
		del = true ;						\
	    }	

#define putDBT(data, dbt_data)						\
                sv_setpvn(data, (char*)dbt_data->get_data(), 		\
				dbt_data->get_size());			

#define getPVorNULL(from, to)						\
            if (from == NULL || from == &PL_sv_undef || SvTYPE(from) == SVt_NULL)\
                to = NULL ;						\
            else {							\
	        STRLEN my_na ;						\
                to = (char*)SvPV(from,my_na) ;				\
                if (my_na == 0)						\
                    to = NULL ;						\
            }

#define Sv_ISA(i, type) 	sv_derived_from(ST(i), type)
#define GetObjPointer(i, type) 	((type*)SvIV((SV*)SvRV(i)))
#define GetStringPointer(i)	(char *)SvPV_nolen(ST(i));
#define GetUV(i, type)		(type)SvUV(ST(i));

#define SV_IS_OBJECT(x) (sv_isobject(x) && (SvTYPE(SvRV(x)) == SVt_PVMG))


static void
my_hv_store(HV * hash, char * key, SV * value)
{
    hv_store(hash, key, strlen(key), value, 0);
}

static void
my_get_caller(int& line_no, string& filename)
{
    SV * sv = perl_get_sv(CALLERS_LINENO, FALSE) ;
    int i ;

    if (sv && (i = SvIV(sv)) >= 0) {
        line_no = i;
        sv = perl_get_sv(CALLERS_FILENAME, FALSE) ;
	if (sv)
	    filename = SvPV_nolen(sv);
	else
            filename =  "fred";
    }
    else {
        line_no = CopLINE(PL_curcop);
        filename =  CopFILE(PL_curcop);
    }
}


class MyBaseException
{
  public:
    MyBaseException(const char * message)
    {
        save_what(message);
    }	   

    MyBaseException(std::exception & e)
    {
        save_what(e.what());
    }	   

    void save_what(const char * what) 
    {
        message = what;
	my_get_caller(line_no, filename);
	char buff[10] ;
	sprintf(buff, "%d", line_no);
	full_message = message + " in " + filename + ", line " + buff;
    }

    ~MyBaseException()
    {
    }	   

    const char* what() const { return full_message.c_str(); }

    const char * getMessage() { return message.c_str() ; }
    int getLineNo() { return line_no; }
    const char * getFilename() { return filename.c_str() ; } 


  private:	 
    string full_message;
    string message;
    int line_no ;
    string filename ;
};

#ifdef DBXML_VERSION_MAJOR
class MyXmlException : public MyBaseException
{
  public:
	MyXmlException(XmlException & e) 
	    : MyBaseException(e)
	{
	    err = e.getDbErrno(); 
	    ex  = e.getExceptionCode();
	}

	~MyXmlException() {}
	XmlException::ExceptionCode getExceptionCode() { return ex ; }
	int getDbErrno() { return err; }

    private:
	int err;
	XmlException::ExceptionCode ex;
};
#endif

class MyDbException : MyBaseException
{
  public:
	MyDbException(DbException & e) : MyBaseException(e.what())
	{
            err = e.get_errno();
            message = e.what();
	    my_get_caller(line_no, filename);
	    char buff[10] ;
	    sprintf(buff, "%d", line_no);
	    full_message = message + " in " + filename + ", line " + buff;
	}

	~MyDbException() {}

	int get_errno() { return err; }

    private:
	int err;
        string full_message;
        string message;
        int line_no ;
        string filename ;
};



class MyUnknownException : public MyBaseException
{
    public:
        MyUnknownException() : MyBaseException("Unknown Exception")
	{
	}

	~MyUnknownException()
	{
	}

};
