- 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;
}