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