errors.c revision f1dc56632881fe4e5beed047580bf927679f3669
1/*********************************************************** 2Copyright 1991, 1992, 1993 by Stichting Mathematisch Centrum, 3Amsterdam, The Netherlands. 4 5 All Rights Reserved 6 7Permission to use, copy, modify, and distribute this software and its 8documentation for any purpose and without fee is hereby granted, 9provided that the above copyright notice appear in all copies and that 10both that copyright notice and this permission notice appear in 11supporting documentation, and that the names of Stichting Mathematisch 12Centrum or CWI not be used in advertising or publicity pertaining to 13distribution of the software without specific, written prior permission. 14 15STICHTING MATHEMATISCH CENTRUM DISCLAIMS ALL WARRANTIES WITH REGARD TO 16THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND 17FITNESS, IN NO EVENT SHALL STICHTING MATHEMATISCH CENTRUM BE LIABLE 18FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 19WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 20ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT 21OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 22 23******************************************************************/ 24 25/* Error handling -- see also run.c */ 26 27/* New error handling interface. 28 29 The following problem exists (existed): methods of built-in modules 30 are called with 'self' and 'args' arguments, but without a context 31 argument, so they have no way to raise a specific exception. 32 The same is true for the object implementations: no context argument. 33 The old convention was to set 'errno' and to return NULL. 34 The caller (usually call_function() in eval.c) detects the NULL 35 return value and then calls puterrno(ctx) to turn the errno value 36 into a true exception. Problems with this approach are: 37 - it used standard errno values to indicate Python-specific errors, 38 but this means that when such an error code is reported by a system 39 call (e.g., in module posix), the user gets a confusing message 40 - errno is a global variable, which makes extensions to a multi- 41 threading environment difficult; e.g., in IRIX, multi-threaded 42 programs must use the function oserror() instead of looking in errno 43 - there is no portable way to add new error numbers for specic 44 situations -- the value space for errno is reserved to the OS, yet 45 the way to turn module-specific errors into a module-specific 46 exception requires module-specific values for errno 47 - there is no way to add a more situation-specific message to an 48 error. 49 50 The new interface solves all these problems. To return an error, a 51 built-in function calls err_set(exception), err_setval(exception, 52 value) or err_setstr(exception, string), and returns NULL. These 53 functions save the value for later use by puterrno(). To adapt this 54 scheme to a multi-threaded environment, only the implementation of 55 err_setval() has to be changed. 56*/ 57 58#include "allobjects.h" 59#include "modsupport.h" 60 61#include <errno.h> 62 63#include "errcode.h" 64 65extern char *strerror PROTO((int)); 66 67/* Last exception stored by err_setval() */ 68 69static object *last_exception; 70static object *last_exc_val; 71 72void 73err_setval(exception, value) 74 object *exception; 75 object *value; 76{ 77 XDECREF(last_exception); 78 XINCREF(exception); 79 last_exception = exception; 80 81 XDECREF(last_exc_val); 82 XINCREF(value); 83 last_exc_val = value; 84} 85 86void 87err_set(exception) 88 object *exception; 89{ 90 err_setval(exception, (object *)NULL); 91} 92 93void 94err_setstr(exception, string) 95 object *exception; 96 char *string; 97{ 98 object *value = newstringobject(string); 99 err_setval(exception, value); 100 XDECREF(value); 101} 102 103int 104err_occurred() 105{ 106 return last_exception != NULL; 107} 108 109void 110err_get(p_exc, p_val) 111 object **p_exc; 112 object **p_val; 113{ 114 *p_exc = last_exception; 115 last_exception = NULL; 116 *p_val = last_exc_val; 117 last_exc_val = NULL; 118} 119 120void 121err_clear() 122{ 123 XDECREF(last_exception); 124 last_exception = NULL; 125 XDECREF(last_exc_val); 126 last_exc_val = NULL; 127} 128 129/* Convenience functions to set a type error exception and return 0 */ 130 131int 132err_badarg() 133{ 134 err_setstr(TypeError, "illegal argument type for built-in operation"); 135 return 0; 136} 137 138object * 139err_nomem() 140{ 141 err_set(MemoryError); 142 return NULL; 143} 144 145object * 146err_errno(exc) 147 object *exc; 148{ 149 object *v; 150 if (errno == EINTR && intrcheck()) { 151 err_set(KeyboardInterrupt); 152 return NULL; 153 } 154 v = mkvalue("(is)", errno, strerror(errno)); 155 if (v != NULL) { 156 err_setval(exc, v); 157 DECREF(v); 158 } 159 return NULL; 160} 161 162void 163err_badcall() 164{ 165 err_setstr(SystemError, "bad argument to internal function"); 166} 167 168/* Set the error appropriate to the given input error code (see errcode.h) */ 169 170void 171err_input(err) 172 int err; 173{ 174 switch (err) { 175 case E_DONE: 176 case E_OK: 177 break; 178 case E_SYNTAX: 179 err_setstr(SyntaxError, "invalid syntax"); 180 break; 181 case E_TOKEN: 182 err_setstr(SyntaxError, "invalid token"); 183 break; 184 case E_INTR: 185 err_set(KeyboardInterrupt); 186 break; 187 case E_NOMEM: 188 err_nomem(); 189 break; 190 case E_EOF: 191 err_setstr(SyntaxError, "unexpected EOF while parsing"); 192 break; 193 default: 194 err_setstr(SystemError, "unknown parsing error"); 195 break; 196 } 197} 198