256 lines
6.7 KiB
C
256 lines
6.7 KiB
C
/* Structured input, compact format */
|
|
|
|
#include "fail.h"
|
|
#include "gc.h"
|
|
#include "intext.h"
|
|
#include "io.h"
|
|
#include "memory.h"
|
|
#include "mlvalues.h"
|
|
#include "misc.h"
|
|
#include "reverse.h"
|
|
|
|
static header_t * intern_ptr;
|
|
static asize_t obj_counter;
|
|
static value * intern_obj_table;
|
|
static unsigned int intern_color;
|
|
static header_t intern_header;
|
|
static value intern_block;
|
|
|
|
#define Sign_extend_shift ((sizeof(long) - 1) * 8)
|
|
#define Sign_extend(x) (((long)(x) << Sign_extend_shift) >> Sign_extend_shift)
|
|
|
|
static long input8u(chan)
|
|
struct channel * chan;
|
|
{
|
|
return getch(chan);
|
|
}
|
|
|
|
static long input8s(chan)
|
|
struct channel * chan;
|
|
{
|
|
long b1 = getch(chan);
|
|
return Sign_extend(b1);
|
|
}
|
|
|
|
static long input16u(chan)
|
|
struct channel * chan;
|
|
{
|
|
long b1 = getch(chan);
|
|
long b2 = getch(chan);
|
|
return (b1 << 8) + b2;
|
|
}
|
|
|
|
static long input16s(chan)
|
|
struct channel * chan;
|
|
{
|
|
long b1 = getch(chan);
|
|
long b2 = getch(chan);
|
|
return (Sign_extend(b1) << 8) + b2;
|
|
}
|
|
|
|
static long input32u(chan)
|
|
struct channel * chan;
|
|
{
|
|
long b1 = getch(chan);
|
|
long b2 = getch(chan);
|
|
long b3 = getch(chan);
|
|
long b4 = getch(chan);
|
|
return (b1 << 24) + (b2 << 16) + (b3 << 8) + b4;
|
|
}
|
|
|
|
static long input32s(chan)
|
|
struct channel * chan;
|
|
{
|
|
long b1 = getch(chan);
|
|
long b2 = getch(chan);
|
|
long b3 = getch(chan);
|
|
long b4 = getch(chan);
|
|
return (Sign_extend(b1) << 24) + (b2 << 16) + (b3 << 8) + b4;
|
|
}
|
|
|
|
#ifdef SIXTYFOUR
|
|
static long input64s(chan)
|
|
struct channel * chan;
|
|
{
|
|
long res;
|
|
int i;
|
|
res = 0;
|
|
for (i = 0; i < 8; i++) res = (res << 8) + getch(chan);
|
|
return res;
|
|
}
|
|
#endif
|
|
|
|
static void read_compact(chan, dest)
|
|
struct channel * chan;
|
|
value * dest;
|
|
{
|
|
unsigned int code;
|
|
tag_t tag;
|
|
mlsize_t size, len, ofs_ind;
|
|
value v;
|
|
asize_t ofs;
|
|
header_t header;
|
|
|
|
tailcall:
|
|
code = getch(chan);
|
|
if (code >= PREFIX_SMALL_INT) {
|
|
if (code >= PREFIX_SMALL_BLOCK) {
|
|
/* Small block */
|
|
tag = code & 0xF;
|
|
size = (code >> 4) & 0x7;
|
|
read_block:
|
|
if (size == 0) {
|
|
v = Atom(tag);
|
|
} else {
|
|
v = Val_hp(intern_ptr);
|
|
*dest = v;
|
|
intern_obj_table[obj_counter++] = v;
|
|
dest = (value *) (intern_ptr + 1);
|
|
*intern_ptr = Make_header(size, tag, intern_color);
|
|
intern_ptr += 1 + size;
|
|
for(/*nothing*/; size > 1; size--, dest++)
|
|
read_compact(chan, dest);
|
|
goto tailcall;
|
|
}
|
|
} else {
|
|
/* Small integer */
|
|
v = Val_int(code & 0x3F);
|
|
}
|
|
} else {
|
|
if (code >= PREFIX_SMALL_STRING) {
|
|
/* Small string */
|
|
len = (code & 0x1F);
|
|
read_string:
|
|
size = (len + sizeof(value)) / sizeof(value);
|
|
v = Val_hp(intern_ptr);
|
|
intern_obj_table[obj_counter++] = v;
|
|
*intern_ptr = Make_header(size, String_tag, intern_color);
|
|
intern_ptr += 1 + size;
|
|
Field(v, size - 1) = 0;
|
|
ofs_ind = Bsize_wsize(size) - 1;
|
|
Byte(v, ofs_ind) = ofs_ind - len;
|
|
really_getblock(chan, String_val(v), len);
|
|
} else {
|
|
switch(code) {
|
|
case CODE_INT8:
|
|
v = Val_long(input8s(chan));
|
|
break;
|
|
case CODE_INT16:
|
|
v = Val_long(input16s(chan));
|
|
break;
|
|
case CODE_INT32:
|
|
v = Val_long(input32s(chan));
|
|
break;
|
|
case CODE_INT64:
|
|
#ifdef SIXTYFOUR
|
|
v = Val_long(input64s(chan));
|
|
break;
|
|
#else
|
|
stat_free((char *) intern_obj_table);
|
|
Hd_val(intern_block) = intern_header; /* Don't confuse the GC */
|
|
failwith("input_value: integer too large");
|
|
break;
|
|
#endif
|
|
case CODE_SHARED8:
|
|
ofs = input8u(chan);
|
|
read_shared:
|
|
Assert(ofs > 0 && ofs <= obj_counter);
|
|
v = intern_obj_table[obj_counter - ofs];
|
|
break;
|
|
case CODE_SHARED16:
|
|
ofs = input16u(chan);
|
|
goto read_shared;
|
|
case CODE_SHARED32:
|
|
ofs = input32u(chan);
|
|
goto read_shared;
|
|
case CODE_BLOCK32:
|
|
header = (header_t) input32u(chan);
|
|
tag = Tag_hd(header);
|
|
size = Wosize_hd(header);
|
|
goto read_block;
|
|
case CODE_STRING8:
|
|
len = input8u(chan);
|
|
goto read_string;
|
|
case CODE_STRING32:
|
|
len = input32u(chan);
|
|
goto read_string;
|
|
case CODE_DOUBLE_LITTLE:
|
|
case CODE_DOUBLE_BIG:
|
|
if (sizeof(double) != 8) {
|
|
stat_free((char *) intern_obj_table);
|
|
Hd_val(intern_block) = intern_header; /* Don't confuse the GC */
|
|
invalid_argument("input_value: non-standard floats");
|
|
}
|
|
v = Val_hp(intern_ptr);
|
|
intern_obj_table[obj_counter++] = v;
|
|
*intern_ptr = Make_header(Double_wosize, Double_tag, intern_color);
|
|
intern_ptr += 1 + Double_wosize;
|
|
really_getblock(chan, (char *) v, 8);
|
|
if (code != CODE_DOUBLE_NATIVE) Reverse_double(v);
|
|
break;
|
|
case CODE_DOUBLE_ARRAY8_LITTLE:
|
|
case CODE_DOUBLE_ARRAY8_BIG:
|
|
len = input8u(chan);
|
|
read_double_array:
|
|
if (sizeof(double) != 8) {
|
|
stat_free((char *) intern_obj_table);
|
|
Hd_val(intern_block) = intern_header; /* Don't confuse the GC */
|
|
invalid_argument("input_value: non-standard floats");
|
|
}
|
|
size = len * Double_wosize;
|
|
v = Val_hp(intern_ptr);
|
|
intern_obj_table[obj_counter++] = v;
|
|
*intern_ptr = Make_header(size, Double_array_tag, intern_color);
|
|
intern_ptr += 1 + size;
|
|
really_getblock(chan, (char *) v, len * 8);
|
|
if (code != CODE_DOUBLE_ARRAY8_NATIVE &&
|
|
code != CODE_DOUBLE_ARRAY32_NATIVE) {
|
|
mlsize_t i;
|
|
for (i = 0; i < len; i++) Reverse_double((value)((double *)v + i));
|
|
}
|
|
break;
|
|
case CODE_DOUBLE_ARRAY32_LITTLE:
|
|
case CODE_DOUBLE_ARRAY32_BIG:
|
|
len = input32u(chan);
|
|
goto read_double_array;
|
|
}
|
|
}
|
|
}
|
|
*dest = v;
|
|
}
|
|
|
|
value input_value(chan) /* ML */
|
|
struct channel * chan;
|
|
{
|
|
uint32 magic;
|
|
mlsize_t num_objects, size_32, size_64, whsize;
|
|
value res;
|
|
|
|
magic = getword(chan);
|
|
if (magic != Intext_magic_number) failwith("input_value: bad object");
|
|
num_objects = getword(chan);
|
|
size_32 = getword(chan);
|
|
size_64 = getword(chan);
|
|
#ifdef SIXTYFOUR
|
|
whsize = size_64;
|
|
#else
|
|
whsize = size_32;
|
|
#endif
|
|
if (whsize == 0) {
|
|
read_compact(chan, &res);
|
|
} else {
|
|
if (Wosize_whsize(whsize) > Max_wosize)
|
|
failwith("intern: structure too big");
|
|
intern_block = alloc_shr(Wosize_whsize(whsize), String_tag);
|
|
intern_header = Hd_val(intern_block);
|
|
intern_color = Color_hd(intern_header);
|
|
Assert (intern_color == White || intern_color == Black);
|
|
intern_ptr = (header_t *) Hp_val(intern_block);
|
|
obj_counter = 0;
|
|
intern_obj_table = (value *) stat_alloc(num_objects * sizeof(value));
|
|
read_compact(chan, &res);
|
|
stat_free((char *) intern_obj_table);
|
|
}
|
|
return res;
|
|
}
|