1 #ifndef __error_h__
2 #define __error_h__
3 
4 #include <iostream>
5 #include <string>
6 #include <algorithm>
7 #include <exception>
8 #include <vector>
9 
10 #include <cerrno>
11 
12 #include "asserts.h"
13 #include "types.h"
14 
15 /** Instance of a single error containing a descriptive error message and the
16  * location in the file that the error took place */
17 class error_instance
18 {
19 public:
20 	error_instance();
21 	error_instance(const error_instance& a_e);
22 	error_instance(
23 		const std::string a_what,
24 #ifdef __GNUC__
25 		const std::string a_where,
26 #endif
27 		const std::string a_file,
28 		const uint16 a_line
29 		);
30 
31 	void clear(void);
32 	void set(void);
33 	void set(const error_instance& a_e);
34 	void set(
35 		const std::string a_what,
36 #ifdef __GNUC__
37 		const std::string a_where,
38 #endif
39 		const std::string a_file,
40 		const uint16 a_line
41 		);
42 
43 	const std::string what(void) const;
44 #ifdef __GNUC__
45 	const std::string where(void) const;
46 #endif
47 	const std::string file(void) const;
48 	const uint16 line(void) const;
49 
50 	error_instance& operator=(const error_instance& a_e);
51 
52 	// void dump(std::ostream& a_out, const std::string& a_prefix) const;
53 
54 private:
55 	std::string m_what;
56 #ifdef __GNUC__
57 	std::string m_where;
58 #endif
59 	std::string m_file;
60 	uint16 m_line;
61 };
62 
63 #ifdef __GNUC__
64 #define ERROR_INSTANCE(s) \
65 	error_instance((s), __PRETTY_FUNCTION__, __FILE__, __LINE__)
66 #else
67 #define ERROR_INSTANCE(s) \
68 	error_instance((s), __FILE__, __LINE__)
69 #endif
70 
71 /** An error class */
72 class error : public std::vector<error_instance>
73 {
74 public:
75 	typedef std::vector<error_instance> type;
76 
77 	error(const int a_errno);
78 	error(
79 		const int a_errno,
80 		const error_instance& a_e,
81 		const bool a_internal = false
82 		);
83 	error(const error& a_e);
84 
85 	void clear(void);
86 	void clear_stack(void);
87 	void internal(bool a_i);
88 	const bool internal(void) const;
89 	void num(int a_i);
90 	int num(void) const;
91 	void push_back(const error_instance& a_e);
92 	void push_back(const error& a_e);
93 	void push_back(const std::string& a_str);
94 	void assign(const error& a_e);
95 
96 	error& operator=(const error& a_e);
97 	std::ostream& write(
98 		std::ostream& a_out,
99 		const std::string a_prefix = ""
100 		) const;
101 	const std::string str(const std::string a_prefix = "") const;
102 
103 	// std::ostream& dump(std::ostream& a_out) const;
104 
105 private:
106 	int m_errno;
107 	bool m_internal;
108 };
109 
110 std::ostream& operator<<(std::ostream& a_out, const error& a_e);
111 
112 //-----------------------------------------------------------------------------
113 
114 #define err_unknown INTERNAL_ERROR(0,"An unknown error has occured")
115 
116 #define err_nomem ERROR(ENOMEM,"Out of memory")
117 
118 //-----------------------------------------------------------------------------
119 
120 #define ERROR(e,s) \
121 	error(e,ERROR_INSTANCE((s)), false)
122 
123 #define INTERNAL_ERROR(e,s) \
124 	error(e,ERROR_INSTANCE(s), true)
125 
126 #define TRY(code,es) \
127 	try { \
128 		code; \
129 	} \
130 	catch(error e) { \
131 		e.push_back(ERROR_INSTANCE(es)); \
132 		throw(e); \
133 	} \
134 	catch(...) { \
135 		if (errno == ENOMEM) { \
136 			throw(err_nomem); \
137 		} \
138 		error e = err_unknown; \
139 	\
140 		e.push_back(es); \
141 		throw(e); \
142 	}
143 
144 #define TRY_nomem(code) \
145 	try { \
146 		code; \
147 	} \
148 	catch(error e) { \
149 		throw(e); \
150 	} \
151 	catch(...) { \
152 		if (errno == ENOMEM) { \
153 			throw(err_nomem); \
154 		} \
155 		throw(err_unknown); \
156 	}
157 
158 #define TRY_instead(code,es) \
159 	try { \
160 		code; \
161 	} \
162 	catch(error e) { \
163 		e.clear_stack(); \
164 		e.push_back(ERROR_INSTANCE(es)); \
165 		throw(e); \
166 	} \
167 	catch(...) { \
168 		if (errno == ENOMEM) { \
169 			throw(err_nomem); \
170 		} \
171 		error e = err_unknown; \
172 	\
173 		e.push_back(es); \
174 		throw(e); \
175 	}
176 
177 #define TRY_log(code,es) \
178 	try { \
179 		code; \
180 	} \
181 	catch(error e) { \
182 		e.clear_stack(); \
183 		e.push_back(ERROR_INSTANCE(es)); \
184 		logger.write(e.str()); \
185 	} \
186 	catch(...) { \
187 		if (errno == ENOMEM) { \
188 			throw(err_nomem); \
189 		} \
190 		error e = err_unknown; \
191 	\
192 		e.push_back(es); \
193 		logger.write(e.str()); \
194 	}
195 
196 const char * get_error_str(const int a_err);
197 
198 #endif
199