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