/*
 * call-seq:
 *   stat.inspect  =>  string
 *
 * Produce a nicely formatted description of <i>stat</i>.
 *
 *   File.stat("/etc/passwd").inspect
 *      #=> "#<File::Stat dev=0xe000005, ino=1078078, mode=0100644, 
 *           nlink=1, uid=0, gid=0, rdev=0x0, size=1374, blksize=4096, 
 *           blocks=8, atime=Wed Dec 10 10:16:12 CST 2003, 
 *           mtime=Fri Sep 12 15:41:41 CDT 2003, 
 *           ctime=Mon Oct 27 11:20:27 CST 2003>"
 */

static VALUE
rb_stat_inspect(self)
    VALUE self;
{
    VALUE str;
    int i;
    static const struct {
        const char *name;
        VALUE (*func)_((VALUE));
    } member[] = {
        {"dev",            rb_stat_dev},
        {"ino",            rb_stat_ino},
        {"mode",    rb_stat_mode},
        {"nlink",   rb_stat_nlink},
        {"uid",            rb_stat_uid},
        {"gid",            rb_stat_gid},
        {"rdev",    rb_stat_rdev},
        {"size",    rb_stat_size},
        {"blksize", rb_stat_blksize},
        {"blocks",  rb_stat_blocks},
        {"atime",   rb_stat_atime},
        {"mtime",   rb_stat_mtime},
        {"ctime",   rb_stat_ctime},
    };

    str = rb_str_buf_new2("#<");
    rb_str_buf_cat2(str, rb_obj_classname(self));
    rb_str_buf_cat2(str, " ");

    for (i = 0; i < sizeof(member)/sizeof(member[0]); i++) {
        VALUE v;

        if (i > 0) {
            rb_str_buf_cat2(str, ", ");
        }
        rb_str_buf_cat2(str, member[i].name);
        rb_str_buf_cat2(str, "=");
        v = (*member[i].func)(self);
        if (i == 2) {          /* mode */
            char buf[32];

            sprintf(buf, "0%lo", NUM2ULONG(v));
            rb_str_buf_cat2(str, buf);
        }
        else if (i == 0 || i == 6) { /* dev/rdev */
            char buf[32];

            sprintf(buf, "0x%lx", NUM2ULONG(v));
            rb_str_buf_cat2(str, buf);
        }
        else {
            rb_str_append(str, rb_inspect(v));
        }
    }
    rb_str_buf_cat2(str, ">");
    OBJ_INFECT(str, self);

    return str;
}