00001
00002
00003
00004
00005
00006 static void
00007 warn_printf(const char *fmt, ...)
00008 {
00009 char buf[BUFSIZ];
00010 va_list args;
00011
00012 va_init_list(args, fmt);
00013 vsnprintf(buf, BUFSIZ, fmt, args);
00014 va_end(args);
00015 rb_write_error(buf);
00016 }
00017
00018 #define warn_print(x) rb_write_error(x)
00019 #define warn_print2(x,l) rb_write_error2(x,l)
00020
00021 static void
00022 error_pos(void)
00023 {
00024 const char *sourcefile = rb_sourcefile();
00025 int sourceline = rb_sourceline();
00026
00027 if (sourcefile) {
00028 if (sourceline == 0) {
00029 warn_printf("%s", sourcefile);
00030 }
00031 else if (rb_frame_callee()) {
00032 warn_printf("%s:%d:in `%s'", sourcefile, sourceline,
00033 rb_id2name(rb_frame_callee()));
00034 }
00035 else {
00036 warn_printf("%s:%d", sourcefile, sourceline);
00037 }
00038 }
00039 }
00040
00041 VALUE rb_check_backtrace(VALUE);
00042
00043 static VALUE
00044 get_backtrace(VALUE info)
00045 {
00046 if (NIL_P(info))
00047 return Qnil;
00048 info = rb_funcall(info, rb_intern("backtrace"), 0);
00049 if (NIL_P(info))
00050 return Qnil;
00051 return rb_check_backtrace(info);
00052 }
00053
00054 VALUE
00055 rb_get_backtrace(VALUE info)
00056 {
00057 return get_backtrace(info);
00058 }
00059
00060 static void
00061 set_backtrace(VALUE info, VALUE bt)
00062 {
00063 rb_funcall(info, rb_intern("set_backtrace"), 1, bt);
00064 }
00065
00066 static void
00067 error_print(void)
00068 {
00069 volatile VALUE errat = Qnil;
00070 rb_thread_t *th = GET_THREAD();
00071 VALUE errinfo = th->errinfo;
00072 int raised_flag = th->raised_flag;
00073 volatile VALUE eclass, e;
00074 const char *volatile einfo;
00075 volatile long elen;
00076
00077 if (NIL_P(errinfo))
00078 return;
00079 rb_thread_raised_clear(th);
00080
00081 PUSH_TAG();
00082 if (EXEC_TAG() == 0) {
00083 errat = get_backtrace(errinfo);
00084 }
00085 else {
00086 errat = Qnil;
00087 }
00088 if (EXEC_TAG())
00089 goto error;
00090 if (NIL_P(errat)) {
00091 const char *file = rb_sourcefile();
00092 int line = rb_sourceline();
00093 if (!file)
00094 warn_printf("%d", line);
00095 else if (!line)
00096 warn_printf("%s", file);
00097 else
00098 warn_printf("%s:%d", file, line);
00099 }
00100 else if (RARRAY_LEN(errat) == 0) {
00101 error_pos();
00102 }
00103 else {
00104 VALUE mesg = RARRAY_PTR(errat)[0];
00105
00106 if (NIL_P(mesg))
00107 error_pos();
00108 else {
00109 warn_print2(RSTRING_PTR(mesg), RSTRING_LEN(mesg));
00110 }
00111 }
00112
00113 eclass = CLASS_OF(errinfo);
00114 if (EXEC_TAG() == 0) {
00115 e = rb_funcall(errinfo, rb_intern("message"), 0, 0);
00116 StringValue(e);
00117 einfo = RSTRING_PTR(e);
00118 elen = RSTRING_LEN(e);
00119 }
00120 else {
00121 einfo = "";
00122 elen = 0;
00123 }
00124 if (EXEC_TAG())
00125 goto error;
00126 if (eclass == rb_eRuntimeError && elen == 0) {
00127 warn_print(": unhandled exception\n");
00128 }
00129 else {
00130 VALUE epath;
00131
00132 epath = rb_class_name(eclass);
00133 if (elen == 0) {
00134 warn_print(": ");
00135 warn_print2(RSTRING_PTR(epath), RSTRING_LEN(epath));
00136 warn_print("\n");
00137 }
00138 else {
00139 char *tail = 0;
00140 long len = elen;
00141
00142 if (RSTRING_PTR(epath)[0] == '#')
00143 epath = 0;
00144 if ((tail = memchr(einfo, '\n', elen)) != 0) {
00145 len = tail - einfo;
00146 tail++;
00147 }
00148 warn_print(": ");
00149 warn_print2(einfo, len);
00150 if (epath) {
00151 warn_print(" (");
00152 warn_print2(RSTRING_PTR(epath), RSTRING_LEN(epath));
00153 warn_print(")\n");
00154 }
00155 if (tail) {
00156 warn_print2(tail, elen - len - 1);
00157 if (einfo[elen-1] != '\n') warn_print2("\n", 1);
00158 }
00159 }
00160 }
00161
00162 if (!NIL_P(errat)) {
00163 long i;
00164 long len = RARRAY_LEN(errat);
00165 VALUE *ptr = RARRAY_PTR(errat);
00166 int skip = eclass == rb_eSysStackError;
00167
00168 #define TRACE_MAX (TRACE_HEAD+TRACE_TAIL+5)
00169 #define TRACE_HEAD 8
00170 #define TRACE_TAIL 5
00171
00172 for (i = 1; i < len; i++) {
00173 if (TYPE(ptr[i]) == T_STRING) {
00174 warn_printf("\tfrom %s\n", RSTRING_PTR(ptr[i]));
00175 }
00176 if (skip && i == TRACE_HEAD && len > TRACE_MAX) {
00177 warn_printf("\t ... %ld levels...\n",
00178 len - TRACE_HEAD - TRACE_TAIL);
00179 i = len - TRACE_TAIL;
00180 }
00181 }
00182 }
00183 error:
00184 POP_TAG();
00185 rb_thread_raised_set(th, raised_flag);
00186 }
00187
00188 void
00189 ruby_error_print(void)
00190 {
00191 error_print();
00192 }
00193
00194 void
00195 rb_print_undef(VALUE klass, ID id, int scope)
00196 {
00197 const char *v;
00198
00199 switch (scope) {
00200 default:
00201 case NOEX_PUBLIC: v = ""; break;
00202 case NOEX_PRIVATE: v = " private"; break;
00203 case NOEX_PROTECTED: v = " protected"; break;
00204 }
00205 rb_name_error(id, "undefined%s method `%s' for %s `%s'", v,
00206 rb_id2name(id),
00207 (TYPE(klass) == T_MODULE) ? "module" : "class",
00208 rb_class2name(klass));
00209 }
00210
00211 static int
00212 sysexit_status(VALUE err)
00213 {
00214 VALUE st = rb_iv_get(err, "status");
00215 return NUM2INT(st);
00216 }
00217
00218 static int
00219 error_handle(int ex)
00220 {
00221 int status = EXIT_FAILURE;
00222 rb_thread_t *th = GET_THREAD();
00223
00224 if (rb_threadptr_set_raised(th))
00225 return EXIT_FAILURE;
00226 switch (ex & TAG_MASK) {
00227 case 0:
00228 status = EXIT_SUCCESS;
00229 break;
00230
00231 case TAG_RETURN:
00232 error_pos();
00233 warn_print(": unexpected return\n");
00234 break;
00235 case TAG_NEXT:
00236 error_pos();
00237 warn_print(": unexpected next\n");
00238 break;
00239 case TAG_BREAK:
00240 error_pos();
00241 warn_print(": unexpected break\n");
00242 break;
00243 case TAG_REDO:
00244 error_pos();
00245 warn_print(": unexpected redo\n");
00246 break;
00247 case TAG_RETRY:
00248 error_pos();
00249 warn_print(": retry outside of rescue clause\n");
00250 break;
00251 case TAG_THROW:
00252
00253 error_pos();
00254 warn_printf(": unexpected throw\n");
00255 break;
00256 case TAG_RAISE: {
00257 VALUE errinfo = GET_THREAD()->errinfo;
00258 if (rb_obj_is_kind_of(errinfo, rb_eSystemExit)) {
00259 status = sysexit_status(errinfo);
00260 }
00261 else if (rb_obj_is_instance_of(errinfo, rb_eSignal)) {
00262
00263 }
00264 else {
00265 error_print();
00266 }
00267 break;
00268 }
00269 case TAG_FATAL:
00270 error_print();
00271 break;
00272 default:
00273 rb_bug("Unknown longjmp status %d", ex);
00274 break;
00275 }
00276 rb_threadptr_reset_raised(th);
00277 return status;
00278 }
00279