* io.c (rb_open_file): encoding in mode string was ignored if perm is
[ruby-svn.git] / eval_error.c
blob622ae4fdd980450c418402d53fb2964d4b5bcfbf
1 /* -*-c-*- */
2 /*
3 * included by eval.c
4 */
6 static void
7 warn_printf(const char *fmt, ...)
9 char buf[BUFSIZ];
10 va_list args;
12 va_init_list(args, fmt);
13 vsnprintf(buf, BUFSIZ, fmt, args);
14 va_end(args);
15 rb_write_error(buf);
18 #define warn_print(x) rb_write_error(x)
19 #define warn_print2(x,l) rb_write_error2(x,l)
21 static void
22 error_pos(void)
24 const char *sourcefile = rb_sourcefile();
25 int sourceline = rb_sourceline();
27 if (sourcefile) {
28 if (sourceline == 0) {
29 warn_printf("%s", sourcefile);
31 else if (rb_frame_callee()) {
32 warn_printf("%s:%d:in `%s'", sourcefile, sourceline,
33 rb_id2name(rb_frame_callee()));
35 else {
36 warn_printf("%s:%d", sourcefile, sourceline);
41 VALUE rb_check_backtrace(VALUE);
43 static VALUE
44 get_backtrace(VALUE info)
46 if (NIL_P(info))
47 return Qnil;
48 info = rb_funcall(info, rb_intern("backtrace"), 0);
49 if (NIL_P(info))
50 return Qnil;
51 return rb_check_backtrace(info);
54 VALUE
55 rb_get_backtrace(VALUE info)
57 return get_backtrace(info);
60 static void
61 set_backtrace(VALUE info, VALUE bt)
63 rb_funcall(info, rb_intern("set_backtrace"), 1, bt);
66 static void
67 error_print(void)
69 VALUE errat = Qnil; /* OK */
70 VALUE errinfo = GET_THREAD()->errinfo;
71 volatile VALUE eclass, e;
72 const char *einfo;
73 long elen;
75 if (NIL_P(errinfo))
76 return;
78 PUSH_TAG();
79 if (EXEC_TAG() == 0) {
80 errat = get_backtrace(errinfo);
82 else {
83 errat = Qnil;
85 if (EXEC_TAG())
86 goto error;
87 if (NIL_P(errat)) {
88 const char *file = rb_sourcefile();
89 int line = rb_sourceline();
90 if (file)
91 warn_printf("%s:%d", file, line);
92 else
93 warn_printf("%d", line);
95 else if (RARRAY_LEN(errat) == 0) {
96 error_pos();
98 else {
99 VALUE mesg = RARRAY_PTR(errat)[0];
101 if (NIL_P(mesg))
102 error_pos();
103 else {
104 warn_print2(RSTRING_PTR(mesg), RSTRING_LEN(mesg));
108 eclass = CLASS_OF(errinfo);
109 if (EXEC_TAG() == 0) {
110 e = rb_funcall(errinfo, rb_intern("message"), 0, 0);
111 StringValue(e);
112 einfo = RSTRING_PTR(e);
113 elen = RSTRING_LEN(e);
115 else {
116 einfo = "";
117 elen = 0;
119 if (EXEC_TAG())
120 goto error;
121 if (eclass == rb_eRuntimeError && elen == 0) {
122 warn_print(": unhandled exception\n");
124 else {
125 VALUE epath;
127 epath = rb_class_name(eclass);
128 if (elen == 0) {
129 warn_print(": ");
130 warn_print2(RSTRING_PTR(epath), RSTRING_LEN(epath));
131 warn_print("\n");
133 else {
134 char *tail = 0;
135 long len = elen;
137 if (RSTRING_PTR(epath)[0] == '#')
138 epath = 0;
139 if ((tail = memchr(einfo, '\n', elen)) != 0) {
140 len = tail - einfo;
141 tail++; /* skip newline */
143 warn_print(": ");
144 warn_print2(einfo, len);
145 if (epath) {
146 warn_print(" (");
147 warn_print2(RSTRING_PTR(epath), RSTRING_LEN(epath));
148 warn_print(")\n");
150 if (tail) {
151 warn_print2(tail, elen - len - 1);
152 if (einfo[elen-1] != '\n') warn_print2("\n", 1);
157 if (!NIL_P(errat)) {
158 long i;
159 long len = RARRAY_LEN(errat);
160 VALUE *ptr = RARRAY_PTR(errat);
161 int skip = eclass == rb_eSysStackError;
163 #define TRACE_MAX (TRACE_HEAD+TRACE_TAIL+5)
164 #define TRACE_HEAD 8
165 #define TRACE_TAIL 5
167 for (i = 1; i < len; i++) {
168 if (TYPE(ptr[i]) == T_STRING) {
169 warn_printf("\tfrom %s\n", RSTRING_PTR(ptr[i]));
171 if (skip && i == TRACE_HEAD && len > TRACE_MAX) {
172 warn_printf("\t ... %ld levels...\n",
173 len - TRACE_HEAD - TRACE_TAIL);
174 i = len - TRACE_TAIL;
178 error:
179 POP_TAG();
182 void
183 ruby_error_print(void)
185 error_print();
188 void
189 rb_print_undef(VALUE klass, ID id, int scope)
191 const char *v;
193 switch (scope) {
194 default:
195 case NOEX_PUBLIC: v = ""; break;
196 case NOEX_PRIVATE: v = " private"; break;
197 case NOEX_PROTECTED: v = " protected"; break;
199 rb_name_error(id, "undefined%s method `%s' for %s `%s'", v,
200 rb_id2name(id),
201 (TYPE(klass) == T_MODULE) ? "module" : "class",
202 rb_class2name(klass));
205 static int
206 sysexit_status(VALUE err)
208 VALUE st = rb_iv_get(err, "status");
209 return NUM2INT(st);
212 static int
213 error_handle(int ex)
215 int status = EXIT_FAILURE;
216 rb_thread_t *th = GET_THREAD();
218 if (rb_thread_set_raised(th))
219 return EXIT_FAILURE;
220 switch (ex & TAG_MASK) {
221 case 0:
222 status = EXIT_SUCCESS;
223 break;
225 case TAG_RETURN:
226 error_pos();
227 warn_print(": unexpected return\n");
228 break;
229 case TAG_NEXT:
230 error_pos();
231 warn_print(": unexpected next\n");
232 break;
233 case TAG_BREAK:
234 error_pos();
235 warn_print(": unexpected break\n");
236 break;
237 case TAG_REDO:
238 error_pos();
239 warn_print(": unexpected redo\n");
240 break;
241 case TAG_RETRY:
242 error_pos();
243 warn_print(": retry outside of rescue clause\n");
244 break;
245 case TAG_THROW:
246 /* TODO: fix me */
247 error_pos();
248 warn_printf(": unexpected throw\n");
249 break;
250 case TAG_RAISE: {
251 VALUE errinfo = GET_THREAD()->errinfo;
252 if (rb_obj_is_kind_of(errinfo, rb_eSystemExit)) {
253 status = sysexit_status(errinfo);
255 else if (rb_obj_is_instance_of(errinfo, rb_eSignal)) {
256 /* no message when exiting by signal */
258 else {
259 error_print();
261 break;
263 case TAG_FATAL:
264 error_print();
265 break;
266 default:
267 rb_bug("Unknown longjmp status %d", ex);
268 break;
270 rb_thread_reset_raised(th);
271 return status;