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