/*
 *  call-seq:
 *     ObjectSpace.define_finalizer(obj, aProc=proc())
 *
 *  Adds <i>aProc</i> as a finalizer, to be called after <i>obj</i>
 *  was destroyed.
 *
 */

static VALUE
define_final(argc, argv, os)
    int argc;
    VALUE *argv;
    VALUE os;
{
    VALUE obj, block, table;

    rb_scan_args(argc, argv, "11", &obj, &block);
    if (argc == 1) {
        block = rb_block_proc();
    }
    else if (!rb_respond_to(block, rb_intern("call"))) {
        rb_raise(rb_eArgError, "wrong type argument %s (should be callable)",
                 rb_obj_classname(block));
    }
    need_call_final = 1;
    if (!FL_ABLE(obj)) {
        rb_raise(rb_eArgError, "cannot define finalizer for %s",
                 rb_obj_classname(obj));
    }
    RBASIC(obj)->flags |= FL_FINALIZE;

    block = rb_ary_new3(2, INT2FIX(ruby_safe_level), block);
    OBJ_FREEZE(block);

    if (!finalizer_table) {
        finalizer_table = st_init_numtable();
    }
    if (st_lookup(finalizer_table, obj, &table)) {
        rb_ary_push(table, block);
    }
    else {
        table = rb_ary_new3(1, block);
        RBASIC(table)->klass = 0;
        st_add_direct(finalizer_table, obj, table);
    }
    return block;
}