- Parameters:
-
static_link | static link from the current frame |
parent | current parent |
prototype | list describing the c-type in the pack |
protodata | list containing the Logo data |
ptr | pointer to memory with C data |
mode | mode of traversal |
- Returns:
- traversal result (depends on the mode)
This function traverses a structure defined by c-type prototype and performs an action determined by mode
.
If mode
is MEM_STRUCT_SIZE
then only the size of the packed data is calculated. Parameters protodata
and ptr
are not used. The returned value is an integer atom containing the size.
If mode
is MEM_STRUCT_PACK
then Logo data from protodata
is packed into the memory pointed to by ptr
using the structure described in prototype
. The result is unbound atom.
If mode
is MEM_STRUCT_UNPACK
then packed data from ptr
is unpacked into a list of Logo data using the structure described in prototype
. The result of traverse_pack
is the list of Logo data.
{
int ofs = 0;
atom_t new_type;
atom_t traverse( atom_t prototype, atom_t protodata )
{
atom_t result = unbound;
atom_t result_end;
if (IS_ERROR( prototype )) return prototype;
if (!IS_LIST( prototype )) return new_error( ERROR_NOT_A_LIST, prototype );
if (IS_ERROR( protodata )) return protodata;
if (!IS_LIST( protodata )) return new_error( ERROR_NOT_A_LIST, protodata );
if( mode==MEM_STRUCT_UNPACK )
{
result = empty_list;
result_end = empty_list;
}
int count = 1;
#define GET_NEXT_TYPE prototype = CDR( prototype )
#define GET_NEXT_DATA protodata = CDR( protodata )
for (; IS_NOT_EMPTY( prototype ); )
{
atom_t type = CAR( prototype );
atom_t data = CAR( protodata );
try_again:
if( IS_LIST(type) )
{
atom_t res = traverse( type, data );
if( IS_ERROR(res) ) return res;
if( mode==MEM_STRUCT_UNPACK ) append( res, &result, &result_end );
goto to_continue;
}
if( IS_INTEGER(type) || IS_FLOAT(type) ) goto its_a_number;
if( !IS_ANY_WORD(type) ) return new_error(ERROR_NOT_A_TYPE_NAME,type);
int type_id = type_info( type );
int type_size = c_types[type_id].size;
switch( c_types[type_id].class )
{
case C_TYPE_POINTER:
{
int64_t i = 0;
if( mode==MEM_STRUCT_PACK )
{
if( !IS_EMPTY( data ) )
{
if( IS_MEM(data) )
i = (int)MEMORY(data);
else
GET_INT( data, i );
}
*(int*)(ptr+ofs) = (int)i;
}
if( mode==MEM_STRUCT_UNPACK )
{
i = *(int*)(ptr+ofs);
append( new_integer(i), &result, &result_end );
}
ofs += type_size/8;
goto to_continue;
}
case C_TYPE_ATOM:
{
atom_t i = 0;
if( mode==MEM_STRUCT_PACK )
{
break;
}
if( mode==MEM_STRUCT_UNPACK )
{
i = *(atom_t*)(ptr+ofs);
append( USE(i), &result, &result_end );
}
ofs += type_size/8;
goto to_continue;
}
case C_TYPE_FLOAT:
{
float64_t i = 0;
if( mode==MEM_STRUCT_PACK )
{
if( !IS_EMPTY( data ) ) GET_FLOAT( data, i );
switch( type_size )
{
case 32: *(float32_t*)(ptr+ofs) = i; break;
case 64: *(float64_t*)(ptr+ofs) = i; break;
default: goto subtype_test;
}
}
if( mode==MEM_STRUCT_UNPACK )
{
switch( type_size )
{
case 32: i = *(float32_t*)(ptr+ofs); break;
case 64: i = *(float64_t*)(ptr+ofs); break;
default: goto subtype_test;
}
append( new_float(i), &result, &result_end );
}
ofs += type_size/8;
goto to_continue;
}
case C_TYPE_SIGNED:
{
int64_t i = 0;
if( mode==MEM_STRUCT_PACK )
{
if( !IS_EMPTY( data ) ) GET_INT( data, i );
switch( type_size )
{
case 8: *(int8_t*) (ptr+ofs) = i; break;
case 16: *(int16_t*)(ptr+ofs) = i; break;
case 32: *(int32_t*)(ptr+ofs) = i; break;
case 64: *(int64_t*)(ptr+ofs) = i; break;
default: goto subtype_test;
}
}
if( mode==MEM_STRUCT_UNPACK )
{
switch( type_size )
{
case 8: i = *(int8_t*) (ptr+ofs); break;
case 16: i = *(int16_t*)(ptr+ofs); break;
case 32: i = *(int32_t*)(ptr+ofs); break;
case 64: i = *(int64_t*)(ptr+ofs); break;
default: goto subtype_test;
}
append( new_integer(i), &result, &result_end );
}
ofs += type_size/8;
goto to_continue;
}
case C_TYPE_UNSIGNED:
{
int64_t i = 0;
if( mode==MEM_STRUCT_PACK )
{
if( !IS_EMPTY( data ) ) GET_INT( data, i );\
switch( type_size )
{
case 8: *(uint8_t*) (ptr+ofs) = i; break;
case 16: *(uint16_t*)(ptr+ofs) = i; break;
case 32: *(uint32_t*)(ptr+ofs) = i; break;
case 64: *(uint64_t*)(ptr+ofs) = i; break;
default: goto subtype_test;
}
}
if( mode==MEM_STRUCT_UNPACK )
{
switch( type_size )
{
case 8: i = *(uint8_t*) (ptr+ofs); break;
case 16: i = *(uint16_t*)(ptr+ofs); break;
case 32: i = *(uint32_t*)(ptr+ofs); break;
case 64: i = *(uint64_t*)(ptr+ofs); break;
default: goto subtype_test;
}
append( new_integer(i), &result, &result_end );
}
ofs += type_size/8;
goto to_continue;
}
}
subtype_test:
new_type = type_value( static_link, parent, type );
if( IS_UNBOUND(new_type) )
{
its_a_number:
if( atom_to_integer( type, &count ) )
{
GET_NEXT_TYPE;
continue;
}
return USE(new_error( ERROR_NOT_A_TYPE_NAME, type ));
}
type = new_type;
goto try_again;
to_continue:
count--;
if( !count )
{
count = 1;
GET_NEXT_TYPE;
}
GET_NEXT_DATA;
}
return result ;
}
atom_t res = traverse( prototype, protodata );
if( IS_ERROR(res) ) return res;
if( mode==MEM_STRUCT_SIZE ) return new_integer( ofs );
return res;
}