1 /* error handling common to all routines. */
3 Copyright (C) 2004, 2005, 2006 John E. Davis
5 This file is part of the S-Lang Library.
7 The S-Lang Library is free software; you can redistribute it and/or
8 modify it under the terms of the GNU General Public License as
9 published by the Free Software Foundation; either version 2 of the
10 License, or (at your option) any later version.
12 The S-Lang Library is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 General Public License for more details.
17 You should have received a copy of the GNU General Public License
18 along with this library; if not, write to the Free Software
19 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
28 void (*_pSLinterpreter_Error_Hook
) (int);
30 void (*SLang_VMessage_Hook
) (char *, va_list);
31 void (*SLang_Error_Hook
)(char *);
32 void (*SLang_Exit_Error_Hook
)(char *, va_list);
33 void (*SLang_Dump_Routine
)(char *);
35 volatile int _pSLang_Error
= 0;
36 volatile int SLKeyBoard_Quit
= 0;
38 typedef struct _Exception_Type Exception_Type
;
39 struct _Exception_Type
44 Exception_Type
*subclasses
;
46 Exception_Type
*parent
;
49 static Exception_Type
*Exception_Root
;
50 static Exception_Type Exception_Root_Buf
=
52 -1, "AnyError", "All Errors", NULL
, NULL
, NULL
56 /* Built-in error codes */
57 /* These values should correspond to the values produced by _pSLerr_init.
58 * Some apps may not use the interpreter, and as such _pSLerr_init will not
61 int SL_Any_Error
= -1;
62 int SL_Unknown_Error
= 6;
63 int SL_Internal_Error
= 5;
65 int SL_Malloc_Error
= 2;
66 int SL_Import_Error
= 7;
67 int SL_RunTime_Error
= 3;
68 int SL_InvalidParm_Error
= 4;
69 int SL_TypeMismatch_Error
= 8;
70 int SL_UserBreak_Error
= 9;
71 int SL_Stack_Error
= 10;
72 int SL_StackOverflow_Error
= 12;
73 int SL_StackUnderflow_Error
= 11;
74 int SL_ReadOnly_Error
= 13;
75 int SL_VariableUninitialized_Error
= 14;
76 int SL_NumArgs_Error
= 15;
77 int SL_Index_Error
= 16;
78 int SL_Usage_Error
= 17;
79 int SL_Application_Error
= 18;
80 int SL_NotImplemented_Error
= 19;
81 int SL_LimitExceeded_Error
= 20;
82 int SL_Forbidden_Error
= 21;
83 int SL_Math_Error
= 22;
84 int SL_DivideByZero_Error
= 23;
85 int SL_ArithOverflow_Error
= 24;
86 int SL_ArithUnderflow_Error
= 25;
87 int SL_Domain_Error
= 26;
89 int SL_Write_Error
= 28;
90 int SL_Read_Error
= 29;
91 int SL_Open_Error
= 30;
92 int SL_Data_Error
= 31;
93 int SL_Unicode_Error
= 32;
94 int SL_InvalidUTF8_Error
= 33;
95 int SL_Namespace_Error
= 34;
96 int SL_Parse_Error
= 35;
97 int SL_Syntax_Error
= 36;
98 int SL_DuplicateDefinition_Error
= 37;
99 int SL_UndefinedName_Error
= 38;
108 BuiltIn_Exception_Table_Type
;
110 static SLCONST BuiltIn_Exception_Table_Type BuiltIn_Exception_Table
[] =
112 /* Define MallocError and InvalidParmError ASAP */
113 {&SL_OS_Error
, "OSError", "OS Error", &SL_Any_Error
},
114 {&SL_Malloc_Error
, "MallocError", "Not enough memory", &SL_OS_Error
},
116 {&SL_RunTime_Error
, "RunTimeError", "Run-Time Error", &SL_Any_Error
},
117 {&SL_InvalidParm_Error
, "InvalidParmError", "Invalid Parameter", &SL_RunTime_Error
},
119 {&SL_Internal_Error
, "InternalError", "Internal Error", &SL_Any_Error
},
120 {&SL_Unknown_Error
, "UnknownError", "Unknown Error", &SL_Any_Error
},
122 /* Rest of OSErrors */
123 {&SL_Import_Error
, "ImportError", "Import Error", &SL_OS_Error
},
125 /* Rest of RunTimeErrors */
126 {&SL_TypeMismatch_Error
, "TypeMismatchError", "Type Mismatch", &SL_RunTime_Error
},
127 {&SL_UserBreak_Error
, "UserBreakError", "User Break", &SL_RunTime_Error
},
128 {&SL_Stack_Error
, "StackError", "Stack Error", &SL_RunTime_Error
},
129 {&SL_StackUnderflow_Error
, "StackUnderflowError", "Stack Underflow Error", &SL_Stack_Error
},
130 {&SL_StackOverflow_Error
, "StackOverflowError", "Stack Overflow Error", &SL_Stack_Error
},
131 {&SL_ReadOnly_Error
, "ReadOnlyError", "Read-Only Error", &SL_RunTime_Error
},
132 {&SL_VariableUninitialized_Error
, "VariableUninitializedError", "Variable Uninitialized Error", &SL_RunTime_Error
},
133 {&SL_NumArgs_Error
, "NumArgsError", "Invalid Number of Arguments", &SL_RunTime_Error
},
134 {&SL_Index_Error
, "IndexError", "Invalid Index", &SL_RunTime_Error
},
135 {&SL_Usage_Error
, "UsageError", "Illegal Usage", &SL_RunTime_Error
},
136 {&SL_Application_Error
, "ApplicationError", "Application Error", &SL_RunTime_Error
},
137 {&SL_NotImplemented_Error
, "NotImplementedError", "Not Implemented", &SL_RunTime_Error
},
138 {&SL_LimitExceeded_Error
, "LimitExceededError", "Limit Exceeded", &SL_RunTime_Error
},
139 {&SL_Forbidden_Error
, "ForbiddenError", "Operation Forbidden", &SL_RunTime_Error
},
140 {&SL_Math_Error
, "MathError", "Math Error", &SL_RunTime_Error
},
141 {&SL_DivideByZero_Error
, "DivideByZeroError", "Divide by Zero", &SL_Math_Error
},
142 {&SL_ArithOverflow_Error
, "ArithOverflowError", "Arithmetic Overflow", &SL_Math_Error
},
143 {&SL_ArithUnderflow_Error
, "ArithUnderflowError", "Arithmetic Underflow", &SL_Math_Error
},
144 {&SL_Domain_Error
, "DomainError", "Domain Error", &SL_Math_Error
},
145 {&SL_IO_Error
, "IOError", "I/O Error", &SL_RunTime_Error
},
146 {&SL_Write_Error
, "WriteError", "Write failed", &SL_IO_Error
},
147 {&SL_Read_Error
, "ReadError", "Read failed", &SL_IO_Error
},
148 {&SL_Open_Error
, "OpenError", "Open failed", &SL_IO_Error
},
149 {&SL_Data_Error
, "DataError", "Data Error", &SL_RunTime_Error
},
150 {&SL_Unicode_Error
, "UnicodeError", "Unicode Error", &SL_RunTime_Error
},
151 {&SL_InvalidUTF8_Error
, "UTF8Error", "Invalid UTF8", &SL_Unicode_Error
},
152 {&SL_Namespace_Error
, "NamespaceError", "Namespace Error", &SL_RunTime_Error
},
155 {&SL_Parse_Error
, "ParseError", "Parse Error", &SL_Any_Error
},
156 {&SL_Syntax_Error
, "SyntaxError", "Syntax Error", &SL_Parse_Error
},
157 {&SL_DuplicateDefinition_Error
, "DuplicateDefinitionError", "Duplicate Definition", &SL_Parse_Error
},
158 {&SL_UndefinedName_Error
, "UndefinedNameError", "Undefined Name", &SL_Parse_Error
},
159 {NULL
, NULL
, NULL
, NULL
}
162 static Exception_Type
*find_exception (Exception_Type
*root
, int error_code
)
168 if (error_code
== root
->error_code
)
171 if (root
->subclasses
!= NULL
)
173 e
= find_exception (root
->subclasses
, error_code
);
183 static int is_exception_ancestor (int a
, int b
)
190 if (NULL
== (e
= find_exception (Exception_Root
, a
)))
193 while (e
->parent
!= NULL
)
196 if (e
->error_code
== b
)
202 int SLerr_exception_eqs (int a
, int b
)
204 if (is_exception_ancestor (a
, b
))
210 static void free_this_exception (Exception_Type
*e
)
216 SLang_free_slstring (e
->name
);
218 if (e
->description
!= NULL
)
219 SLang_free_slstring (e
->description
);
225 static int Next_Exception_Code
;
226 /* The whole point of this nonsense involving the _pSLerr_New_Exception_Hook
227 * is to provide a mechanism to avoid linking in the interpreter for apps
228 * that just want the other facilities.
230 int (*_pSLerr_New_Exception_Hook
)(char *name
, char *desc
, int error_code
);
232 int _pSLerr_init_interp_exceptions (void)
234 SLCONST BuiltIn_Exception_Table_Type
*b
;
237 if (_pSLerr_New_Exception_Hook
== NULL
)
240 e
= &Exception_Root_Buf
;
241 if (-1 == (*_pSLerr_New_Exception_Hook
)(e
->name
, e
->description
, e
->error_code
))
244 b
= BuiltIn_Exception_Table
;
245 while (b
->errcode_ptr
!= NULL
)
247 if (-1 == (*_pSLerr_New_Exception_Hook
)(b
->name
, b
->description
, *b
->errcode_ptr
))
255 int SLerr_new_exception (int baseclass
, char *name
, char *descript
)
257 Exception_Type
*base
;
260 if (-1 == _pSLerr_init ())
263 base
= find_exception (Exception_Root
, baseclass
);
266 SLang_verror (SL_InvalidParm_Error
,
267 "Base class for new exception not found");
271 e
= (Exception_Type
*) SLcalloc (1, sizeof (Exception_Type
));
275 if ((NULL
== (e
->name
= SLang_create_slstring (name
)))
276 || (NULL
== (e
->description
= SLang_create_slstring (descript
))))
278 free_this_exception (e
);
282 e
->error_code
= Next_Exception_Code
;
284 if ((_pSLerr_New_Exception_Hook
!= NULL
)
285 && (-1 == (*_pSLerr_New_Exception_Hook
) (e
->name
, e
->description
, e
->error_code
)))
287 free_this_exception (e
);
292 e
->next
= base
->subclasses
;
293 base
->subclasses
= e
;
295 Next_Exception_Code
++;
296 return e
->error_code
;
300 static int init_exceptions (void)
302 SLCONST BuiltIn_Exception_Table_Type
*b
;
304 if (Exception_Root
!= NULL
)
307 Exception_Root
= &Exception_Root_Buf
;
308 Next_Exception_Code
= 1;
309 b
= BuiltIn_Exception_Table
;
310 while (b
->errcode_ptr
!= NULL
)
314 err_code
= SLerr_new_exception (*b
->base_class_ptr
, b
->name
, b
->description
);
318 *b
->errcode_ptr
= err_code
;
325 static void free_exceptions (Exception_Type
*root
)
329 Exception_Type
*next
;
331 if (root
->subclasses
!= NULL
)
332 free_exceptions (root
->subclasses
);
335 free_this_exception (root
);
341 static void deinit_exceptions (void)
343 Exception_Type
*root
= Exception_Root
;
346 free_exceptions (root
->subclasses
);
348 Exception_Root
= NULL
;
349 Next_Exception_Code
= 0;
352 char *SLerr_strerror (int err_code
)
357 err_code
= _pSLang_Error
;
359 if (-1 == _pSLerr_init ())
360 return "Unable to initialize SLerr module";
362 if (NULL
== (e
= find_exception (Exception_Root
, err_code
)))
363 return "Invalid/Unknown Error Code";
365 return e
->description
;
368 /* Error Queue Functions
369 * SLang_verror (int errcode, fmt, args)
370 * Add an error message to the queue.
371 * SLerr_delete_queue ()
372 * Removes messages from the error queue
373 * SLerr_print_queue ()
374 * Prints all messages from the queue, deletes the queue
376 typedef struct _Error_Message_Type
378 char *msg
; /* SLstring, may be NULL */
380 #define _SLERR_MSG_ERROR 1
381 #define _SLERR_MSG_WARNING 2
382 #define _SLERR_MSG_TRACEBACK 4
383 struct _Error_Message_Type
*next
;
389 Error_Message_Type
*head
;
390 Error_Message_Type
*tail
;
394 static Error_Queue_Type
*Default_Error_Queue
;
396 static void free_error_msg (Error_Message_Type
*m
)
401 SLang_free_slstring (m
->msg
);
405 static Error_Message_Type
*allocate_error_msg (char *msg
, int msg_type
)
407 Error_Message_Type
*m
;
409 if (NULL
== (m
= (Error_Message_Type
*) SLcalloc (1, sizeof (Error_Message_Type
))))
412 if ((NULL
!= msg
) && (NULL
== (m
->msg
= SLang_create_slstring (msg
))))
417 m
->msg_type
= msg_type
;
421 static void free_queued_messages (Error_Queue_Type
*q
)
423 Error_Message_Type
*m
;
431 Error_Message_Type
*m1
= m
->next
;
439 static void delete_msg_queue (Error_Queue_Type
*q
)
444 free_queued_messages (q
);
449 static Error_Queue_Type
*create_msg_queue (void)
453 if (NULL
== (q
= (Error_Queue_Type
*)SLcalloc (1, sizeof(Error_Queue_Type
))))
459 static int queue_message (Error_Queue_Type
*q
, char *msg
, int msg_type
)
461 Error_Message_Type
*m
;
463 if (NULL
== (m
= allocate_error_msg (msg
, msg_type
)))
475 static void print_error (int msg_type
, char *err
)
481 case _SLERR_MSG_ERROR
:
482 if (SLang_Error_Hook
!= NULL
)
484 (*SLang_Error_Hook
)(err
);
488 case _SLERR_MSG_TRACEBACK
:
489 case _SLERR_MSG_WARNING
:
490 if (SLang_Dump_Routine
!= NULL
)
492 (*SLang_Dump_Routine
)(err
);
503 if ((err
[len
-1] != '\n')
504 && (msg_type
!= _SLERR_MSG_TRACEBACK
))
510 static void print_queue (void)
512 if (-1 == _pSLerr_init ())
513 print_error (_SLERR_MSG_ERROR
, "Unable to initialize SLerr module");
515 if (_pSLang_Error
== 0)
518 if (Default_Error_Queue
!= NULL
)
520 Error_Queue_Type
*q
= Default_Error_Queue
;
521 Error_Message_Type
*m
= q
->head
;
524 Error_Message_Type
*m_next
= m
->next
;
526 print_error (m
->msg_type
, m
->msg
);
530 free_queued_messages (q
);
533 if (_pSLang_Error
!= SL_Usage_Error
)
535 print_error (_SLERR_MSG_ERROR
, SLerr_strerror (_pSLang_Error
));
540 /* This function returns a pointer to the first error message in the queue.
541 * Make no attempts to free the returned pointer.
543 char *_pSLerr_get_error_from_queue (void)
546 Error_Message_Type
*m
;
548 char *err
, *err1
, *err_max
;
550 if (NULL
== (q
= Default_Error_Queue
))
557 if (m
->msg_type
== _SLERR_MSG_ERROR
)
558 len
+= 1 + strlen (m
->msg
);
564 len
--; /* last \n not needed */
566 if (NULL
== (err
= _pSLallocate_slstring (len
)))
574 if (m
->msg_type
== _SLERR_MSG_ERROR
)
576 unsigned int dlen
= strlen (m
->msg
);
577 strcpy (err1
, m
->msg
);
586 return _pSLcreate_via_alloced_slstring (err
, len
);
589 void _pSLerr_print_message_queue (void)
595 static volatile int Suspend_Error_Messages
= 0;
596 int _pSLerr_resume_messages (void)
598 if (Suspend_Error_Messages
== 0)
601 Suspend_Error_Messages
--;
602 if (Suspend_Error_Messages
== 0)
607 int _pSLerr_suspend_messages (void)
609 Suspend_Error_Messages
++;
613 void _pSLerr_free_queued_messages (void)
615 free_queued_messages (Default_Error_Queue
);
619 void SLang_verror (int err_code
, char *fmt
, ...)
624 if (-1 == _pSLerr_init ())
631 err_code
= SL_INTRINSIC_ERROR
;
633 if (_pSLang_Error
== 0)
634 SLang_set_error (err_code
);
640 (void) SLvsnprintf (err
, sizeof (err
), fmt
, ap
);
643 if (Suspend_Error_Messages
)
644 (void) queue_message (Default_Error_Queue
, err
, _SLERR_MSG_ERROR
);
646 print_error (_SLERR_MSG_ERROR
, err
);
649 int _pSLerr_traceback_msg (char *fmt
, ...)
655 (void) SLvsnprintf (msg
, sizeof (msg
), fmt
, ap
);
658 return queue_message (Default_Error_Queue
, msg
, _SLERR_MSG_TRACEBACK
);
661 void SLang_exit_error (char *fmt
, ...)
667 if (SLang_Exit_Error_Hook
!= NULL
)
669 (*SLang_Exit_Error_Hook
) (fmt
, ap
);
675 vfprintf (stderr
, fmt
, ap
);
676 fputs ("\n", stderr
);
684 int SLang_set_error (int error
)
686 /* Only allow an error to be cleared (error==0), but not changed
687 * if there already is an error.
690 || (_pSLang_Error
== 0))
691 _pSLang_Error
= error
;
693 if (_pSLinterpreter_Error_Hook
!= NULL
)
694 (*_pSLinterpreter_Error_Hook
) (_pSLang_Error
);
699 int SLang_get_error (void)
701 return _pSLang_Error
;
704 void SLang_vmessage (char *fmt
, ...)
713 if (SLang_VMessage_Hook
!= NULL
)
714 (*SLang_VMessage_Hook
) (fmt
, ap
);
717 vfprintf (stdout
, fmt
, ap
);
718 fputs ("\n", stdout
);
724 /* This routine does not queue messages. It is used for tracing, etc. */
725 void _pSLerr_dump_msg (char *fmt
, ...)
731 if (SLang_Dump_Routine
!= NULL
)
733 (void) SLvsnprintf (buf
, sizeof (buf
), fmt
, ap
);
734 (*SLang_Dump_Routine
) (buf
);
738 vfprintf (stderr
, fmt
, ap
);
744 int _pSLerr_init (void)
746 if (Default_Error_Queue
== NULL
)
748 Suspend_Error_Messages
= 0;
749 if (NULL
== (Default_Error_Queue
= create_msg_queue ()))
753 if (-1 == init_exceptions ())
759 void _pSLerr_deinit (void)
761 deinit_exceptions ();
762 delete_msg_queue (Default_Error_Queue
);
763 Suspend_Error_Messages
= 0;
764 Default_Error_Queue
= NULL
;