(linenum→info "unix/slp.c:2238")

ruby/1.9.0/error.c

    1: /**********************************************************************
    2: 
    3:   error.c -
    4: 
    5:   $Author: nobu $
    6:   $Date: 2007-12-25 11:37:40 +0900 (Tue, 25 Dec 2007) $
    7:   created at: Mon Aug  9 16:11:34 JST 1993
    8: 
    9:   Copyright (C) 1993-2007 Yukihiro Matsumoto
   10: 
   11: **********************************************************************/
   12: 
   13: #include "ruby/ruby.h"
   14: #include "ruby/st.h"
   15: #include "vm_core.h"
   16: 
   17: #include <stdio.h>
   18: #include <stdarg.h>
   19: #ifdef HAVE_STDLIB_H
   20: #include <stdlib.h>
   21: #endif
   22: #ifndef EXIT_SUCCESS
   23: #define EXIT_SUCCESS 0
   24: #endif
   25: 
   26: extern const char ruby_description[];
   27: 
   28: static int
   29: err_position_0(char *buf, long len, const char *file, int line)
   30: {
   31:     if (!file) {
   32:         return 0;
   33:     }
   34:     else if (line == 0) {
   35:         return snprintf(buf, len, "%s: ", file);
   36:     }
   37:     else {
   38:         return snprintf(buf, len, "%s:%d: ", file, line);
   39:     }
   40: }
   41: 
   42: static int
   43: err_position(char *buf, long len)
   44: {
   45:     return err_position_0(buf, len, rb_sourcefile(), rb_sourceline());
   46: }
   47: 
   48: static void
   49: err_snprintf(char *buf, long len, const char *fmt, va_list args)
   50: {
   51:     long n;
   52: 
   53:     n = err_position(buf, len);
   54:     if (len > n) {
   55:         vsnprintf((char*)buf+n, len-n, fmt, args);
   56:     }
   57: }
   58: 
   59: static void
   60: compile_snprintf(char *buf, long len, const char *file, int line, const char *fmt, va_list args)
   61: {
   62:     long n;
   63: 
   64:     n = err_position_0(buf, len, file, line);
   65:     if (len > n) {
   66:         vsnprintf((char*)buf+n, len-n, fmt, args);
   67:     }
   68: }
   69: 
   70: static void err_append(const char*);
   71: 
   72: void
   73: rb_compile_error(const char *file, int line, const char *fmt, ...)
   74: {
   75:     va_list args;
   76:     char buf[BUFSIZ];
   77: 
   78:     va_start(args, fmt);
   79:     compile_snprintf(buf, BUFSIZ, file, line, fmt, args);
   80:     va_end(args);
   81:     err_append(buf);
   82: }
   83: 
   84: void
   85: rb_compile_error_append(const char *fmt, ...)
   86: {
   87:     va_list args;
   88:     char buf[BUFSIZ];
   89: 
   90:     va_start(args, fmt);
   91:     vsnprintf(buf, BUFSIZ, fmt, args);
   92:     va_end(args);
   93:     err_append(buf);
   94: }
   95: 
   96: static void
   97: compile_warn_print(const char *file, int line, const char *fmt, va_list args)
   98: {
   99:     char buf[BUFSIZ];
  100:     int len;
  101: 
  102:     compile_snprintf(buf, BUFSIZ, file, line, fmt, args);
  103:     len = strlen(buf);
  104:     buf[len++] = '\n';
  105:     rb_write_error2(buf, len);
  106: }
  107: 
  108: void
  109: rb_compile_warn(const char *file, int line, const char *fmt, ...)
  110: {
  111:     char buf[BUFSIZ];
  112:     va_list args;
  113: 
  114:     if (NIL_P(ruby_verbose)) return;
  115: 
  116:     snprintf(buf, BUFSIZ, "warning: %s", fmt);
  117: 
  118:     va_start(args, fmt);
  119:     compile_warn_print(file, line, buf, args);
  120:     va_end(args);
  121: }
  122: 
  123: /* rb_compile_warning() reports only in verbose mode */
  124: void
  125: rb_compile_warning(const char *file, int line, const char *fmt, ...)
  126: {
  127:     char buf[BUFSIZ];
  128:     va_list args;
  129: 
  130:     if (!RTEST(ruby_verbose)) return;
  131: 
  132:     snprintf(buf, BUFSIZ, "warning: %s", fmt);
  133: 
  134:     va_start(args, fmt);
  135:     compile_warn_print(file, line, buf, args);
  136:     va_end(args);
  137: }
  138: 
  139: static void
  140: warn_print(const char *fmt, va_list args)
  141: {
  142:     char buf[BUFSIZ];
  143:     int len;
  144: 
  145:     err_snprintf(buf, BUFSIZ, fmt, args);
  146:     len = strlen(buf);
  147:     buf[len++] = '\n';
  148:     rb_write_error2(buf, len);
  149: }
  150: 
  151: void
  152: rb_warn(const char *fmt, ...)
  153: {
  154:     char buf[BUFSIZ];
  155:     va_list args;
  156: 
  157:     if (NIL_P(ruby_verbose)) return;
  158: 
  159:     snprintf(buf, BUFSIZ, "warning: %s", fmt);
  160: 
  161:     va_start(args, fmt);
  162:     warn_print(buf, args);
  163:     va_end(args);
  164: }
  165: 
  166: /* rb_warning() reports only in verbose mode */
  167: void
  168: rb_warning(const char *fmt, ...)
  169: {
  170:     char buf[BUFSIZ];
  171:     va_list args;
  172: 
  173:     if (!RTEST(ruby_verbose)) return;
  174: 
  175:     snprintf(buf, BUFSIZ, "warning: %s", fmt);
  176: 
  177:     va_start(args, fmt);
  178:     warn_print(buf, args);
  179:     va_end(args);
  180: }
  181: 
  182: /*
  183:  * call-seq:
  184:  *    warn(msg)   => nil
  185:  *
  186:  * Display the given message (followed by a newline) on STDERR unless
  187:  * warnings are disabled (for example with the <code>-W0</code> flag).
  188:  */
  189: 
  190: static VALUE
  191: rb_warn_m(VALUE self, VALUE mesg)
  192: {
  193:     if (!NIL_P(ruby_verbose)) {
  194:         rb_io_write(rb_stderr, mesg);
  195:         rb_io_write(rb_stderr, rb_default_rs);
  196:     }
  197:     return Qnil;
  198: }
  199: 
  200: void rb_vm_bugreport(void);
  201: 
  202: static void
  203: report_bug(const char *file, int line, const char *fmt, va_list args)
  204: {
  205:     char buf[BUFSIZ];
  206:     FILE *out = stderr;
  207:     int len = err_position_0(buf, BUFSIZ, file, line);
  208: 
  209:     if (fwrite(buf, 1, len, out) == len ||
  210:         fwrite(buf, 1, len, (out = stdout)) == len) {
  211:         fputs("[BUG] ", out);
  212:         vfprintf(out, fmt, args);
  213:         fprintf(out, "\n%s\n\n", ruby_description);
  214:         rb_vm_bugreport();
  215:     }
  216: }
  217: 
  218: void
  219: rb_bug(const char *fmt, ...)
  220: {
  221:     va_list args;
  222: 
  223:     va_start(args, fmt);
  224:     report_bug(rb_sourcefile(), rb_sourceline(), fmt, args);
  225:     va_end(args);
  226: 
  227:     abort();
  228: }
  229: 
  230: void
  231: rb_compile_bug(const char *file, int line, const char *fmt, ...)
  232: {
  233:     va_list args;
  234: 
  235:     va_start(args, fmt);
  236:     report_bug(file, line, fmt, args);
  237:     va_end(args);
  238: 
  239:     abort();
  240: }
  241: 
  242: static struct types {
  243:     int type;
  244:     const char *name;
  245: } builtin_types[] = {
  246:     {T_NIL,     "nil"},
  247:     {T_OBJECT,  "Object"},
  248:     {T_CLASS,   "Class"},
  249:     {T_ICLASS,  "iClass"},       /* internal use: mixed-in module holder */
  250:     {T_MODULE,  "Module"},
  251:     {T_FLOAT,   "Float"},
  252:     {T_STRING,  "String"},
  253:     {T_REGEXP,  "Regexp"},
  254:     {T_ARRAY,   "Array"},
  255:     {T_FIXNUM,  "Fixnum"},
  256:     {T_HASH,    "Hash"},
  257:     {T_STRUCT,  "Struct"},
  258:     {T_BIGNUM,  "Bignum"},
  259:     {T_FILE,    "File"},
  260:     {T_TRUE,    "true"},
  261:     {T_FALSE,   "false"},
  262:     {T_SYMBOL,  "Symbol"},       /* :symbol */
  263:     {T_DATA,    "Data"},   /* internal use: wrapped C pointers */
  264:     {T_MATCH,   "MatchData"},     /* data of $~ */
  265:     {T_NODE,    "Node"},   /* internal use: syntax tree node */
  266:     {T_UNDEF,   "undef"}, /* internal use: #undef; should not happen */
  267:     {-1,        0}
  268: };
  269: 
  270: void
  271: rb_check_type(VALUE x, int t)
  272: {
  273:     struct types *type = builtin_types;
  274: 
  275:     if (x == Qundef) {
  276:         rb_bug("undef leaked to the Ruby space");
  277:     }
  278: 
  279:     if (TYPE(x) != t) {
  280:         while (type->type >= 0) {
  281:             if (type->type == t) {
  282:                 const char *etype;
  283: 
  284:                 if (NIL_P(x)) {
  285:                     etype = "nil";
  286:                 }
  287:                 else if (FIXNUM_P(x)) {
  288:                     etype = "Fixnum";
  289:                 }
  290:                 else if (SYMBOL_P(x)) {
  291:                     etype = "Symbol";
  292:                 }
  293:                 else if (rb_special_const_p(x)) {
  294:                     etype = RSTRING_PTR(rb_obj_as_string(x));
  295:                 }
  296:                 else {
  297:                     etype = rb_obj_classname(x);
  298:                 }
  299:                 rb_raise(rb_eTypeError, "wrong argument type %s (expected %s)",
  300:                          etype, type->name);
  301:             }
  302:             type++;
  303:         }
  304:         rb_bug("unknown type 0x%x (0x%x given)", t, TYPE(x));
  305:     }
  306: }
  307: 
  308: /* exception classes */
  309: #include <errno.h>
  310: 
  311: VALUE rb_eException;
  312: VALUE rb_eSystemExit;
  313: VALUE rb_eInterrupt;
  314: VALUE rb_eSignal;
  315: VALUE rb_eFatal;
  316: VALUE rb_eStandardError;
  317: VALUE rb_eRuntimeError;
  318: VALUE rb_eTypeError;
  319: VALUE rb_eArgError;
  320: VALUE rb_eIndexError;
  321: VALUE rb_eKeyError;
  322: VALUE rb_eRangeError;
  323: VALUE rb_eNameError;
  324: VALUE rb_eNoMethodError;
  325: VALUE rb_eSecurityError;
  326: VALUE rb_eNotImpError;
  327: VALUE rb_eNoMemError;
  328: VALUE rb_cNameErrorMesg;
  329: 
  330: VALUE rb_eScriptError;
  331: VALUE rb_eSyntaxError;
  332: VALUE rb_eLoadError;
  333: 
  334: VALUE rb_eSystemCallError;
  335: VALUE rb_mErrno;
  336: static VALUE eNOERROR;
  337: 
  338: VALUE
  339: rb_exc_new(VALUE etype, const char *ptr, long len)
  340: {
  341:     return rb_funcall(etype, rb_intern("new"), 1, rb_str_new(ptr, len));
  342: }
  343: 
  344: VALUE
  345: rb_exc_new2(VALUE etype, const char *s)
  346: {
  347:     return rb_exc_new(etype, s, strlen(s));
  348: }
  349: 
  350: VALUE
  351: rb_exc_new3(VALUE etype, VALUE str)
  352: {
  353:     StringValue(str);
  354:     return rb_funcall(etype, rb_intern("new"), 1, str);
  355: }
  356: 
  357: /*
  358:  * call-seq:
  359:  *    Exception.new(msg = nil)   =>  exception
  360:  *
  361:  *  Construct a new Exception object, optionally passing in 
  362:  *  a message.
  363:  */
  364: 
  365: static VALUE
  366: exc_initialize(int argc, VALUE *argv, VALUE exc)
  367: {
  368:     VALUE arg;
  369: 
  370:     rb_scan_args(argc, argv, "01", &arg);
  371:     rb_iv_set(exc, "mesg", arg);
  372:     rb_iv_set(exc, "bt", Qnil);
  373: 
  374:     return exc;
  375: }
  376: 
  377: /*
  378:  *  Document-method: exception
  379:  *
  380:  *  call-seq:
  381:  *     exc.exception(string) -> an_exception or exc
  382:  *  
  383:  *  With no argument, or if the argument is the same as the receiver,
  384:  *  return the receiver. Otherwise, create a new
  385:  *  exception object of the same class as the receiver, but with a
  386:  *  message equal to <code>string.to_str</code>.
  387:  *     
  388:  */
  389: 
  390: static VALUE
  391: exc_exception(int argc, VALUE *argv, VALUE self)
  392: {
  393:     VALUE exc;
  394: 
  395:     if (argc == 0) return self;
  396:     if (argc == 1 && self == argv[0]) return self;
  397:     exc = rb_obj_clone(self);
  398:     exc_initialize(argc, argv, exc);
  399: 
  400:     return exc;
  401: }
  402: 
  403: /*
  404:  * call-seq:
  405:  *   exception.to_s   =>  string
  406:  *
  407:  * Returns exception's message (or the name of the exception if
  408:  * no message is set).
  409:  */
  410: 
  411: static VALUE
  412: exc_to_s(VALUE exc)
  413: {
  414:     VALUE mesg = rb_attr_get(exc, rb_intern("mesg"));
  415: 
  416:     if (NIL_P(mesg)) return rb_class_name(CLASS_OF(exc));
  417:     if (OBJ_TAINTED(exc)) OBJ_TAINT(mesg);
  418:     return mesg;
  419: }
  420: 
  421: /*
  422:  * call-seq:
  423:  *   exception.message   =>  string
  424:  *
  425:  * Returns the result of invoking <code>exception.to_s</code>.
  426:  * Normally this returns the exception's message or name. By
  427:  * supplying a to_str method, exceptions are agreeing to
  428:  * be used where Strings are expected.
  429:  */
  430: 
  431: static VALUE
  432: exc_message(VALUE exc)
  433: {
  434:     return rb_funcall(exc, rb_intern("to_s"), 0, 0);
  435: }
  436: 
  437: /*
  438:  * call-seq:
  439:  *   exception.inspect   => string
  440:  *
  441:  * Return this exception's class name an message
  442:  */
  443: 
  444: static VALUE
  445: exc_inspect(VALUE exc)
  446: {
  447:     VALUE str, klass;
  448: 
  449:     klass = CLASS_OF(exc);
  450:     exc = rb_obj_as_string(exc);
  451:     if (RSTRING_LEN(exc) == 0) {
  452:         return rb_str_dup(rb_class_name(klass));
  453:     }
  454: 
  455:     str = rb_str_buf_new2("#<");
  456:     klass = rb_class_name(klass);
  457:     rb_str_buf_append(str, klass);
  458:     rb_str_buf_cat(str, ": ", 2);
  459:     rb_str_buf_append(str, exc);
  460:     rb_str_buf_cat(str, ">", 1);
  461: 
  462:     return str;
  463: }
  464: 
  465: /*
  466:  *  call-seq:
  467:  *     exception.backtrace    => array
  468:  *  
  469:  *  Returns any backtrace associated with the exception. The backtrace
  470:  *  is an array of strings, each containing either ``filename:lineNo: in
  471:  *  `method''' or ``filename:lineNo.''
  472:  *     
  473:  *     def a
  474:  *       raise "boom"
  475:  *     end
  476:  *     
  477:  *     def b
  478:  *       a()
  479:  *     end
  480:  *     
  481:  *     begin
  482:  *       b()
  483:  *     rescue => detail
  484:  *       print detail.backtrace.join("\n")
  485:  *     end
  486:  *     
  487:  *  <em>produces:</em>
  488:  *     
  489:  *     prog.rb:2:in `a'
  490:  *     prog.rb:6:in `b'
  491:  *     prog.rb:10
  492: */
  493: 
  494: static VALUE
  495: exc_backtrace(VALUE exc)
  496: {
  497:     static ID bt;
  498: 
  499:     if (!bt) bt = rb_intern("bt");
  500:     return rb_attr_get(exc, bt);
  501: }
  502: 
  503: VALUE
  504: rb_check_backtrace(VALUE bt)
  505: {
  506:     long i;
  507:     static const char *err = "backtrace must be Array of String";
  508: 
  509:     if (!NIL_P(bt)) {
  510:         int t = TYPE(bt);
  511: 
  512:         if (t == T_STRING) return rb_ary_new3(1, bt);
  513:         if (t != T_ARRAY) {
  514:             rb_raise(rb_eTypeError, err);
  515:         }
  516:         for (i=0;i<RARRAY_LEN(bt);i++) {
  517:             if (TYPE(RARRAY_PTR(bt)[i]) != T_STRING) {
  518:                 rb_raise(rb_eTypeError, err);
  519:             }
  520:         }
  521:     }
  522:     return bt;
  523: }
  524: 
  525: /*
  526:  *  call-seq:
  527:  *     exc.set_backtrace(array)   =>  array
  528:  *  
  529:  *  Sets the backtrace information associated with <i>exc</i>. The
  530:  *  argument must be an array of <code>String</code> objects in the
  531:  *  format described in <code>Exception#backtrace</code>.
  532:  *     
  533:  */
  534: 
  535: static VALUE
  536: exc_set_backtrace(VALUE exc, VALUE bt)
  537: {
  538:     return rb_iv_set(exc, "bt", rb_check_backtrace(bt));
  539: }
  540: 
  541: /*
  542:  *  call-seq:
  543:  *     exc == obj   => true or false
  544:  *  
  545:  *  Equality---If <i>obj</i> is not an <code>Exception</code>, returns
  546:  *  <code>false</code>. Otherwise, returns <code>true</code> if <i>exc</i> and 
  547:  *  <i>obj</i> share same class, messages, and backtrace.
  548:  */
  549: 
  550: static VALUE
  551: exc_equal(VALUE exc, VALUE obj)
  552: {
  553:     ID id_mesg = rb_intern("mesg");
  554: 
  555:     if (exc == obj) return Qtrue;
  556:     if (rb_obj_class(exc) != rb_obj_class(obj))
  557:         return Qfalse;
  558:     if (!rb_equal(rb_attr_get(exc, id_mesg), rb_attr_get(obj, id_mesg)))
  559:         return Qfalse;
  560:     if (!rb_equal(exc_backtrace(exc), exc_backtrace(obj)))
  561:         return Qfalse;
  562:     return Qtrue;
  563: }
  564: 
  565: /*
  566:  * call-seq:
  567:  *   SystemExit.new(status=0)   => system_exit
  568:  *
  569:  * Create a new +SystemExit+ exception with the given status.
  570:  */
  571: 
  572: static VALUE
  573: exit_initialize(int argc, VALUE *argv, VALUE exc)
  574: {
  575:     VALUE status = INT2FIX(EXIT_SUCCESS);
  576:     if (argc > 0 && FIXNUM_P(argv[0])) {
  577:         status = *argv++;
  578:         --argc;
  579:     }
  580:     rb_call_super(argc, argv);
  581:     rb_iv_set(exc, "status", status);
  582:     return exc;
  583: }
  584: 
  585: 
  586: /*
  587:  * call-seq:
  588:  *   system_exit.status   => fixnum
  589:  *
  590:  * Return the status value associated with this system exit.
  591:  */
  592: 
  593: static VALUE
  594: exit_status(VALUE exc)
  595: {
  596:     return rb_attr_get(exc, rb_intern("status"));
  597: }
  598: 
  599: 
  600: /*
  601:  * call-seq:
  602:  *   system_exit.success?  => true or false
  603:  *
  604:  * Returns +true+ if exiting successful, +false+ if not.
  605:  */
  606: 
  607: static VALUE
  608: exit_success_p(VALUE exc)
  609: {
  610:     VALUE status = rb_attr_get(exc, rb_intern("status"));
  611:     if (NIL_P(status)) return Qtrue;
  612:     if (status == INT2FIX(EXIT_SUCCESS)) return Qtrue;
  613:     return Qfalse;
  614: }
  615: 
  616: void
  617: rb_name_error(ID id, const char *fmt, ...)
  618: {
  619:     VALUE exc, argv[2];
  620:     va_list args;
  621:     char buf[BUFSIZ];
  622: 
  623:     va_start(args, fmt);
  624:     vsnprintf(buf, BUFSIZ, fmt, args);
  625:     va_end(args);
  626: 
  627:     argv[0] = rb_str_new2(buf);
  628:     argv[1] = ID2SYM(id);
  629:     exc = rb_class_new_instance(2, argv, rb_eNameError);
  630:     rb_exc_raise(exc);
  631: }
  632: 
  633: /*
  634:  * call-seq:
  635:  *   NameError.new(msg [, name])  => name_error
  636:  *
  637:  * Construct a new NameError exception. If given the <i>name</i>
  638:  * parameter may subsequently be examined using the <code>NameError.name</code>
  639:  * method.
  640:  */
  641: 
  642: static VALUE
  643: name_err_initialize(int argc, VALUE *argv, VALUE self)
  644: {
  645:     VALUE name;
  646: 
  647:     name = (argc > 1) ? argv[--argc] : Qnil;
  648:     rb_call_super(argc, argv);
  649:     rb_iv_set(self, "name", name);
  650:     return self;
  651: }
  652