diff options
Diffstat (limited to 'ext/marshal')
-rw-r--r-- | ext/marshal/MANIFEST | 4 | ||||
-rw-r--r-- | ext/marshal/depend | 2 | ||||
-rw-r--r-- | ext/marshal/marshal.c | 565 | ||||
-rw-r--r-- | ext/marshal/marshal.doc | 45 |
4 files changed, 616 insertions, 0 deletions
diff --git a/ext/marshal/MANIFEST b/ext/marshal/MANIFEST new file mode 100644 index 0000000000..53b0849484 --- /dev/null +++ b/ext/marshal/MANIFEST @@ -0,0 +1,4 @@ +MANIFEST +depend +marshal.c +marshal.doc diff --git a/ext/marshal/depend b/ext/marshal/depend new file mode 100644 index 0000000000..c955eb2d59 --- /dev/null +++ b/ext/marshal/depend @@ -0,0 +1,2 @@ +marshal.o: marshal.c ../../ruby.h ../../config.h ../../defines.h ../../io.h \ + ../../st.h diff --git a/ext/marshal/marshal.c b/ext/marshal/marshal.c new file mode 100644 index 0000000000..0b29ad5ab8 --- /dev/null +++ b/ext/marshal/marshal.c @@ -0,0 +1,565 @@ +/************************************************ + + marshal.c - + + $Author$ + $Revision$ + $Date$ + created at: Thu Apr 27 16:30:01 JST 1995 + +************************************************/ + +#include "ruby.h" +#include "io.h" +#include "st.h" + +#define TYPE_NIL '0' +#define TYPE_FIXNUM 'i' + +#define TYPE_OBJECT 'o' +#define TYPE_LINK '@' +#define TYPE_FLOAT 'f' +#define TYPE_BIGNUM 'l' +#define TYPE_STRING '"' +#define TYPE_REGEXP '/' +#define TYPE_ARRAY '[' +#define TYPE_HASH '{' +#define TYPE_STRUCT 'S' + +char *rb_class2path(); +VALUE rb_path2class(); + +static ID s_dump, s_load; + +#define w_byte(c, fp) putc((c), fp) +#define w_bytes(s, n, fp) (w_long((n), fp),fwrite(s, 1, n, fp)) + +static void +w_short(x, fp) + int x; + FILE *fp; +{ + w_byte( x & 0xff, fp); + w_byte((x>> 8) & 0xff, fp); +} + +static void +w_long(x, fp) + long x; + FILE *fp; +{ + w_byte((int)( x & 0xff), fp); + w_byte((int)((x>> 8) & 0xff), fp); + w_byte((int)((x>>16) & 0xff), fp); + w_byte((int)((x>>24) & 0xff), fp); +} + +static void +w_float(d, fp) + double d; + FILE *fp; +{ + char buf[100]; + + sprintf(buf, "%.12g", d); + w_bytes(buf, strlen(buf), fp); +} + +static void +w_symbol(id, fp) + ID id; + FILE *fp; +{ + char *sym = rb_id2name(id); + + w_bytes(sym, strlen(sym), fp); +} + +static void w_object(); +extern VALUE cBignum, cStruct; + +static int +hash_each(key, value, fp) + VALUE key, value; + FILE *fp; +{ + w_object(key, fp); + w_object(value, fp); + return ST_CONTINUE; +} + +static int +obj_each(id, value, fp) + ID id; + VALUE value; + FILE *fp; +{ + w_symbol(id, fp); + w_object(value, fp); + return ST_CONTINUE; +} + +struct st_table *new_idhash(); + +static void +w_object(obj, fp, port, table) + VALUE obj, port; + FILE *fp; + st_table *table; +{ + if (obj == Qnil) { + w_byte(TYPE_NIL, fp); + } + else if (FIXNUM_P(obj)) { + w_byte(TYPE_FIXNUM, fp); + w_long(FIX2INT(obj), fp); + } + else if (st_lookup(table, obj, 0)) { + w_byte(TYPE_LINK, fp); + w_long(obj, fp); + } + else { + st_insert(table, obj, 0); + switch (BUILTIN_TYPE(obj)) { + case T_FLOAT: + w_byte(TYPE_FLOAT, fp); + w_long(obj, fp); + w_float(RFLOAT(obj)->value, fp); + break; + + case T_BIGNUM: + w_byte(TYPE_BIGNUM, fp); + w_long(obj, fp); + { + char sign = RBIGNUM(obj)->sign?'+':'-'; + int len = RBIGNUM(obj)->len; + USHORT *d = RBIGNUM(obj)->digits; + + w_byte(sign, fp); + w_long(len, fp); + while (len--) { + w_short(d, fp); + d++; + } + } + break; + + case T_STRING: + w_byte(TYPE_STRING, fp); + w_long(obj, fp); + w_bytes(RSTRING(obj)->ptr, RSTRING(obj)->len, fp); + break; + + case T_REGEXP: + w_byte(TYPE_REGEXP, fp); + w_long(obj, fp); + w_bytes(RREGEXP(obj)->str, RREGEXP(obj)->len, fp); + w_byte(FL_TEST(obj, FL_USER1), fp); + break; + + case T_ARRAY: + w_byte(TYPE_ARRAY, fp); + w_long(obj, fp); + { + int len = RARRAY(obj)->len; + VALUE *ptr = RARRAY(obj)->ptr; + + w_long(len, fp); + while (len--) { + w_object(*ptr, fp, port, table); + ptr++; + } + } + break; + + case T_HASH: + w_byte(TYPE_HASH, fp); + w_long(obj, fp); + w_long(RHASH(obj)->tbl->num_entries, fp); + st_foreach(RHASH(obj)->tbl, hash_each, fp); + break; + + case T_STRUCT: + w_byte(TYPE_STRUCT, fp); + w_long(obj, fp); + { + int len = RSTRUCT(obj)->len; + char *path = rb_class2path(CLASS_OF(obj)); + VALUE mem; + int i; + + w_bytes(path, strlen(path), fp); + w_long(len, fp); + mem = rb_ivar_get(CLASS_OF(obj), rb_intern("__member__")); + if (mem == Qnil) { + Fail("non-initialized struct"); + } + for (i=0; i<len; i++) { + w_symbol(FIX2INT(RARRAY(mem)->ptr[i]), fp); + w_object(RSTRUCT(obj)->ptr[i], fp, port, table); + } + } + break; + + case T_OBJECT: + w_byte(TYPE_OBJECT, fp); + w_long(obj, fp); + { + VALUE class = CLASS_OF(obj); + char *path = rb_class2path(class); + + w_bytes(path, strlen(path), fp); + if (rb_responds_to(obj, s_dump)) { + w_long(-1, fp); + rb_funcall(obj, s_dump, 1, port); + } + else if (ROBJECT(obj)->iv_tbl) { + w_long(ROBJECT(obj)->iv_tbl->num_entries, fp); + st_foreach(ROBJECT(obj)->iv_tbl, obj_each, fp); + } + else { + w_long(0, fp); + } + } + break; + + default: + Fail("can't dump %s", rb_class2name(CLASS_OF(obj))); + break; + } + } +} + +static VALUE +marshal_dump(self, obj, port) + VALUE self, obj, port; +{ + extern VALUE cIO; + FILE *fp; + OpenFile *fptr; + st_table *table; + + if (obj_is_kind_of(port, cIO)) { + GetOpenFile(port, fptr); + if (!(fptr->mode & FMODE_WRITABLE)) { + Fail("not opened for writing"); + } + fp = (fptr->f2) ? fptr->f2 : fptr->f; + } + else { + Fail("instance of IO needed"); + } + + table = new_idhash(); + + w_object(obj, fp, port, table); + + st_free_table(table); + return Qnil; +} + +static VALUE +marshal_dumps(self, obj) + VALUE self, obj; +{ + VALUE str = str_new(0, 0); + VALUE port; + FILE *fp = Qnil; + char buf[BUFSIZ]; + int n; + + sprintf(buf, "/tmp/rb-mrsr-%x", getpid()^(int)buf); + port = file_open(buf, "w"); + if (!port) rb_sys_fail("tmp file"); + fp = fopen(buf, "r"); + if (!fp) rb_sys_fail("tmp file(read)"); + unlink(buf); + + marshal_dump(self, obj, port); + io_close(port); + + while (n = fread(buf, 1, BUFSIZ, fp)) { + str_cat(str, buf, n); + } + + return str; +} + +#define r_byte(fp) getc(fp) + +static int +r_short(fp) + FILE *fp; +{ + register short x; + x = r_byte(fp); + x |= r_byte(fp) << 8; + /* XXX If your short is > 16 bits, add sign-extension here!!! */ + return x; +} + +static long +r_long(fp) + FILE *fp; +{ + register long x; + x = r_byte(fp); + x |= (long)r_byte(fp) << 8; + x |= (long)r_byte(fp) << 16; + x |= (long)r_byte(fp) << 24; + /* XXX If your long is > 32 bits, add sign-extension here!!! */ + return x; +} +#define r_bytes(s, fp) r_bytes0(&s, fp) +static int +r_bytes0(s, fp) + char **s; + FILE *fp; +{ + int len = r_long(fp); + *s = ALLOC_N(char, len+1); + + fread(*s, 1, len, fp); + (*s)[len] = '\0'; + return len; +} + +static ID +r_symbol(fp) + FILE *fp; +{ + char *buf; + ID id; + + r_bytes(buf, fp); + id = rb_intern(buf); + free(buf); + return id; +} + +static VALUE +r_object(fp, port, table) + FILE *fp; + VALUE port; + st_table *table; +{ + VALUE v; + int type = r_byte(fp); + int id; + + switch (type) { + case EOF: + Fail("EOF read where object expected"); + return Qnil; + + case TYPE_NIL: + return Qnil; + + case TYPE_LINK: + if (st_lookup(table, r_long(fp), &v)) { + return v; + } + Fail("corrupted marshal file"); + break; + + case TYPE_FIXNUM: + { + int i = r_long(fp); + return INT2FIX(i); + } + } + + id = r_long(fp); + switch (type) { + case TYPE_FLOAT: + { + double atof(); + char *buf; + + r_bytes(buf, fp); + v = float_new(atof(buf)); + free(buf); + } + break; + + case TYPE_BIGNUM: + { + int len; + USHORT *digits; + + NEWOBJ(big, struct RBignum); + OBJSETUP(big, cBignum, T_BIGNUM); + big->sign = (r_byte(fp) == '+'); + big->len = len = r_long(fp); + big->digits = digits = ALLOC_N(USHORT, len); + while (len--) { + *digits++ = r_short(fp); + } + v = (VALUE)big; + } + break; + + case TYPE_STRING: + { + char *buf; + int len = r_bytes(buf, fp); + v = str_new(buf, len); + free(buf); + } + break; + + case TYPE_REGEXP: + { + char *buf; + int len = r_bytes(buf, fp); + int ci = r_byte(fp); + v = reg_new(buf, len, ci); + free(buf); + } + break; + + case TYPE_ARRAY: + { + int len = r_long(fp); + v = ary_new2(len); + while (len--) { + ary_push(v, r_object(fp, port, table)); + } + } + break; + + case TYPE_HASH: + { + int len = r_long(fp); + + v = hash_new(); + while (len--) { + VALUE key = r_object(fp, port, table); + VALUE value = r_object(fp, port, table); + hash_aset(v, key, value); + } + } + break; + + case TYPE_STRUCT: + { + VALUE class, mem, values; + char *path; + int i, len; + + r_bytes(path, fp); + class = rb_path2class(path); + free(path); + mem = rb_ivar_get(class, rb_intern("__member__")); + if (mem == Qnil) { + Fail("non-initialized struct"); + } + len = r_long(fp); + + values = ary_new(); + i = 0; + while (len--) { + ID slot = r_symbol(fp); + if (RARRAY(mem)->ptr[i++] != INT2FIX(slot)) + Fail("struct not compatible"); + ary_push(values, r_object(fp, port, table)); + } + v = struct_alloc(class, values); + } + break; + + case TYPE_OBJECT: + { + VALUE class; + int len; + char *path; + + r_bytes(path, fp); + class = rb_path2class(path); + free(path); + len = r_long(fp); + if (len == -1) { + if (rb_responds_to(class, s_load)) { + v = rb_funcall(class, s_load, 1, port); + } + else { + Fail("class %s needs to have method `_load_from'", + rb_class2name(class)); + } + } + else { + v = obj_alloc(class); + if (len > 0) { + while (len--) { + ID id = r_symbol(fp); + VALUE val = r_object(fp, port, table); + rb_ivar_set(v, id, val); + } + } + } + } + break; + + default: + Fail("dump format error(0x%x)", type); + break; + } + st_insert(table, id, v); + return v; +} + +static VALUE +marshal_load(self, port) + VALUE self, port; +{ + extern VALUE cIO; + void *fp; + VALUE v; + OpenFile *fptr; + st_table *table; + + if (TYPE(port) == T_STRING) { + char buf[32]; + + sprintf(buf, "/tmp/rb-mrsw-%x", getpid()^(int)buf); + fp = fopen(buf, "w"); + if (!fp) rb_sys_fail("tmp file"); + v = file_open(buf, "r"); + if (!v) rb_sys_fail("tmp file(read)"); + unlink(buf); + + fwrite(RSTRING(port)->ptr, RSTRING(port)->len, 1, fp); + fclose(fp); + port = v; + } + if (obj_is_kind_of(port, cIO)) { + GetOpenFile(port, fptr); + if (!(fptr->mode & FMODE_READABLE)) { + Fail("not opened for reading"); + } + fp = fptr->f; + } + else { + Fail("instance of IO needed"); + } + + table = new_idhash(); + + v = r_object(fp, port, table); + + st_free_table(table); + + return v; +} + +Init_marshal() +{ + VALUE mMarshal = rb_define_module("Marshal"); + + s_dump = rb_intern("_dump_to"); + s_load = rb_intern("_load_from"); + rb_define_module_function(mMarshal, "dump", marshal_dump, 2); + rb_define_module_function(mMarshal, "dumps", marshal_dumps, 1); + rb_define_module_function(mMarshal, "load", marshal_load, 1); + rb_define_module_function(mMarshal, "restore", marshal_load, 1); +} diff --git a/ext/marshal/marshal.doc b/ext/marshal/marshal.doc new file mode 100644 index 0000000000..8c3b63072e --- /dev/null +++ b/ext/marshal/marshal.doc @@ -0,0 +1,45 @@ +.\" marshal.doc - -*- Indented-Text -*- created at: Tue May 16 12:18:08 JST 1995 + +** Marshal(�⥸�塼��) + +ruby���֥������Ȥ�ե�����˽Ф����ꡤ�ɤߤ��٤����ꤹ�뵡ǽ���� +����⥸�塼�롥����ʬ�Υ��饹�Υ�����Ф������Ǥ��뤬���ե� +����ؤ��Բ�ǽ�ʥ��饹��¸�ߤ�(��:IO)�����Τ褦�ʥ��饹��Ф����� +������㳰��ȯ�������롥 + +Methods: +Single Methods: + + dump(obj, port) + + obj��Ƶ�Ū�˥ե�����˽Ф����ե�����˽Ф��ʤ����饹�Υ� + ����ե�����˽Ф����Ȥ�����㳰��ȯ�������롥�ե����� + �˽Ф��ʤ����饹�ϰʲ����̤ꡥ + + Class, Module, Data + + �ޤ��������Υ��饹�����Ū�˻ؤ����饹(�㤨��IO�Υ��֥��饹)�ʤ� + ��Ф��ʤ���port��IO(�ޤ��Ϥ��Υ��֥��饹)�Υ�������� + ���롥 + + ���Ϥ��륪�֥������Ȥ���å�`_dump_to'��������Ƥ�����ˤϡ��ե� + ������ϤϤ��Υ�åɤ�ȤäƹԤ��롥��å�`_dump_to'�ϰ����� + ���ƽ�����Υե����륪�֥������Ȥ������롥��������å� + `_dump_to'����ĥ��饹��ɬ��Ʊ���ե����ޥåȤ��ɤ��᤹�ðۥ�å� + `_load_from'���������ɬ�פ����롥 + + + dumps(obj) + + dump()���ե�����˽Ф��Τ�Ʊ�����Ƥ�ޤ�ʸ������֤��� + + load(port) + + port���饪�֥������Ȥ��ɤ߹������ơ����Υ��֥������Ȥ�Ʊ�����֤� + ��ĥ��֥������Ȥ��������롥port��ʸ����IO(�ޤ��Ϥ��Υ��֥��饹) + �Υ����Ǥ��롥 + +------------------------------------------------------- +Local variables: +fill-column: 70 +end: |