6#define write_warn(str, x) \
7 (NIL_P(str) ? warn_print(x) : (void)rb_str_cat_cstr(str, x))
8#define write_warn2(str, x, l) \
9 (NIL_P(str) ? warn_print2(x, l) : (void)rb_str_cat(str, x, l))
10#ifdef HAVE_BUILTIN___BUILTIN_CONSTANT_P
11#define warn_print(x) RB_GNUC_EXTENSION_BLOCK( \
12 (__builtin_constant_p(x)) ? \
13 rb_write_error2((x), (long)strlen(x)) : \
17#define warn_print(x) rb_write_error(x)
20#define warn_print2(x,l) rb_write_error2((x),(l))
22#define write_warn_str(str,x) NIL_P(str) ? rb_write_error_str(x) : (void)rb_str_concat((str), (x))
23#define warn_print_str(x) rb_write_error_str(x)
25static VALUE error_pos_str(
void);
28error_pos(
const VALUE str)
30 VALUE pos = error_pos_str();
32 write_warn_str(str, pos);
40 VALUE sourcefile = rb_source_location(&sourceline);
42 if (!
NIL_P(sourcefile)) {
44 if (sourceline == 0) {
45 return rb_sprintf(
"%"PRIsVALUE
": ", sourcefile);
48 return rb_sprintf(
"%"PRIsVALUE
":%d:in `%"PRIsVALUE
"': ",
49 sourcefile, sourceline,
53 return rb_sprintf(
"%"PRIsVALUE
":%d: ", sourcefile, sourceline);
60set_backtrace(VALUE info, VALUE bt)
62 ID set_backtrace =
rb_intern(
"set_backtrace");
64 if (rb_backtrace_p(bt)) {
66 rb_exc_set_backtrace(info, bt);
70 bt = rb_backtrace_to_str_ary(bt);
79 rb_ec_error_print(ec, ec->errinfo);
83write_warnq(VALUE out, VALUE str,
const char *ptr,
long len)
86 const char *beg = ptr;
87 const long olen = len;
88 for (; len > 0; --len, ++ptr) {
89 unsigned char c = *ptr;
91 case '\n':
case '\t':
continue;
98 cc = ruby_escaped_char(c);
106 else if (c ==
'\\') {
113 rb_write_error_str(str);
123#define CSI_BEGIN "\033["
126static const char underline[] = CSI_BEGIN
"1;4"CSI_SGR;
127static const char bold[] = CSI_BEGIN
"1"CSI_SGR;
128static const char reset[] = CSI_BEGIN
""CSI_SGR;
131print_errinfo(
const VALUE eclass,
const VALUE errat,
const VALUE emesg,
const VALUE str,
int highlight)
133 const char *einfo =
"";
143 write_warn_str(str, mesg);
144 write_warn(str,
": ");
153 if (eclass == rb_eRuntimeError && elen == 0) {
154 if (highlight) write_warn(str, underline);
155 write_warn(str,
"unhandled exception");
156 if (highlight) write_warn(str, reset);
157 write_warn2(str,
"\n", 1);
164 if (highlight) write_warn(str, underline);
165 write_warn_str(str, epath);
166 if (highlight) write_warn(str, reset);
167 write_warn(str,
"\n");
171 const char *tail = 0;
173 if (highlight) write_warn(str, bold);
176 if ((tail = memchr(einfo,
'\n', elen)) != 0) {
177 write_warnq(str, emesg, einfo, tail - einfo);
181 write_warnq(str, emesg, einfo, elen);
184 write_warn(str,
" (");
185 if (highlight) write_warn(str, underline);
186 write_warn_str(str, epath);
188 write_warn(str, reset);
189 write_warn(str, bold);
191 write_warn2(str,
")", 1);
192 if (highlight) write_warn(str, reset);
193 write_warn2(str,
"\n", 1);
195 if (tail && einfo+elen > tail) {
197 write_warnq(str, emesg, tail, einfo+elen-tail);
198 if (einfo[elen-1] !=
'\n') write_warn2(str,
"\n", 1);
201 elen -= tail - einfo;
204 tail = memchr(einfo,
'\n', elen);
205 if (!tail || tail > einfo) {
206 write_warn(str, bold);
207 write_warnq(str, emesg, einfo, tail ? tail-einfo : elen);
208 write_warn(str, reset);
210 write_warn2(str,
"\n", 1);
214 elen -= tail - einfo;
216 do ++tail;
while (tail < einfo+elen && *tail ==
'\n');
217 write_warnq(str, emesg, einfo, tail-einfo);
218 elen -= tail - einfo;
224 write_warn2(str,
"\n", 1);
231print_backtrace(
const VALUE eclass,
const VALUE errat,
const VALUE str,
int reverse,
long backtrace_limit)
236 const int threshold = 1000000000;
237 int width = (len <= 1) ? INT_MIN : ((
int)log10((
double)(len > threshold ?
238 ((len - 1) / threshold) :
240 (len < threshold ? 0 : 9) + 1);
242 long skip_start = -1, skip_len = 0;
248 long trace_max = trace_head + trace_tail + 5;
249 if (len > trace_max) {
250 skip_start = trace_head;
251 skip_len = len - trace_max + 5;
256 if (backtrace_limit >= 0 && len > backtrace_limit + 2) {
257 skip_start = backtrace_limit + 1;
258 skip_len = len - skip_start;
261 for (i = 1; i < len; i++) {
262 if (i == skip_start) {
263 write_warn_str(str,
rb_sprintf(
"\t ... %ld levels...\n", skip_len));
267 VALUE line =
RARRAY_AREF(errat, reverse ? len - i : i);
270 if (reverse)
rb_str_catf(bt,
"%*ld: ", width, len - i);
271 write_warn_str(str,
rb_str_catf(bt,
"from %"PRIsVALUE
"\n", line));
277VALUE rb_get_message(VALUE exc);
280shown_cause_p(VALUE cause, VALUE *shown_causes)
282 VALUE shown = *shown_causes;
284 *shown_causes = shown = rb_obj_hide(rb_ident_hash_new());
286 if (rb_hash_has_key(shown, cause))
return TRUE;
292show_cause(VALUE errinfo, VALUE str, VALUE highlight, VALUE reverse,
long backtrace_limit, VALUE *shown_causes)
295 if (!
NIL_P(cause) && rb_obj_is_kind_of(cause, rb_eException) &&
296 !shown_cause_p(cause, shown_causes)) {
297 volatile VALUE eclass =
CLASS_OF(cause);
298 VALUE errat = rb_get_backtrace(cause);
299 VALUE emesg = rb_get_message(cause);
301 show_cause(cause, str, highlight, reverse, backtrace_limit, shown_causes);
302 print_backtrace(eclass, errat, str, TRUE, backtrace_limit);
303 print_errinfo(eclass, errat, emesg, str, highlight!=0);
306 print_errinfo(eclass, errat, emesg, str, highlight!=0);
307 print_backtrace(eclass, errat, str, FALSE, backtrace_limit);
308 show_cause(cause, str, highlight, reverse, backtrace_limit, shown_causes);
314rb_error_write(VALUE errinfo, VALUE emesg, VALUE errat, VALUE str, VALUE highlight, VALUE reverse)
316 volatile VALUE eclass;
317 VALUE shown_causes = 0;
318 long backtrace_limit = rb_backtrace_length_limit;
328 if (
NIL_P(highlight)) {
329 VALUE tty = (
VALUE)rb_stderr_tty_p();
330 if (
NIL_P(highlight)) highlight = tty;
333 static const char traceback[] =
"Traceback "
334 "(most recent call last):\n";
336 char buff[
sizeof(traceback)+
sizeof(bold)+
sizeof(reset)-2], *p = buff;
337 const char *msg = traceback;
338 long len =
sizeof(traceback) - 1;
340#define APPEND(s, l) (memcpy(p, s, l), p += (l))
341 APPEND(bold,
sizeof(bold)-1);
342 APPEND(traceback, bold_part);
343 APPEND(reset,
sizeof(reset)-1);
344 APPEND(traceback + bold_part,
sizeof(traceback)-bold_part-1);
346 len = p - (msg = buff);
348 write_warn2(str, msg, len);
349 show_cause(errinfo, str, highlight, reverse, backtrace_limit, &shown_causes);
350 print_backtrace(eclass, errat, str, TRUE, backtrace_limit);
351 print_errinfo(eclass, errat, emesg, str, highlight!=0);
354 print_errinfo(eclass, errat, emesg, str, highlight!=0);
355 print_backtrace(eclass, errat, str, FALSE, backtrace_limit);
356 show_cause(errinfo, str, highlight, reverse, backtrace_limit, &shown_causes);
363 volatile uint8_t raised_flag = ec->raised_flag;
364 volatile VALUE errat =
Qundef;
365 volatile VALUE emesg =
Qundef;
366 volatile bool written =
false;
370 rb_ec_raised_clear(ec);
373 if (EC_EXEC_TAG() == TAG_NONE) {
374 errat = rb_get_backtrace(errinfo);
378 emesg = rb_get_message(errinfo);
387 ec->errinfo = errinfo;
388 rb_ec_raised_set(ec, raised_flag);
391#define undef_mesg_for(v, k) rb_fstring_lit("undefined"v" method `%1$s' for "k" `%2$s'")
392#define undef_mesg(v) ( \
394 undef_mesg_for(v, "module") : \
395 undef_mesg_for(v, "class"))
398rb_print_undef(VALUE klass, ID
id, rb_method_visibility_t visi)
402 switch (visi & METHOD_VISI_MASK) {
403 case METHOD_VISI_UNDEF:
404 case METHOD_VISI_PUBLIC: mesg = undef_mesg(
"");
break;
405 case METHOD_VISI_PRIVATE: mesg = undef_mesg(
" private");
break;
406 case METHOD_VISI_PROTECTED: mesg = undef_mesg(
" protected");
break;
409 rb_name_err_raise_str(mesg, klass,
ID2SYM(
id));
413rb_print_undef_str(VALUE klass, VALUE name)
416 rb_name_err_raise_str(undef_mesg(
""), klass, name);
419#define inaccessible_mesg_for(v, k) rb_fstring_lit("method `%1$s' for "k" `%2$s' is "v)
420#define inaccessible_mesg(v) ( \
422 inaccessible_mesg_for(v, "module") : \
423 inaccessible_mesg_for(v, "class"))
426rb_print_inaccessible(VALUE klass, ID
id, rb_method_visibility_t visi)
430 switch (visi & METHOD_VISI_MASK) {
431 case METHOD_VISI_UNDEF:
432 case METHOD_VISI_PUBLIC: mesg = inaccessible_mesg(
"");
break;
433 case METHOD_VISI_PRIVATE: mesg = inaccessible_mesg(
"private");
break;
434 case METHOD_VISI_PROTECTED: mesg = inaccessible_mesg(
"protected");
break;
437 rb_name_err_raise_str(mesg, klass,
ID2SYM(
id));
441sysexit_status(VALUE err)
447#define unknown_longjmp_status(status) \
448 rb_bug("Unknown longjmp status %d", status)
453 int status = EXIT_FAILURE;
455 if (rb_ec_set_raised(ec))
457 switch (ex & TAG_MASK) {
459 status = EXIT_SUCCESS;
464 warn_print(
"unexpected return\n");
468 warn_print(
"unexpected next\n");
472 warn_print(
"unexpected break\n");
476 warn_print(
"unexpected redo\n");
480 warn_print(
"retry outside of rescue clause\n");
485 warn_print(
"unexpected throw\n");
488 VALUE errinfo = ec->errinfo;
489 if (rb_obj_is_kind_of(errinfo, rb_eSystemExit)) {
490 status = sysexit_status(errinfo);
492 else if (rb_obj_is_instance_of(errinfo, rb_eSignal) &&
496 else if (rb_obj_is_kind_of(errinfo, rb_eSystemCallError) &&
501 rb_ec_error_print(ec, errinfo);
509 unknown_longjmp_status(ex);
512 rb_ec_reset_raised(ec);
static int rb_iscntrl(int c)
Our own locale-insensitive version of iscntrl(3).
#define T_STRING
Old name of RUBY_T_STRING.
#define Qundef
Old name of RUBY_Qundef.
#define INT2FIX
Old name of RB_INT2FIX.
#define UNREACHABLE
Old name of RBIMPL_UNREACHABLE.
#define ID2SYM
Old name of RB_ID2SYM.
#define CLASS_OF
Old name of rb_class_of.
#define T_MODULE
Old name of RUBY_T_MODULE.
#define Qtrue
Old name of RUBY_Qtrue.
#define NUM2INT
Old name of RB_NUM2INT.
#define Qnil
Old name of RUBY_Qnil.
#define Qfalse
Old name of RUBY_Qfalse.
#define NIL_P
Old name of RB_NIL_P.
#define FIXNUM_P
Old name of RB_FIXNUM_P.
VALUE rb_eSysStackError
SystemStackError exception.
ID rb_frame_callee(void)
Identical to rb_frame_this_func(), except it returns the named used to call the method.
VALUE rb_hash_aset(VALUE hash, VALUE key, VALUE val)
Inserts or replaces ("upsert"s) the objects into the given hash table.
void rb_write_error2(const char *str, long len)
Identical to rb_write_error(), except it additionally takes the message's length.
VALUE rb_str_cat(VALUE dst, const char *src, long srclen)
Destructively appends the passed contents to the string.
#define rb_strlen_lit(str)
Length of a string literal.
VALUE rb_str_new_cstr(const char *ptr)
Identical to rb_str_new(), except it assumes the passed pointer is a pointer to a C string.
VALUE rb_attr_get(VALUE obj, ID name)
Identical to rb_ivar_get()
VALUE rb_ivar_get(VALUE obj, ID name)
Identical to rb_iv_get(), except it accepts the name as an ID instead of a C string.
VALUE rb_class_name(VALUE obj)
Queries the name of the given object's class.
int rb_method_basic_definition_p(VALUE klass, ID mid)
Well... Let us hesitate from describing what a "basic definition" is.
VALUE rb_check_funcall(VALUE recv, ID mid, int argc, const VALUE *argv)
Identical to rb_funcallv(), except it returns RUBY_Qundef instead of raising rb_eNoMethodError.
ID rb_intern(const char *name)
Finds or creates a symbol of the given name.
VALUE rb_id2str(ID id)
Identical to rb_id2name(), except it returns a Ruby's String instead of C's.
VALUE rb_sprintf(const char *fmt,...)
Ruby's extended sprintf(3).
VALUE rb_str_catf(VALUE dst, const char *fmt,...)
Identical to rb_sprintf(), except it renders the output to the specified object rather than creating ...
#define RARRAY_LEN
Just another name of rb_array_len.
#define RARRAY_AREF(a, i)
static long RSTRING_LEN(VALUE str)
Queries the length of the string.
static char * RSTRING_PTR(VALUE str)
Queries the contents pointer of the string.
uintptr_t VALUE
Type that represents a Ruby object.
static bool RB_TYPE_P(VALUE obj, enum ruby_value_type t)
Queries if the given object is of given type.