1 /*
2 * Copyright (C) 2000-2005 Chris Ross and various contributors
3 * Copyright (C) 1999-2000 Chris Ross
4 * All rights reserved.
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions are met:
8 *
9 * o Redistributions of source code must retain the above copyright notice, this
10 * list of conditions and the following disclaimer.
11 * o Redistributions in binary form must reproduce the above copyright notice,
12 * this list of conditions and the following disclaimer in the documentation
13 * and/or other materials provided with the distribution.
14 * o Neither the name of the ferite software nor the names of its contributors may
15 * be used to endorse or promote products derived from this software without
16 * specific prior written permission.
17 *
18 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
19 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
21 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
22 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
23 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
24 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
25 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
26 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
27 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
28 * POSSIBILITY OF SUCH DAMAGE.
29 */
30
31 #ifdef HAVE_CONFIG_HEADER
32 #include "../config.h"
33 #endif
34
35 #include "ferite.h"
36
37 #if defined(WIN32) && !defined(USING_MINGW)
38 # include "snprintf.h" /* This is so that we have somethings */
39 #endif
40
41 /**
42 * @group Error System
43 * @description There are a number of things a lot of languages lack and that is error handling.
44 * The functions in this group allow for the raising of exceptions during runtime,
45 * and compile time.
46 */
47
48 /**
49 * @function ferite_raise_script_error
50 * @declaration void ferite_raise_script_error( FeriteScript *script, int err, char *fmt, ... )
51 * @brief Raise an exception within the ferite engine.
52 * @param FeriteScript *script The running script
53 * @param int err The error code
54 * @param char *fmt The format of the error string
55 * @description Use the same formating codes as printf with this function
56 */
ferite_raise_script_error(FeriteScript * script,int err,char * fmt,...)57 void ferite_raise_script_error( FeriteScript *script, int err, char *fmt, ... )
58 {
59 FeriteNamespaceBucket *nsb;
60 FeriteVariable *gerr, *newError;
61 FeriteVariable *errstr, *erno;
62 char *msg;
63 va_list ap;
64
65 FE_ENTER_FUNCTION;
66 msg = fmalloc( 4096 );
67 va_start( ap, fmt );
68 vsprintf( msg, fmt, ap );
69 FUD(("ERROR RAISED: %s %d\n", msg, err ));
70
71 nsb = ferite_namespace_element_exists( script, script->mainns, "err" );
72 FE_ASSERT( nsb && nsb->type == FENS_VAR );
73 gerr = nsb->data;
74 script->error_state = FE_ERROR_THROWN;
75
76 if( VAO(gerr) == NULL )
77 {
78 nsb = ferite_namespace_element_exists( script, script->mainns, "Error" );
79 if( nsb == NULL )
80 {
81 FE_LEAVE_FUNCTION( NOWT );
82 exit(1);
83 }
84 newError = ferite_new_object( script, nsb->data, NULL );
85 VAO(gerr) = VAO(newError);
86 VAO(gerr)->refcount++;
87 ferite_variable_destroy( script, newError );
88 }
89
90 errstr = ferite_object_get_var( script, VAO(gerr), "str" );
91 ferite_str_set( VAS(errstr), msg, strlen(msg), FE_CHARSET_DEFAULT );
92 ffree( msg );
93
94 erno = ferite_object_get_var( script, VAO(gerr), "num" );
95 VAI(erno) = err;
96 FE_LEAVE_FUNCTION( NOWT );
97 }
98
99 /**
100 * @function ferite_verror
101 * @declaration void ferite_verror( FeriteScript *script, char *errormsg, va_list *ap )
102 * @brief Raise an error
103 * @param FeriteScript *script The script
104 * @param int err The error number associated with the error
105 * @param char *errormsg The error with formating codes in it
106 * @param va_list *ap The list of arguments
107 */
ferite_verror(FeriteScript * script,int err,char * errormsg,va_list * ap)108 void ferite_verror( FeriteScript *script, int err, char *errormsg, va_list *ap )
109 {
110 char msg[1024];
111
112 FE_ENTER_FUNCTION;
113
114 if( script == NULL )
115 {
116 vprintf(errormsg, *ap );
117 FE_LEAVE_FUNCTION( NOWT );
118 }
119 if( script->error == NULL )
120 script->error = ferite_buffer_new( 0 );
121
122 ferite_buffer_add_str( script->error, "Error: " );
123
124 /* if( ferite_is_executing( script ) )
125 ferite_buffer_printf( script->error, "[%s:%d] ", script->current_op_file, script->current_op_line ); */
126 ferite_buffer_vprintf( script->error, errormsg, ap );
127 if( script->error_state != FE_ERROR_THROWN )
128 {
129 if( ferite_is_executing( script ) )
130 {
131 vsnprintf( msg, 1024, errormsg, *ap );
132 ferite_raise_script_error( script, err, msg );
133 }
134 script->error_state = FE_ERROR_THROWN;
135 }
136
137 FE_LEAVE_FUNCTION( NOWT );
138 }
139 /**
140 * @function ferite_error
141 * @declaration void ferite_error( FeriteScript *script, char *errormsg, ... )
142 * @brief Throw an error within the engine
143 * @param FeriteScript *script The scipt we are using
144 * @param int err The error number associated with the error
145 * @param char *errormsg The error information
146 * @param . .. The formating values
147 */
ferite_error(FeriteScript * script,int err,char * errormsg,...)148 void ferite_error( FeriteScript *script, int err, char *errormsg, ... )
149 {
150 va_list ap;
151
152 FE_ENTER_FUNCTION;
153 va_start( ap, errormsg );
154 ferite_verror( script, err, errormsg, &ap);
155 va_end( ap );
156 FE_LEAVE_FUNCTION( NOWT );
157 }
158
159 /**
160 * @function ferite_vwarning
161 * @declaration void ferite_vwarning( FeriteScript *script, char *errormsg, ... )
162 * @brief Display a warning message. This does not cause an exception
163 * @param FeriteScript *script The current script
164 * @param char *errormsg The warning to be displayed
165 * @param va_list *ap The formatting values
166 */
ferite_vwarning(FeriteScript * script,char * errormsg,va_list * ap)167 void ferite_vwarning( FeriteScript *script, char *errormsg, va_list *ap )
168 {
169
170 FE_ENTER_FUNCTION;
171
172 if( script == NULL )
173 {
174 printf("ferite_warning(): script was called with NULL, this shouldn't happen\n");
175 vprintf(errormsg, *ap );
176 #ifdef DEBUG
177 printf("ferite_warning(): sleeping for gdb interruption for 10 seconds\n");
178 sleep(10);
179 #endif
180 FE_LEAVE_FUNCTION( NOWT );
181 }
182
183 if( script->warning == NULL )
184 script->warning = ferite_buffer_new( 0 );
185
186 ferite_buffer_add_str( script->warning, "Warning: " );
187 if( ferite_is_executing( script ) )
188 ferite_buffer_printf( script->warning, "[%s:%d] ", script->current_op_file, script->current_op_line );
189 ferite_buffer_vprintf( script->warning, errormsg, ap );
190
191 FE_LEAVE_FUNCTION( NOWT );
192 }
193
194 /**
195 * @function ferite_warning
196 * @declaration void ferite_warning( FeriteScript *script, char *errormsg, ... )
197 * @brief Display a warning message. This does not cause an exception
198 * @param FeriteScript *script The current script
199 * @param char *errormsg The warning to be displayed
200 * @param . .. The formatting values
201 */
ferite_warning(FeriteScript * script,char * errormsg,...)202 void ferite_warning( FeriteScript *script, char *errormsg, ... )
203 {
204 va_list ap;
205
206 FE_ENTER_FUNCTION;
207 va_start( ap, errormsg );
208
209 ferite_vwarning( script, errormsg, &ap );
210
211 va_end( ap );
212 FE_LEAVE_FUNCTION(NOWT);
213 }
214
215 /**
216 * @function ferite_get_error_log
217 * @declaration char *ferite_get_error_log( FeriteScript *script )
218 * @brief Get a null terminated string containing the error and warning logs on a script
219 * @param FeriteScript *script The script to get the errror logs from
220 * @return A null terminated string, you will need to ffree the string when done to prevent memory leak
221 */
ferite_get_error_log(FeriteScript * script)222 char *ferite_get_error_log( FeriteScript *script )
223 {
224 int err_size = 0, warn_size = 0;
225 char *msg, *err_ptr, *warn_ptr;
226
227 FE_ENTER_FUNCTION;
228 if( script->error )
229 err_ptr = ferite_buffer_get( script->error, &err_size );
230 else
231 err_ptr = fstrdup("");
232 if( script->warning )
233 warn_ptr = ferite_buffer_get( script->warning, &warn_size );
234 else
235 warn_ptr = fstrdup("");
236 msg = fmalloc( err_size + warn_size + 1 );
237 strcpy( msg, warn_ptr );
238 strcat( msg, err_ptr );
239 ffree( err_ptr );
240 ffree( warn_ptr );
241 FE_LEAVE_FUNCTION( msg );
242 }
243
244 /**
245 * @function ferite_get_error_string
246 * @declaration char *ferite_get_error_string( FeriteScript *script )
247 * @brief Get a null terminated string containing the error log
248 * @param FeriteScript *script The script whose errors are required
249 * @return A null terminated string, you will need to ffree the string when done to prevent memory leak
250 */
ferite_get_error_string(FeriteScript * script)251 char *ferite_get_error_string( FeriteScript *script )
252 {
253 char *msg;
254 FE_ENTER_FUNCTION;
255 if( script->error )
256 msg = ferite_buffer_get( script->error, NULL );
257 else
258 msg = fstrdup("");
259 FE_LEAVE_FUNCTION( msg );
260 }
261
262 /**
263 * @function ferite_get_warning_string
264 * @declaration char *ferite_get_warning_string( FeriteScript *script )
265 * @brief Get a null terminated string containing the warning log
266 * @param FeriteScript *script The script whose warnings are required
267 * @return A null terminated string, you will need to ffree the string when done to prevent memory leak
268 */
ferite_get_warning_string(FeriteScript * script)269 char *ferite_get_warning_string( FeriteScript *script )
270 {
271 char *msg;
272 FE_ENTER_FUNCTION;
273 if( script->warning )
274 msg = ferite_buffer_get( script->warning, NULL );
275 else
276 msg = fstrdup("");
277 FE_LEAVE_FUNCTION( msg );
278 }
279
280 /**
281 * @function ferite_reset_warnings
282 * @declaration void ferite_reset_warnings( FeriteScript *script )
283 * @brief Reset any warnings on the script
284 * @param FeriteScript *script The script to check
285 */
ferite_reset_warnings(FeriteScript * script)286 void ferite_reset_warnings( FeriteScript *script )
287 {
288 FE_ENTER_FUNCTION;
289 if( script->warning != NULL )
290 {
291 ferite_buffer_delete( script->warning );
292 script->warning = NULL;
293 }
294 FE_LEAVE_FUNCTION(NOWT);
295 }
296
297 /**
298 * @function ferite_reset_errors
299 * @declaration void ferite_reset_errors( FeriteScript *script )
300 * @brief Reset any errors on the script
301 * @param FeriteScript *script The script to check
302 */
ferite_reset_errors(FeriteScript * script)303 void ferite_reset_errors( FeriteScript *script )
304 {
305 FE_ENTER_FUNCTION;
306 if( script->error != NULL )
307 {
308 ferite_buffer_delete( script->error );
309 script->error = NULL;
310 script->error_state = 0;
311 }
312 FE_LEAVE_FUNCTION(NOWT);
313 }
314
315 /**
316 * @function ferite_has_compile_error
317 * @declaration int ferite_has_compile_error( FeriteScript *script )
318 * @brief Check to see if the script has had a compilation error
319 * @param FeriteScript *script The script to check
320 * @return FE_TRUE if a compilation error occured, FE_FALSE otherwise
321 */
ferite_has_compile_error(FeriteScript * script)322 int ferite_has_compile_error( FeriteScript *script )
323 {
324 FE_ENTER_FUNCTION;
325 FE_LEAVE_FUNCTION( ( script->error == NULL ) ? FE_FALSE : FE_TRUE );
326 }
327
328 /**
329 * @function ferite_has_warnings
330 * @declaration int ferite_has_warnings( FeriteScript *script )
331 * @brief Check to see if the script has warnings
332 * @param FeriteScript *script The script to check
333 * @return FE_TRUE if there are warnings, FE_FALSE otherwise
334 */
ferite_has_warnings(FeriteScript * script)335 int ferite_has_warnings( FeriteScript *script )
336 {
337 FE_ENTER_FUNCTION;
338 FE_LEAVE_FUNCTION( (script->warning == NULL) ? FE_FALSE : FE_TRUE );
339 }
340
341 /**
342 * @function ferite_has_runtime_error
343 * @declaration int ferite_has_runtime_error( FeriteScript *script )
344 * @brief Check to see if the script has had a runtime error
345 * @param FeriteScript *script The script to check
346 * @return FE_TRUE if a compilation error occured, FE_FALSE otherwise
347 */
ferite_has_runtime_error(FeriteScript * script)348 int ferite_has_runtime_error( FeriteScript *script )
349 {
350 FE_ENTER_FUNCTION;
351 FE_LEAVE_FUNCTION( ( script->error_state == FE_ERROR_THROWN ) ? FE_TRUE : FE_FALSE );
352 }
353
354 /**
355 * @function ferite_init_error_system
356 * @declaration void ferite_init_error_system( FeriteScript *script, FeriteNamespace *ns )
357 * @brief Setup the special error handling class on a script
358 * @param FeriteScript *script The current script
359 * @param FeriteNamespace *ns The namespace in which the class should be registered
360 */
ferite_init_error_system(FeriteScript * script,FeriteNamespace * ns)361 void ferite_init_error_system( FeriteScript *script, FeriteNamespace *ns )
362 {
363 FeriteClass *ferite_error_class = NULL;
364 FeriteVariable *var, *errobj = NULL;
365 FeriteNamespaceBucket *nsb = NULL;
366
367 FE_ENTER_FUNCTION;
368 ferite_error_class = ferite_register_class( script, ns, "Error" );
369 ferite_register_class_variable( script, ferite_error_class, ferite_create_number_long_variable( script, "num", 0, FE_STATIC ), 0 );
370 ferite_register_class_variable( script, ferite_error_class, ferite_create_string_variable( script, "str", NULL, FE_STATIC ), 0 );
371
372 nsb = ferite_find_namespace( script, script->mainns, "err", FENS_VAR );
373 if( nsb != NULL )
374 {
375 errobj = ferite_build_object( script, ferite_error_class );
376 var = nsb->data;
377 VAO(var) = VAO(errobj);
378 VAO(errobj) = NULL;
379 ferite_variable_destroy( script, errobj );
380 }
381
382 FE_LEAVE_FUNCTION(NOWT);
383 }
384
385 /**
386 * @function ferite_set_error
387 * @declaration void ferite_set_error( FeriteScript *script, int num, char *fmt, ... )
388 * @brief Same as ferite_error except this wont raise an exception at runtime
389 */
ferite_set_error(FeriteScript * script,int num,char * fmt,...)390 void ferite_set_error( FeriteScript *script, int num, char *fmt, ... )
391 {
392 FeriteNamespaceBucket *nsb = NULL;
393 FeriteVariable *gerr = NULL, *newError = NULL;
394 FeriteVariable *errstr = NULL, *erno = NULL;
395 va_list ap;
396 char *buf = NULL;
397
398 FE_ENTER_FUNCTION;
399
400 if( !script->is_being_deleted && (script->parent == NULL || !script->parent->is_being_deleted) )
401 {
402 buf = fmalloc( 4096 );
403 va_start( ap, fmt );
404 vsprintf( buf, fmt, ap );
405
406 nsb = ferite_namespace_element_exists( script, script->mainns, "err" );
407 FE_ASSERT( nsb && nsb->type == FENS_VAR );
408 gerr = nsb->data;
409
410 if( VAO(gerr) == NULL )
411 {
412 nsb = ferite_namespace_element_exists( script, script->mainns, "Error" );
413 newError = ferite_new_object( script, nsb->data, NULL );
414 VAO(gerr) = VAO(newError);
415 VAO(gerr)->refcount++;
416 ferite_variable_destroy( script, newError );
417 }
418
419 errstr = ferite_object_get_var( script, VAO(gerr), "str" );
420 ferite_str_set( VAS(errstr), buf, strlen(buf), FE_CHARSET_DEFAULT );
421
422 erno = ferite_object_get_var( script, VAO(gerr), "num" );
423 VAI(erno) = num;
424
425 ffree( buf );
426 va_end( ap );
427 }
428 FE_LEAVE_FUNCTION( NOWT );
429 }
430 /* This function will never return, set ferite_assert_debug to generate
431 * a segfault to get a backtrace */
432 int ferite_assert_debug = 0;
ferite_assert(char * fmt,...)433 void ferite_assert( char *fmt, ... )
434 {
435 char *p = NULL;
436 va_list ap;
437 va_start( ap, fmt );
438 ferite_vwarning( NULL, fmt, &ap );
439 va_end( ap );
440 if( ferite_assert_debug )
441 *p = '\0';
442 exit( -1 );
443 }
444
445 /**
446 * @end
447 */
448