//except6.cpp
#include <iostream.h>
struct Error	{
   const char* source;
   const char* file;
   int line;
   friend ostream& operator<<(ostream& o, Error &e);
   Error(const char* src, const char* srcfile, int srcline)
	: source(src), file(srcfile), line(srcline) { }
};
ostream& operator<<(ostream& o, Error &e)	{
   o << "Error -  file:" << e.file;
   o << ", line:" << e.line;
   o << ", source:" << e.source << "\n";
   return o;
}
struct MemoryExhaust : public Error	{
   friend ostream& operator<<(ostream& o, MemoryExhaust &e);
   MemoryExhaust(const char* src, const char* srcfile, int srcline)
	 : Error(src,srcfile,srcline) {		}
};
ostream& operator<<(ostream& o, MemoryExhaust &e)	{
   o << "Memory Exhausted " << (Error)e;
   return o;
}
struct Bounds : public	Error	{
   int index;
   friend ostream& operator<<(ostream& o, Bounds &e);
   Bounds(const char* src, const char* srcfile, int srcline, int idx)
	 : Error(src,srcfile,srcline), index(idx) {		}
};
ostream& operator<<(ostream& o, Bounds &e)	{
   o << "Bounds (" << e.index << ") " << (Error)e;
   return o;
}
struct UnderFlowError : public Bounds	{
   friend ostream& operator<<(ostream& o, UnderFlowError &e);
   UnderFlowError(const char* src, const char* srcfile, int srcline, int idx)
	 : Bounds(src,srcfile,srcline,idx) { }
};
ostream& operator<<(ostream& o, UnderFlowError &e)	{
   o << "UnderFlow " << (Bounds)e;
   return o;
}
struct OverFlowError : public Bounds	{
   friend ostream& operator<<(ostream &o, OverFlowError &e);
   OverFlowError(const char* src, const char* srcfile, int srcline, int idx)
	: Bounds(src,srcfile,srcline,idx) { }
};
ostream& operator<<(ostream &o, OverFlowError &e)	{
   o << "OverFlow " << (Bounds)e;
   return o;
}
struct NoObject : public Error	{
   friend ostream& operator<<(ostream& o, NoObject &e);
   NoObject(const char* src, const char* srcfile, int srcline)
	  : Error(src,srcfile,srcline) {		}
};
ostream& operator<<(ostream& o, NoObject &e)	{
   o << "Null Object Access" << (Error)e;
   return o;
}

template <class T>
class Array	{
   T *values;
   int size;
public:
   enum Error { Memory, UnderFlow, OverFlow };
   Array(int sz);
   T get(int idx) throw (int);
   int set(int idx, T val);
   };
template <class T>
Array<T>::Array(int sz)		{
   values = new T[size=sz];
   if (!values)	{
	size = 0;
	throw MemoryExhaust("Array<T>::Array()",__FILE__,__LINE__);
	cerr << "this statement will never get executed\n";
   }
}
template <class T>
T Array<T>::get(int idx) throw(int)  {
   if (idx < 0)	{
	throw UnderFlowError("Array<T>::get()",__FILE__,__LINE__,idx);
	cerr << "this statement will never get executed\n";
   }
   else if (idx >= size)	{
	throw OverFlowError("Array<T>::get()",__FILE__,__LINE__,idx);
	cerr << "this statement will never get executed\n";
   }
   else if (!values)	{
	throw NoObject("Array<T>::set()",__FILE__,__LINE__);
   }
   else	{
	return values[idx];
   }
}
template <class T>
int Array<T>::set(int idx, T val)	{
   if (idx < 0)	{
	throw Bounds("Array<T>::set()",__FILE__,__LINE__,idx);
	cerr << "this statement will never get executed\n";
   }
   else if (idx >= size)	{
	throw Bounds("Array<T>::set()",__FILE__,__LINE__,idx);
	cerr << "this statement will never get executed\n";
   }
   else if (!values)	{
	throw NoObject("Array<T>::set()",__FILE__,__LINE__);
   }
   else	{
	values[idx] = val;
	return 0;
   }
}
void fn(int c)	{
   static Array<int> *myArrayPtr=0;
   switch (c)	{
	case 0:	myArrayPtr = new Array<int>(10);
		//let's pretend there was an error
		throw MemoryExhaust("fn",__FILE__,__LINE__);
		break;
	case 1:	myArrayPtr->set(-1,0);	break;
	case 2:	myArrayPtr->set(10,0);	break;
	case 3:	myArrayPtr->get(-1);	break;
	case 4:	myArrayPtr->get(10);	break;
   }
}
void main()	{
   try	{ fn(0);	}
   catch (MemoryExhaust &m)	{
	cerr << m;
	try {	fn(1);	}
	catch (Bounds &b)	{
		cerr << b;
		try {	fn(2);	}
		catch (Bounds &b)	{
			cerr << b;
			try {	fn(3);	}
			catch (UnderFlowError &u)	{
				cerr << u;
				try { fn(4);	}
				catch (OverFlowError &o)	{
					cerr << o;
					fn(5);
				} //catch-OverFlowError
			} //catch-UnderFlowError
		} //catch-Bounds
	} //catch-Bounds
   } //catch-MemoryExhaust
   catch (NoObject &n)	{
	cerr << n;
   }
   catch (...)	{
	cerr << "xxx\n";
   }
   cout << "bye\n";
}
/************** output *****************
Memory Exhausted Error - file:EXCEPT6.CPP, line:125, source fn
Bounds (-1) Error - file:EXCEPT6.CPP, line:104, source:Array<T>::set()
Bounds (10) Error - file:EXCEPT6.CPP, line:108, source:Array<T>::set()
****************************************/


