5d0c54bca2
[INTERPRETER] * BUG: Fix overflow detection in conversion functions. * BUG: Check for overflow detection only if the '__has_builtin' pseudo-macro is implemented by the compiler.
2194 lines
41 KiB
C
2194 lines
41 KiB
C
/***************************************************************************
|
|
|
|
gbx_value.c
|
|
|
|
(c) 2000-2017 Benoît Minisini <benoit.minisini@gambas-basic.org>
|
|
|
|
This program is free software; you can redistribute it and/or modify
|
|
it under the terms of the GNU General Public License as published by
|
|
the Free Software Foundation; either version 2, or (at your option)
|
|
any later version.
|
|
|
|
This program is distributed in the hope that it will be useful,
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
GNU General Public License for more details.
|
|
|
|
You should have received a copy of the GNU General Public License
|
|
along with this program; if not, write to the Free Software
|
|
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
|
|
MA 02110-1301, USA.
|
|
|
|
***************************************************************************/
|
|
|
|
#define __GBX_VALUE_C
|
|
|
|
#include "gb_common.h"
|
|
#include "gb_common_case.h"
|
|
#include "gb_overflow.h"
|
|
|
|
#include "gbx_math.h"
|
|
#include "gbx_type.h"
|
|
|
|
#include "gbx_c_array.h"
|
|
#include "gbx_string.h"
|
|
#include "gbx_number.h"
|
|
#include "gbx_object.h"
|
|
#include "gbx_variant.h"
|
|
#include "gbx_date.h"
|
|
#include "gbx_struct.h"
|
|
#include "gbx_exec.h"
|
|
#include "gbx_local.h"
|
|
#include "gb_common_buffer.h"
|
|
#include "gbx_extern.h"
|
|
|
|
#include "gbx_value.h"
|
|
|
|
#if 0
|
|
static bool unknown_function(VALUE *value)
|
|
{
|
|
if (value->_function.kind == FUNCTION_UNKNOWN)
|
|
{
|
|
EXEC_unknown_property = TRUE;
|
|
EXEC_unknown_name = CP->load->unknown[value->_function.index];
|
|
|
|
EXEC_special(SPEC_UNKNOWN, value->_function.class, value->_function.object, 0, FALSE);
|
|
|
|
//object = value->_function.object;
|
|
OBJECT_UNREF(value->_function.object);
|
|
|
|
SP--;
|
|
//*val = *SP;
|
|
COPY_VALUE(value, SP);
|
|
return TRUE;
|
|
}
|
|
else
|
|
return FALSE;
|
|
}
|
|
#endif
|
|
|
|
void THROW_TYPE(TYPE wanted, TYPE got)
|
|
{
|
|
THROW(E_TYPE, TYPE_get_name(wanted), TYPE_get_name(got));
|
|
}
|
|
|
|
static void undo_variant(VALUE *value)
|
|
{
|
|
static void *jump[16] = {
|
|
&&__VOID, &&__BOOLEAN, &&__BYTE, &&__SHORT, &&__INTEGER, &&__LONG, &&__SINGLE, &&__FLOAT, &&__DATE,
|
|
&&__STRING, &&__CSTRING, &&__POINTER, &&__VOID, &&__FUNCTION, &&__CLASS, &&__NULL
|
|
};
|
|
|
|
TYPE type = value->_variant.vtype;
|
|
|
|
//if (index != T_NULL)
|
|
// VALUE_read(value, &value->_variant.value, value->_variant.vtype);
|
|
|
|
value->type = type;
|
|
|
|
if (TYPE_is_object(type))
|
|
goto __OBJECT;
|
|
else
|
|
goto *jump[type];
|
|
|
|
__BOOLEAN:
|
|
|
|
value->_boolean.value = value->_variant.value._boolean ? -1 : 0;
|
|
return;
|
|
|
|
__BYTE:
|
|
|
|
value->_byte.value = value->_variant.value._byte;
|
|
return;
|
|
|
|
__SHORT:
|
|
|
|
value->_short.value = value->_variant.value._short;
|
|
return;
|
|
|
|
__INTEGER:
|
|
|
|
value->_integer.value = value->_variant.value._integer;
|
|
return;
|
|
|
|
__LONG:
|
|
|
|
value->_long.value = value->_variant.value._long;
|
|
return;
|
|
|
|
__SINGLE:
|
|
|
|
value->_single.value = value->_variant.value._single;
|
|
return;
|
|
|
|
__FLOAT:
|
|
|
|
value->_float.value = value->_variant.value._float;
|
|
return;
|
|
|
|
__DATE:
|
|
|
|
// It works, as the normal date field is before the variant date field!
|
|
value->_date.date = value->_variant.value._date.date;
|
|
value->_date.time = value->_variant.value._date.time;
|
|
return;
|
|
|
|
__STRING:
|
|
|
|
{
|
|
char *str = value->_variant.value._string;
|
|
|
|
value->type = T_STRING;
|
|
value->_string.addr = str;
|
|
value->_string.start = 0;
|
|
value->_string.len = STRING_length(str);
|
|
|
|
return;
|
|
}
|
|
|
|
__CSTRING:
|
|
|
|
{
|
|
char *str = value->_variant.value._string;
|
|
|
|
value->type = T_CSTRING;
|
|
value->_string.addr = str;
|
|
value->_string.start = 0;
|
|
value->_string.len = strlen(str);
|
|
|
|
return;
|
|
}
|
|
|
|
__OBJECT:
|
|
|
|
value->_object.object = value->_variant.value._object;
|
|
return;
|
|
|
|
__POINTER:
|
|
|
|
value->_pointer.value = value->_variant.value._pointer;
|
|
return;
|
|
|
|
__CLASS: // Is it useful for variants ?
|
|
|
|
value->_class.class = value->_variant.value._object;
|
|
value->_class.super = NULL;
|
|
return;
|
|
|
|
__NULL:
|
|
return;
|
|
|
|
__VOID:
|
|
__FUNCTION:
|
|
|
|
ERROR_panic("Bad type (%d) for undo_variant", type);
|
|
}
|
|
|
|
|
|
static void VALUE_put(VALUE *value, void *addr, TYPE type)
|
|
{
|
|
static void *jump[16] = {
|
|
&&__VOID, &&__BOOLEAN, &&__BYTE, &&__SHORT, &&__INTEGER, &&__LONG, &&__SINGLE, &&__FLOAT, &&__DATE,
|
|
&&__STRING, &&__STRING, &&__POINTER, &&__VARIANT, &&__FUNCTION, &&__CLASS, &&__NULL
|
|
};
|
|
|
|
VALUE_conv(value, type);
|
|
|
|
if (TYPE_is_object(type))
|
|
goto __OBJECT;
|
|
else
|
|
goto *jump[type];
|
|
|
|
__BOOLEAN:
|
|
|
|
*((unsigned char *)addr) = (value->_boolean.value != 0 ? 255 : 0);
|
|
return;
|
|
|
|
__BYTE:
|
|
|
|
*((unsigned char *)addr) = (unsigned char)(value->_byte.value);
|
|
return;
|
|
|
|
__SHORT:
|
|
|
|
*((short *)addr) = (short)(value->_short.value);
|
|
return;
|
|
|
|
__INTEGER:
|
|
|
|
*((int *)addr) = value->_integer.value;
|
|
return;
|
|
|
|
__LONG:
|
|
|
|
*((int64_t *)addr) = value->_long.value;
|
|
return;
|
|
|
|
__SINGLE:
|
|
|
|
*((float *)addr) = value->_single.value;
|
|
return;
|
|
|
|
__FLOAT:
|
|
|
|
*((double *)addr) = value->_float.value;
|
|
return;
|
|
|
|
__DATE:
|
|
|
|
/* Inverted, if value ~= addr */
|
|
|
|
((int *)addr)[1] = value->_date.time;
|
|
((int *)addr)[0] = value->_date.date;
|
|
return;
|
|
|
|
/*__STRING:
|
|
|
|
((int *)addr)[0] = (int)(value->_string.addr + value->_string.start);
|
|
((int *)addr)[1] = value->_string.len;
|
|
return;*/
|
|
|
|
__POINTER:
|
|
|
|
*((void **)addr) = value->_pointer.value;
|
|
return;
|
|
|
|
__OBJECT:
|
|
|
|
*((void **)addr) = value->_object.object;
|
|
return;
|
|
|
|
__VARIANT:
|
|
|
|
*((VARIANT *)addr) = *((VARIANT *)&value->_variant.vtype);
|
|
return;
|
|
|
|
__CLASS:
|
|
|
|
*((void **)addr) = value->_class.class;
|
|
return;
|
|
|
|
__VOID:
|
|
__FUNCTION:
|
|
__NULL:
|
|
__STRING:
|
|
|
|
ERROR_panic("Bad type (%d) for VALUE_put", type);
|
|
}
|
|
|
|
|
|
/* This function must keep the datatype, as it is used for initializing local variables */
|
|
|
|
void VALUE_default(VALUE *value, TYPE type)
|
|
{
|
|
static void *jump[16] = {
|
|
&&__VOID, &&__BOOLEAN, &&__BYTE, &&__SHORT, &&__INTEGER, &&__LONG, &&__SINGLE, &&__FLOAT, &&__DATE,
|
|
&&__STRING, &&__STRING, &&__POINTER, &&__VARIANT, &&__FUNCTION, &&__CLASS, &&__NULL
|
|
};
|
|
|
|
value->type = type;
|
|
|
|
if (TYPE_is_object(type))
|
|
goto __OBJECT;
|
|
else
|
|
goto *jump[type];
|
|
|
|
__BOOLEAN:
|
|
__BYTE:
|
|
__SHORT:
|
|
__INTEGER:
|
|
|
|
value->_integer.value = 0;
|
|
return;
|
|
|
|
__LONG:
|
|
|
|
value->_long.value = 0;
|
|
return;
|
|
|
|
__SINGLE:
|
|
value->_single.value = 0;
|
|
return;
|
|
|
|
__FLOAT:
|
|
value->_float.value = 0;
|
|
return;
|
|
|
|
__STRING:
|
|
value->_string.addr = NULL;
|
|
value->_string.start = 0;
|
|
value->_string.len = 0;
|
|
return;
|
|
|
|
__VARIANT:
|
|
value->_variant.vtype = T_NULL;
|
|
return;
|
|
|
|
__POINTER:
|
|
value->_pointer.value = NULL;
|
|
return;
|
|
|
|
__DATE:
|
|
value->_date.date = 0;
|
|
value->_date.time = 0;
|
|
return;
|
|
|
|
__VOID:
|
|
return;
|
|
|
|
__OBJECT:
|
|
value->_object.class = (CLASS *)type;
|
|
value->_object.object = NULL;
|
|
return;
|
|
|
|
__FUNCTION:
|
|
__CLASS:
|
|
__NULL:
|
|
ERROR_panic("VALUE_default: Unknown default type");
|
|
}
|
|
|
|
|
|
void VALUE_convert(VALUE *value, TYPE type)
|
|
{
|
|
static const void *jump[16][16] =
|
|
{
|
|
/* ,------> void b c h i l g f d cs s p v func class n */
|
|
// |
|
|
/* void */ { &&__OK, &&__NR, &&__NR, &&__NR, &&__NR, &&__NR, &&__NR, &&__NR, &&__NR, &&__NR, &&__NR, &&__NR, &&__NR, &&__NR, &&__NR, &&__NR, },
|
|
/* b */ { &&__N, &&__OK, &&__b2c, &&__b2h, &&__TYPE, &&__b2l, &&__b2g, &&__b2f, &&__N, &&__b2s, &&__b2s, &&__N, &&__2v, &&__N, &&__N, &&__N, },
|
|
/* c */ { &&__N, &&__c2b, &&__OK, &&__c2h, &&__TYPE, &&__c2l, &&__c2g, &&__c2f, &&__c2d, &&__c2s, &&__c2s, &&__N, &&__2v, &&__N, &&__N, &&__N, },
|
|
/* h */ { &&__N, &&__h2b, &&__h2c, &&__OK, &&__TYPE, &&__h2l, &&__h2g, &&__h2f, &&__h2d, &&__h2s, &&__h2s, &&__N, &&__2v, &&__N, &&__N, &&__N, },
|
|
/* i */ { &&__N, &&__i2b, &&__i2c, &&__i2h, &&__OK, &&__i2l, &&__i2g, &&__i2f, &&__i2d, &&__i2s, &&__i2s, &&__i2p, &&__2v, &&__N, &&__N, &&__N, },
|
|
/* l */ { &&__N, &&__l2b, &&__l2c, &&__l2h, &&__l2i, &&__OK, &&__l2g, &&__l2f, &&__l2d, &&__l2s, &&__l2s, &&__l2p, &&__2v, &&__N, &&__N, &&__N, },
|
|
/* g */ { &&__N, &&__g2b, &&__g2c, &&__g2h, &&__g2i, &&__g2l, &&__OK, &&__g2f, &&__g2d, &&__g2s, &&__g2s, &&__N, &&__2v, &&__N, &&__N, &&__N, },
|
|
/* f */ { &&__N, &&__f2b, &&__f2c, &&__f2h, &&__f2i, &&__f2l, &&__f2g, &&__OK, &&__f2d, &&__f2s, &&__f2s, &&__N, &&__2v, &&__N, &&__N, &&__N, },
|
|
/* d */ { &&__N, &&__d2b, &&__d2c, &&__d2h, &&__d2i, &&__d2l, &&__d2g, &&__d2f, &&__OK, &&__d2s, &&__d2s, &&__N, &&__2v, &&__N, &&__N, &&__N, },
|
|
/* cs */ { &&__N, &&__s2b, &&__s2c, &&__s2h, &&__s2i, &&__s2l, &&__s2g, &&__s2f, &&__s2d, &&__OK, &&__OK, &&__s2p, &&__s2v, &&__N, &&__N, &&__N, },
|
|
/* s */ { &&__N, &&__s2b, &&__s2c, &&__s2h, &&__s2i, &&__s2l, &&__s2g, &&__s2f, &&__s2d, &&__OK, &&__OK, &&__s2p, &&__s2v, &&__N, &&__N, &&__N, },
|
|
/* p */ { &&__N, &&__p2b, &&__N, &&__N, &&__p2i, &&__p2l, &&__N, &&__N, &&__N, &&__p2s, &&__p2s, &&__OK, &&__2v, &&__N, &&__N, &&__N, },
|
|
/* v */ { &&__N, &&__v2, &&__v2, &&__v2, &&__v2, &&__v2, &&__v2, &&__v2, &&__v2, &&__v2, &&__v2, &&__v2, &&__OK, &&__N, &&__v2, &&__v2, },
|
|
/* func */ { &&__N, &&__func, &&__func, &&__func, &&__func, &&__func, &&__func, &&__func, &&__func, &&__func, &&__func, &&__F2p, &&__func, &&__OK, &&__N, &&__func, },
|
|
/* class */ { &&__N, &&__N, &&__N, &&__N, &&__N, &&__N, &&__N, &&__N, &&__N, &&__N, &&__N, &&__N, &&__2v, &&__N, &&__OK, &&__N, },
|
|
/* null */ { &&__N, &&__n2b, &&__N, &&__N, &&__N, &&__N, &&__N, &&__N, &&__n2d, &&__n2s, &&__n2s, &&__n2p, &&__2v, &&__N, &&__N, &&__OK, },
|
|
};
|
|
|
|
int len;
|
|
char *addr;
|
|
CLASS *class;
|
|
bool test;
|
|
|
|
__CONV:
|
|
|
|
if ((type | value->type) >> 4)
|
|
goto __OBJECT;
|
|
else
|
|
goto *jump[value->type][type];
|
|
|
|
__c2b:
|
|
__h2b:
|
|
__i2b:
|
|
|
|
value->_integer.value = -(value->_integer.value != 0);
|
|
value->type = T_BOOLEAN;
|
|
return;
|
|
|
|
__l2b:
|
|
|
|
value->_integer.value = -(value->_long.value != 0);
|
|
value->type = T_BOOLEAN;
|
|
return;
|
|
|
|
__g2b:
|
|
|
|
value->_integer.value = -(value->_single.value != 0);
|
|
value->type = T_BOOLEAN;
|
|
return;
|
|
|
|
__f2b:
|
|
|
|
value->_integer.value = -(value->_float.value != 0);
|
|
value->type = T_BOOLEAN;
|
|
return;
|
|
|
|
__d2b:
|
|
value->_integer.value = -(value->_date.date != 0 || value->_date.time != 0);
|
|
value->type = T_BOOLEAN;
|
|
return;
|
|
|
|
__p2b:
|
|
value->_integer.value = -(value->_pointer.value != NULL);
|
|
value->type = T_BOOLEAN;
|
|
return;
|
|
|
|
#if DO_NOT_CHECK_OVERFLOW
|
|
|
|
__b2c:
|
|
__h2c:
|
|
__i2c:
|
|
value->_integer.value = (uchar)value->_integer.value;
|
|
value->type = T_BYTE;
|
|
return;
|
|
|
|
__l2c:
|
|
value->_integer.value = (uchar)value->_long.value;
|
|
value->type = T_BYTE;
|
|
return;
|
|
|
|
#else
|
|
|
|
__b2c:
|
|
value->_integer.value = (uchar)value->_integer.value;
|
|
value->type = T_BYTE;
|
|
return;
|
|
|
|
__h2c:
|
|
__i2c:
|
|
{
|
|
uchar result;
|
|
|
|
if (__builtin_add_overflow(value->_integer.value, 0, &result))
|
|
THROW_OVERFLOW();
|
|
value->_integer.value = result;
|
|
value->type = T_BYTE;
|
|
return;
|
|
}
|
|
|
|
__l2c:
|
|
{
|
|
uchar result;
|
|
|
|
if (__builtin_add_overflow(value->_long.value, 0, &result))
|
|
THROW_OVERFLOW();
|
|
value->_integer.value = result;
|
|
value->type = T_BYTE;
|
|
return;
|
|
}
|
|
|
|
#endif
|
|
|
|
__g2c:
|
|
|
|
value->_integer.value = (unsigned char)value->_single.value;
|
|
value->type = T_BYTE;
|
|
return;
|
|
|
|
__f2c:
|
|
|
|
value->_integer.value = (unsigned char)value->_float.value;
|
|
value->type = T_BYTE;
|
|
return;
|
|
|
|
#if DO_NOT_CHECK_OVERFLOW
|
|
|
|
__b2h:
|
|
__c2h:
|
|
__i2h:
|
|
value->type = T_SHORT;
|
|
return;
|
|
|
|
__l2h:
|
|
value->_integer.value = (short)value->_long.value;
|
|
value->type = T_SHORT;
|
|
return;
|
|
|
|
#else
|
|
|
|
__b2h:
|
|
__c2h:
|
|
value->type = T_SHORT;
|
|
return;
|
|
|
|
__i2h:
|
|
{
|
|
short result;
|
|
|
|
if (__builtin_add_overflow(value->_integer.value, 0, &result))
|
|
THROW_OVERFLOW();
|
|
value->_integer.value = result;
|
|
value->type = T_SHORT;
|
|
return;
|
|
}
|
|
|
|
__l2h:
|
|
{
|
|
short result;
|
|
|
|
if (__builtin_add_overflow(value->_long.value, 0, &result))
|
|
THROW_OVERFLOW();
|
|
value->_integer.value = result;
|
|
value->type = T_SHORT;
|
|
return;
|
|
}
|
|
|
|
#endif
|
|
|
|
__g2h:
|
|
|
|
value->_integer.value = (short)value->_single.value;
|
|
value->type = T_SHORT;
|
|
return;
|
|
|
|
__f2h:
|
|
|
|
value->_integer.value = (short)value->_float.value;
|
|
value->type = T_SHORT;
|
|
return;
|
|
|
|
#if DO_NOT_CHECK_OVERFLOW
|
|
|
|
__l2i:
|
|
value->_integer.value = (int)value->_long.value;
|
|
value->type = T_INTEGER;
|
|
return;
|
|
|
|
#else
|
|
|
|
__l2i:
|
|
if (__builtin_add_overflow(value->_long.value, 0, &value->_integer.value))
|
|
THROW_OVERFLOW();
|
|
value->type = T_INTEGER;
|
|
return;
|
|
|
|
#endif
|
|
|
|
__g2i:
|
|
|
|
value->_integer.value = (int)value->_single.value;
|
|
value->type = T_INTEGER;
|
|
return;
|
|
|
|
__f2i:
|
|
|
|
value->_integer.value = (int)value->_float.value;
|
|
value->type = T_INTEGER;
|
|
return;
|
|
|
|
__p2i:
|
|
|
|
value->_integer.value = (int)(intptr_t)value->_pointer.value;
|
|
value->type = T_INTEGER;
|
|
return;
|
|
|
|
__b2l:
|
|
__c2l:
|
|
__h2l:
|
|
__i2l:
|
|
|
|
value->_long.value = (int64_t)value->_integer.value;
|
|
value->type = T_LONG;
|
|
return;
|
|
|
|
__g2l:
|
|
|
|
value->_long.value = (int64_t)value->_single.value;
|
|
value->type = T_LONG;
|
|
return;
|
|
|
|
__f2l:
|
|
|
|
value->_long.value = (int64_t)value->_float.value;
|
|
value->type = T_LONG;
|
|
return;
|
|
|
|
__p2l:
|
|
|
|
value->_long.value = (int64_t)(intptr_t)value->_pointer.value;
|
|
value->type = T_LONG;
|
|
return;
|
|
|
|
__b2g:
|
|
__c2g:
|
|
__h2g:
|
|
__i2g:
|
|
|
|
value->_single.value = value->_integer.value;
|
|
value->type = T_SINGLE;
|
|
return;
|
|
|
|
__l2g:
|
|
|
|
value->_single.value = (float)value->_long.value;
|
|
if (!isfinite(value->_single.value))
|
|
THROW(E_OVERFLOW);
|
|
value->type = T_SINGLE;
|
|
return;
|
|
|
|
__f2g:
|
|
|
|
value->_single.value = (float)value->_float.value;
|
|
if (!isfinite(value->_single.value))
|
|
THROW(E_OVERFLOW);
|
|
value->type = T_SINGLE;
|
|
return;
|
|
|
|
__b2f:
|
|
__c2f:
|
|
__h2f:
|
|
__i2f:
|
|
|
|
value->_float.value = value->_integer.value;
|
|
value->type = T_FLOAT;
|
|
return;
|
|
|
|
__l2f:
|
|
|
|
value->_float.value = value->_long.value;
|
|
value->type = T_FLOAT;
|
|
return;
|
|
|
|
__g2f:
|
|
|
|
value->_float.value = value->_single.value;
|
|
value->type = T_FLOAT;
|
|
return;
|
|
|
|
__c2d:
|
|
__h2d:
|
|
__i2d:
|
|
|
|
value->_date.date = Max(0, value->_integer.value);
|
|
value->_date.time = 0;
|
|
value->type = T_DATE;
|
|
return;
|
|
|
|
__l2d:
|
|
|
|
if (value->_long.value < 0)
|
|
value->_date.date = 0;
|
|
else if (value->_long.value > INT_MAX)
|
|
value->_date.date = INT_MAX;
|
|
else
|
|
value->_date.date = (int)value->_long.value;
|
|
|
|
value->_date.time = 0;
|
|
value->type = T_DATE;
|
|
return;
|
|
|
|
__g2d:
|
|
{
|
|
float val = value->_single.value;
|
|
float ival = floorf(val);
|
|
value->_date.time = (int)((val - ival) * 86400000.0 + 0.5);
|
|
value->_date.date = (int)ival;
|
|
value->type = T_DATE;
|
|
return;
|
|
}
|
|
|
|
__f2d:
|
|
{
|
|
double val = value->_float.value;
|
|
double ival = floor(val);
|
|
value->_date.time = (int)((val - ival) * 86400000.0 + 0.5);
|
|
value->_date.date = (int)ival;
|
|
value->type = T_DATE;
|
|
return;
|
|
}
|
|
|
|
__d2c:
|
|
__d2h:
|
|
__d2i:
|
|
|
|
value->_integer.value = value->_date.date;
|
|
value->type = T_INTEGER;
|
|
goto *jump[T_INTEGER][type];
|
|
|
|
__d2l:
|
|
|
|
value->_long.value = value->_date.date;
|
|
value->type = T_LONG;
|
|
return;
|
|
|
|
__d2g:
|
|
|
|
value->_single.value = (float)value->_date.date + (float)value->_date.time / 86400000.0;
|
|
value->type = T_SINGLE;
|
|
return;
|
|
|
|
__d2f:
|
|
|
|
value->_float.value = (double)value->_date.date + (double)value->_date.time / 86400000.0;
|
|
value->type = T_FLOAT;
|
|
return;
|
|
|
|
__b2s:
|
|
|
|
if (value->_boolean.value)
|
|
STRING_char_value(value, 'T');
|
|
else
|
|
STRING_void_value(value);
|
|
return;
|
|
|
|
__c2s:
|
|
__h2s:
|
|
__i2s:
|
|
|
|
/*len = sprintf(COMMON_buffer, "%d", value->_integer.value);
|
|
STRING_new_temp_value(value, COMMON_buffer, len);*/
|
|
NUMBER_int_to_string(value->_integer.value, 0, 10, value);
|
|
BORROW(value);
|
|
return;
|
|
|
|
__l2s:
|
|
|
|
/*len = sprintf(COMMON_buffer, "%" PRId64, value->_long.value);
|
|
STRING_new_temp_value(value, COMMON_buffer, len);*/
|
|
NUMBER_int_to_string(value->_long.value, 0, 10, value);
|
|
BORROW(value);
|
|
return;
|
|
|
|
__g2s:
|
|
|
|
LOCAL_format_number(value->_single.value, LF_GENERAL_NUMBER, NULL, 0, &addr, &len, FALSE);
|
|
STRING_new_temp_value(value, addr, len);
|
|
BORROW(value);
|
|
return;
|
|
|
|
__f2s:
|
|
|
|
LOCAL_format_number(value->_float.value, LF_GENERAL_NUMBER, NULL, 0, &addr, &len, FALSE);
|
|
STRING_new_temp_value(value, addr, len);
|
|
BORROW(value);
|
|
return;
|
|
|
|
__p2s:
|
|
#if OS_64BITS
|
|
NUMBER_int_to_string((int64_t)(intptr_t)value->_pointer.value, 0, 16, value);
|
|
#else
|
|
NUMBER_int_to_string((int)(intptr_t)value->_pointer.value, 0, 16, value);
|
|
#endif
|
|
BORROW(value);
|
|
return;
|
|
|
|
__d2s:
|
|
|
|
len = DATE_to_string(COMMON_buffer, value);
|
|
STRING_new_temp_value(value, COMMON_buffer, len);
|
|
BORROW(value);
|
|
return;
|
|
|
|
__s2b:
|
|
|
|
addr = value->_string.addr;
|
|
value->_integer.value = -(addr != NULL && value->_string.len != 0);
|
|
if (value->type == T_STRING)
|
|
STRING_unref(&addr);
|
|
value->type = T_BOOLEAN;
|
|
return;
|
|
|
|
__s2c:
|
|
__s2h:
|
|
__s2i:
|
|
|
|
addr = value->type == T_STRING ? value->_string.addr : NULL;
|
|
|
|
if (NUMBER_from_string(NB_READ_INTEGER, value->_string.addr + value->_string.start, value->_string.len, value))
|
|
goto __N;
|
|
|
|
STRING_unref(&addr);
|
|
goto *jump[T_INTEGER][type];
|
|
|
|
__s2l:
|
|
|
|
addr = value->type == T_STRING ? value->_string.addr : NULL;
|
|
|
|
if (NUMBER_from_string(NB_READ_LONG, value->_string.addr + value->_string.start, value->_string.len, value))
|
|
goto __N;
|
|
|
|
STRING_unref(&addr);
|
|
return;
|
|
|
|
__s2g:
|
|
|
|
addr = value->type == T_STRING ? value->_string.addr : NULL;
|
|
|
|
if (NUMBER_from_string(NB_READ_FLOAT, value->_string.addr + value->_string.start, value->_string.len, value))
|
|
goto __N;
|
|
|
|
value->_single.value = value->_float.value;
|
|
|
|
STRING_unref(&addr);
|
|
value->type = type;
|
|
return;
|
|
|
|
__s2f:
|
|
|
|
addr = value->type == T_STRING ? value->_string.addr : NULL;
|
|
|
|
if (NUMBER_from_string(NB_READ_FLOAT, value->_string.addr + value->_string.start, value->_string.len, value))
|
|
goto __N;
|
|
|
|
STRING_unref(&addr);
|
|
value->type = type;
|
|
return;
|
|
|
|
__s2d:
|
|
|
|
addr = value->type == T_STRING ? value->_string.addr : NULL;
|
|
|
|
if (DATE_from_string(value->_string.addr + value->_string.start, value->_string.len, value, FALSE))
|
|
goto __N;
|
|
|
|
STRING_unref(&addr);
|
|
return;
|
|
|
|
__s2p:
|
|
|
|
value->_pointer.value = value->_string.addr + value->_string.start;
|
|
value->type = T_POINTER;
|
|
return;
|
|
|
|
__n2b:
|
|
|
|
value->_integer.value = 0;
|
|
value->type = T_BOOLEAN;
|
|
return;
|
|
|
|
__n2d:
|
|
|
|
DATE_void_value(value);
|
|
return;
|
|
|
|
__n2s:
|
|
|
|
STRING_void_value(value);
|
|
return;
|
|
|
|
__n2p:
|
|
|
|
value->_pointer.value = 0;
|
|
value->type = T_POINTER;
|
|
return;
|
|
|
|
__v2:
|
|
|
|
undo_variant(value);
|
|
goto __CONV;
|
|
|
|
__s2v:
|
|
|
|
addr = STRING_copy_from_value_temp(value);
|
|
|
|
if (addr != value->_string.addr)
|
|
{
|
|
STRING_ref(addr);
|
|
|
|
if (value->type == T_STRING)
|
|
STRING_unref(&value->_string.addr);
|
|
}
|
|
|
|
value->_variant.vtype = T_STRING; //value->type;
|
|
value->_variant.value._string = addr;
|
|
value->type = T_VARIANT;
|
|
return;
|
|
|
|
__2v:
|
|
|
|
/* VALUE_put ne fonctionne pas avec T_STRING ! */
|
|
if (value->type != T_NULL)
|
|
VALUE_put(value, &value->_variant.value, value->type);
|
|
|
|
value->_variant.vtype = value->type;
|
|
value->type = T_VARIANT;
|
|
return;
|
|
|
|
__func:
|
|
|
|
goto __N;
|
|
|
|
__i2p:
|
|
value->_pointer.value = (void *)(intptr_t)value->_integer.value;
|
|
value->type = T_POINTER;
|
|
return;
|
|
|
|
__l2p:
|
|
value->_pointer.value = (void *)(intptr_t)value->_long.value;
|
|
value->type = T_POINTER;
|
|
return;
|
|
|
|
__F2p:
|
|
|
|
value->_pointer.value = EXTERN_make_callback(&value->_function);
|
|
value->type = T_POINTER;
|
|
return;
|
|
|
|
__OBJECT:
|
|
|
|
if (!TYPE_is_object(type))
|
|
{
|
|
if (type == T_BOOLEAN)
|
|
{
|
|
test = (value->_object.object != NULL);
|
|
OBJECT_UNREF(value->_object.object);
|
|
value->_boolean.value = -test;
|
|
value->type = T_BOOLEAN;
|
|
return;
|
|
}
|
|
|
|
if (type == T_VARIANT)
|
|
goto __2v;
|
|
|
|
if (!value->_object.object)
|
|
goto __N;
|
|
|
|
if (value->type == T_OBJECT)
|
|
class = OBJECT_class(value->_object.object);
|
|
else
|
|
class = value->_object.class;
|
|
|
|
if (class->has_convert)
|
|
{
|
|
void *unref = value->_object.object;
|
|
TYPE old_type = value->type;
|
|
|
|
if (!((*class->convert)(value->_object.object, type, value)))
|
|
{
|
|
OBJECT_UNREF(unref);
|
|
|
|
if (value->type == old_type)
|
|
goto __TYPE;
|
|
else
|
|
goto __OK;
|
|
}
|
|
}
|
|
|
|
goto __N;
|
|
}
|
|
|
|
if (!TYPE_is_object(value->type))
|
|
{
|
|
if (value->type == T_NULL)
|
|
{
|
|
OBJECT_null(value, (CLASS *)type); // Also works if type == T_OBJECT
|
|
goto __TYPE;
|
|
}
|
|
|
|
if (value->type == T_POINTER && type != T_OBJECT)
|
|
{
|
|
class = (CLASS *)type;
|
|
|
|
if (CLASS_is_struct(class))
|
|
{
|
|
value->_object.object = CSTRUCT_create_static(STRUCT_CONST, class, value->_pointer.value);
|
|
OBJECT_REF(value->_object.object);
|
|
goto __TYPE;
|
|
}
|
|
}
|
|
|
|
if (value->type == T_VARIANT)
|
|
goto __v2;
|
|
|
|
if (value->type == T_FUNCTION)
|
|
goto __func;
|
|
|
|
if (value->type == T_CLASS)
|
|
{
|
|
class = value->_class.class;
|
|
|
|
if (CLASS_is_virtual(class))
|
|
THROW(E_VIRTUAL);
|
|
|
|
CLASS_load(class);
|
|
|
|
if (class->auto_create)
|
|
value->_object.object = CLASS_auto_create(class, 0);
|
|
else
|
|
value->_object.object = class;
|
|
|
|
OBJECT_REF(value->_object.object);
|
|
value->type = T_OBJECT;
|
|
/* on continue... */
|
|
}
|
|
else
|
|
{
|
|
if (TYPE_is_pure_object(type))
|
|
{
|
|
class = (CLASS *)type;
|
|
|
|
if (class->has_convert)
|
|
{
|
|
if (!((*class->convert)(NULL, value->type, value)))
|
|
{
|
|
OBJECT_REF_CHECK(value->_object.object);
|
|
goto __TYPE;
|
|
}
|
|
}
|
|
}
|
|
|
|
goto __N;
|
|
}
|
|
}
|
|
|
|
if (value->_object.object == NULL)
|
|
goto __TYPE;
|
|
|
|
if (value->type == T_OBJECT)
|
|
class = OBJECT_class(value->_object.object);
|
|
else
|
|
class = value->_object.class;
|
|
|
|
if (CLASS_is_virtual(class))
|
|
THROW(E_VIRTUAL);
|
|
|
|
if (type == T_OBJECT)
|
|
goto __TYPE;
|
|
|
|
__RETRY:
|
|
|
|
if ((class == (CLASS *)type) || CLASS_inherits(class, (CLASS *)type))
|
|
goto __TYPE;
|
|
|
|
if (value->type != T_OBJECT && value->_object.object)
|
|
{
|
|
class = OBJECT_class(value->_object.object);
|
|
value->type = T_OBJECT;
|
|
goto __RETRY;
|
|
}
|
|
|
|
if (class->has_convert)
|
|
{
|
|
void *unref = value->_object.object;
|
|
if (!((*class->convert)(value->_object.object, type, value)))
|
|
{
|
|
OBJECT_UNREF(unref);
|
|
OBJECT_REF_CHECK(value->_object.object);
|
|
goto __TYPE;
|
|
}
|
|
}
|
|
|
|
CLASS *class2 = (CLASS *)type;
|
|
if (class2->has_convert)
|
|
{
|
|
void *unref = value->_object.object;
|
|
if (!((*class2->convert)(NULL, OBJECT_class(unref), value)))
|
|
{
|
|
OBJECT_UNREF(unref);
|
|
OBJECT_REF_CHECK(value->_object.object);
|
|
goto __TYPE;
|
|
}
|
|
}
|
|
|
|
THROW_TYPE(type, (TYPE)class);
|
|
|
|
__TYPE:
|
|
|
|
value->type = type;
|
|
|
|
__OK:
|
|
|
|
return;
|
|
|
|
__N:
|
|
|
|
THROW_TYPE(type, value->type);
|
|
|
|
__NR:
|
|
|
|
THROW(E_NRETURN);
|
|
}
|
|
|
|
|
|
void VALUE_write_variant(VALUE *value, void *addr)
|
|
{
|
|
static void *jump[16] = {
|
|
&&__VOID, &&__BOOLEAN, &&__BYTE, &&__SHORT, &&__INTEGER, &&__LONG, &&__SINGLE, &&__FLOAT, &&__DATE,
|
|
&&__STRING, &&__CSTRING, &&__POINTER, &&__VOID, &&__VOID, &&__CLASS, &&__NULL
|
|
};
|
|
|
|
TYPE type = value->_variant.vtype;
|
|
|
|
if (TYPE_is_object(type))
|
|
goto __OBJECT;
|
|
else
|
|
goto *jump[type];
|
|
|
|
__BOOLEAN:
|
|
__BYTE:
|
|
__SHORT:
|
|
__INTEGER:
|
|
__LONG:
|
|
__SINGLE:
|
|
__FLOAT:
|
|
__DATE:
|
|
__POINTER:
|
|
__NULL:
|
|
|
|
VARIANT_free((VARIANT *)addr);
|
|
((VARIANT *)addr)->type = value->_variant.vtype;
|
|
((VARIANT *)addr)->value.data = value->_variant.value.data;
|
|
return;
|
|
|
|
__CSTRING:
|
|
__STRING:
|
|
{
|
|
char *str = value->_variant.value._string;
|
|
STRING_ref(str);
|
|
VARIANT_free((VARIANT *)addr);
|
|
((VARIANT *)addr)->type = GB_T_STRING;
|
|
((VARIANT *)addr)->value._string = str;
|
|
return;
|
|
}
|
|
|
|
__OBJECT:
|
|
__CLASS:
|
|
{
|
|
void *object = value->_variant.value._object;
|
|
OBJECT_REF_CHECK(object);
|
|
VARIANT_free((VARIANT *)addr);
|
|
((VARIANT *)addr)->type = type;
|
|
((VARIANT *)addr)->value._object = object;
|
|
return;
|
|
}
|
|
|
|
__VOID:
|
|
|
|
ERROR_panic("Bad type (%d) for VALUE_write_variant", type);
|
|
}
|
|
|
|
void VALUE_write(VALUE *value, void *addr, TYPE type)
|
|
{
|
|
static void *jump[16] = {
|
|
&&__VOID, &&__BOOLEAN, &&__BYTE, &&__SHORT, &&__INTEGER, &&__LONG, &&__SINGLE, &&__FLOAT, &&__DATE,
|
|
&&__STRING, &&__STRING, &&__POINTER, &&__VARIANT, &&__FUNCTION, &&__CLASS, &&__NULL
|
|
};
|
|
|
|
char *str;
|
|
|
|
__CONV:
|
|
|
|
if (TYPE_is_object(type))
|
|
goto __OBJECT;
|
|
else
|
|
goto *jump[type];
|
|
|
|
__BOOLEAN:
|
|
|
|
VALUE_conv_boolean(value);
|
|
*((unsigned char *)addr) = (value->_boolean.value != 0 ? 255 : 0);
|
|
return;
|
|
|
|
__BYTE:
|
|
|
|
VALUE_conv(value, T_BYTE);
|
|
*((unsigned char *)addr) = (unsigned char)(value->_byte.value);
|
|
return;
|
|
|
|
__SHORT:
|
|
|
|
VALUE_conv(value, T_SHORT);
|
|
*((short *)addr) = (short)(value->_short.value);
|
|
return;
|
|
|
|
__INTEGER:
|
|
|
|
VALUE_conv_integer(value);
|
|
*((int *)addr) = value->_integer.value;
|
|
return;
|
|
|
|
__LONG:
|
|
|
|
VALUE_conv(value, T_LONG);
|
|
*((int64_t *)addr) = value->_long.value;
|
|
return;
|
|
|
|
__SINGLE:
|
|
|
|
VALUE_conv(value, T_SINGLE);
|
|
*((float *)addr) = value->_single.value;
|
|
return;
|
|
|
|
__FLOAT:
|
|
|
|
VALUE_conv_float(value);
|
|
*((double *)addr) = value->_float.value;
|
|
return;
|
|
|
|
__DATE:
|
|
|
|
VALUE_conv(value, T_DATE);
|
|
((int *)addr)[0] = value->_date.date;
|
|
((int *)addr)[1] = value->_date.time;
|
|
return;
|
|
|
|
__STRING:
|
|
|
|
VALUE_conv_string(value);
|
|
|
|
str = STRING_copy_from_value_temp(value);
|
|
STRING_ref(str);
|
|
STRING_unref((char **)addr);
|
|
*((char **)addr) = str;
|
|
return;
|
|
|
|
__OBJECT:
|
|
|
|
VALUE_conv(value, type);
|
|
|
|
OBJECT_REF_CHECK(value->_object.object);
|
|
OBJECT_UNREF(*((void **)addr));
|
|
*((void **)addr) = value->_object.object;
|
|
return;
|
|
|
|
__CLASS:
|
|
|
|
VALUE_conv(value, type);
|
|
|
|
OBJECT_REF(value->_class.class);
|
|
OBJECT_UNREF(*((void **)addr));
|
|
*((void **)addr) = value->_class.class;
|
|
return;
|
|
|
|
__POINTER:
|
|
|
|
VALUE_conv(value, T_POINTER);
|
|
*((void **)addr) = value->_pointer.value;
|
|
return;
|
|
|
|
__VARIANT:
|
|
|
|
VARIANT_undo(value);
|
|
|
|
type = value->type;
|
|
if (type == T_CSTRING)
|
|
type = T_STRING;
|
|
|
|
VARIANT_clear((VARIANT *)addr);
|
|
((VARIANT *)addr)->type = type;
|
|
|
|
/* Et si type ne fait pas partie des types valides pour cette fonction ?? */
|
|
if (type == T_NULL)
|
|
return;
|
|
|
|
addr = &((VARIANT *)addr)->value.data;
|
|
/*goto *jump[Min(T_OBJECT, type)];*/
|
|
goto __CONV;
|
|
|
|
__VOID:
|
|
|
|
THROW(E_NRETURN);
|
|
|
|
__FUNCTION:
|
|
|
|
THROW_TYPE(T_VARIANT, type);
|
|
|
|
__NULL:
|
|
|
|
ERROR_panic("Bad type (%d) for VALUE_write", type);
|
|
}
|
|
|
|
|
|
|
|
void VALUE_read(VALUE *value, void *addr, TYPE type)
|
|
{
|
|
static void *jump[16] = {
|
|
&&__VOID, &&__BOOLEAN, &&__BYTE, &&__SHORT, &&__INTEGER, &&__LONG, &&__SINGLE, &&__FLOAT, &&__DATE,
|
|
&&__STRING, &&__CSTRING, &&__POINTER, &&__VARIANT, &&__FUNCTION, &&__CLASS, &&__NULL
|
|
};
|
|
|
|
value->type = type;
|
|
|
|
if (TYPE_is_object(type))
|
|
goto __OBJECT;
|
|
else
|
|
goto *jump[type];
|
|
|
|
__BOOLEAN:
|
|
|
|
value->_boolean.value = (*((unsigned char *)addr) != 0) ? (-1) : 0;
|
|
return;
|
|
|
|
__BYTE:
|
|
|
|
value->_byte.value = *((unsigned char *)addr);
|
|
return;
|
|
|
|
__SHORT:
|
|
|
|
value->_short.value = *((short *)addr);
|
|
return;
|
|
|
|
__INTEGER:
|
|
|
|
value->_integer.value = *((int *)addr);
|
|
return;
|
|
|
|
__LONG:
|
|
|
|
value->_long.value = *((int64_t *)addr);
|
|
return;
|
|
|
|
__SINGLE:
|
|
|
|
value->_single.value = *((float *)addr);
|
|
return;
|
|
|
|
__FLOAT:
|
|
|
|
value->_float.value = *((double *)addr);
|
|
return;
|
|
|
|
__DATE:
|
|
|
|
value->_date.date = ((int *)addr)[0];
|
|
value->_date.time = ((int *)addr)[1];
|
|
return;
|
|
|
|
__STRING:
|
|
|
|
{
|
|
char *str = *((char **)addr);
|
|
|
|
value->type = T_STRING;
|
|
value->_string.addr = str;
|
|
value->_string.start = 0;
|
|
value->_string.len = STRING_length(str);
|
|
|
|
return;
|
|
}
|
|
|
|
__CSTRING:
|
|
|
|
{
|
|
char *str = *((char **)addr);
|
|
|
|
value->type = T_CSTRING;
|
|
value->_string.addr = str;
|
|
value->_string.start = 0;
|
|
value->_string.len = (str == NULL) ? 0 : strlen(str);
|
|
|
|
return;
|
|
}
|
|
|
|
__OBJECT:
|
|
|
|
value->_object.object = *((void **)addr);
|
|
return;
|
|
|
|
__POINTER:
|
|
|
|
value->_pointer.value = *((void **)addr);
|
|
return;
|
|
|
|
__VARIANT:
|
|
|
|
value->_variant.type = T_VARIANT;
|
|
value->_variant.vtype = ((VARIANT *)addr)->type;
|
|
|
|
if (value->_variant.vtype == T_VOID)
|
|
value->_variant.vtype = T_NULL;
|
|
|
|
VARIANT_copy_value(&value->_variant, ((VARIANT *)addr));
|
|
|
|
return;
|
|
|
|
__CLASS:
|
|
|
|
value->_class.class = *((void **)addr);
|
|
value->_class.super = NULL;
|
|
return;
|
|
|
|
__VOID:
|
|
__FUNCTION:
|
|
__NULL:
|
|
|
|
ERROR_panic("Bad type (%d) for VALUE_read", type);
|
|
}
|
|
|
|
|
|
void VALUE_free(void *addr, TYPE type)
|
|
{
|
|
if (type == T_STRING)
|
|
{
|
|
STRING_unref((char **)addr);
|
|
*((char **)addr) = NULL;
|
|
}
|
|
else if (TYPE_is_object(type))
|
|
{
|
|
OBJECT_UNREF(*((void **)addr));
|
|
*((void **)addr) = NULL;
|
|
}
|
|
else if (type == T_VARIANT)
|
|
{
|
|
VARIANT_free((VARIANT *)addr);
|
|
((VARIANT *)addr)->type = T_NULL;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
void VALUE_to_local_string(VALUE *value, char **addr, int *len)
|
|
{
|
|
static void *jump[16] = {
|
|
&&__VOID, &&__BOOLEAN, &&__BYTE, &&__SHORT, &&__INTEGER, &&__LONG, &&__SINGLE, &&__FLOAT, &&__DATE,
|
|
&&__STRING, &&__STRING, &&__POINTER, &&__VARIANT, &&__FUNCTION, &&__CLASS, &&__NULL
|
|
};
|
|
|
|
__CONV:
|
|
|
|
if (TYPE_is_object(value->type))
|
|
goto __OBJECT;
|
|
else
|
|
goto *jump[value->type];
|
|
|
|
__NULL:
|
|
|
|
*addr = ""; // To be coherent with Print "", as Null == "" */
|
|
*len = 0;
|
|
return;
|
|
|
|
__BOOLEAN:
|
|
|
|
if (value->_boolean.value)
|
|
{
|
|
*addr = LOCAL_local.true_str;
|
|
*len = LOCAL_local.len_true_str;
|
|
}
|
|
else
|
|
{
|
|
*addr = LOCAL_local.false_str;
|
|
*len = LOCAL_local.len_false_str;
|
|
}
|
|
return;
|
|
|
|
__BYTE:
|
|
__SHORT:
|
|
__INTEGER:
|
|
|
|
*len = sprintf(COMMON_buffer, "%d", value->_integer.value);
|
|
*addr = COMMON_buffer;
|
|
|
|
return;
|
|
|
|
__LONG:
|
|
|
|
*len = sprintf(COMMON_buffer, "%" PRId64, value->_long.value);
|
|
*addr = COMMON_buffer;
|
|
|
|
return;
|
|
|
|
__DATE:
|
|
{
|
|
const DATE_SERIAL *date = DATE_split(value);
|
|
LOCAL_format_date(date, DATE_SERIAL_has_no_date(date) ? LF_LONG_TIME : LF_STANDARD, NULL, 0, addr, len);
|
|
return;
|
|
}
|
|
|
|
__SINGLE:
|
|
|
|
LOCAL_format_number(value->_single.value, LF_SHORT_NUMBER, NULL, 0, addr, len, TRUE);
|
|
return;
|
|
|
|
__FLOAT:
|
|
|
|
LOCAL_format_number(value->_float.value, LF_STANDARD, NULL, 0, addr, len, TRUE);
|
|
return;
|
|
|
|
__STRING:
|
|
|
|
*len = value->_string.len;
|
|
*addr = value->_string.addr + value->_string.start;
|
|
return;
|
|
|
|
__OBJECT:
|
|
|
|
{
|
|
CLASS *class;
|
|
|
|
if (VALUE_is_null(value))
|
|
goto __NULL;
|
|
|
|
class = OBJECT_class(value->_object.object);
|
|
if (class->has_convert)
|
|
{
|
|
VALUE temp;
|
|
if (!((*class->convert)(value->_object.object, T_CSTRING, &temp)))
|
|
{
|
|
*addr = temp._string.addr + temp._string.start;
|
|
*len = temp._string.len;
|
|
STRING_free_later(*addr);
|
|
return;
|
|
}
|
|
}
|
|
|
|
*len = sprintf(COMMON_buffer, "(%s %p)", class->name, value->_object.object);
|
|
*addr = COMMON_buffer;
|
|
return;
|
|
}
|
|
|
|
__POINTER:
|
|
|
|
if (VALUE_is_null(value))
|
|
goto __NULL;
|
|
|
|
*len = sprintf(COMMON_buffer, "(Pointer %p)", value->_pointer.value);
|
|
*addr = COMMON_buffer;
|
|
return;
|
|
|
|
__VARIANT:
|
|
|
|
VARIANT_undo(value);
|
|
goto __CONV;
|
|
|
|
__VOID:
|
|
|
|
THROW(E_NRETURN);
|
|
|
|
__CLASS:
|
|
|
|
*len = sprintf(COMMON_buffer, "(Class %s)", value->_class.class->name);
|
|
*addr = COMMON_buffer;
|
|
return;
|
|
|
|
__FUNCTION:
|
|
|
|
//if (unknown_function(value))
|
|
// goto __CONV;
|
|
|
|
*len = sprintf(COMMON_buffer, "(Function %s:%d)", value->_function.class->name, value->_function.index);
|
|
*addr = COMMON_buffer;
|
|
}
|
|
|
|
|
|
void VALUE_from_local_string(VALUE *value, const char *addr, int len)
|
|
{
|
|
while (len > 0 && isspace(*addr))
|
|
addr++, len--;
|
|
|
|
while (len > 0 && isspace(addr[len - 1]))
|
|
len--;
|
|
|
|
if (len > 0)
|
|
{
|
|
if (!DATE_from_string(addr, len, value, TRUE))
|
|
return;
|
|
|
|
if (!NUMBER_from_string(NB_READ_ALL | NB_READ_HEX_BIN | NB_LOCAL, addr, len, value))
|
|
return;
|
|
|
|
if (len == LOCAL_local.len_true_str && strncasecmp(addr, LOCAL_local.true_str, len) == 0)
|
|
{
|
|
value->type = T_BOOLEAN;
|
|
value->_boolean.value = -1;
|
|
return;
|
|
}
|
|
|
|
if (len == LOCAL_local.len_false_str && strncasecmp(addr, LOCAL_local.false_str, len) == 0)
|
|
{
|
|
value->type = T_BOOLEAN;
|
|
value->_boolean.value = 0;
|
|
return;
|
|
}
|
|
}
|
|
|
|
VALUE_null(value);
|
|
}
|
|
|
|
|
|
void VALUE_class_read(CLASS *class, VALUE *value, char *addr, CTYPE ctype, void *ref)
|
|
{
|
|
VALUE_class_read_inline(class, value, addr, ctype, ref, VCR);
|
|
}
|
|
|
|
void VALUE_class_write(CLASS *class, VALUE *value, char *addr, CTYPE ctype)
|
|
{
|
|
if (ctype.id == T_OBJECT)
|
|
{
|
|
TYPE type = (ctype.value >= 0) ? (TYPE)class->load->class_ref[ctype.value] : T_OBJECT;
|
|
|
|
VALUE_conv(value, type);
|
|
|
|
OBJECT_REF_CHECK(value->_object.object);
|
|
OBJECT_UNREF(*((void **)addr));
|
|
*((void **)addr) = value->_object.object;
|
|
}
|
|
else if (ctype.id == TC_STRUCT)
|
|
{
|
|
int i;
|
|
CLASS *sclass;
|
|
CLASS_DESC *desc;
|
|
void *src;
|
|
char *saddr;
|
|
VALUE temp;
|
|
int offset;
|
|
|
|
sclass = class->load->class_ref[ctype.value];
|
|
VALUE_conv(value, (TYPE)sclass);
|
|
src = value->_object.object;
|
|
|
|
for (i = 0; i < sclass->n_desc; i++)
|
|
{
|
|
desc = sclass->table[i].desc;
|
|
ctype = desc->variable.ctype;
|
|
offset = desc->variable.offset;
|
|
|
|
if (((CSTRUCT *)src)->ref)
|
|
saddr = (char *)((CSTATICSTRUCT *)src)->addr;
|
|
else
|
|
saddr = (char *)src + sizeof(CSTRUCT);
|
|
|
|
VALUE_class_read(desc->variable.class, &temp, &saddr[offset], ctype, src);
|
|
//BORROW(&temp);
|
|
VALUE_class_write(sclass, &temp, &addr[offset], ctype);
|
|
RELEASE(&temp);
|
|
}
|
|
}
|
|
else if (ctype.id == TC_ARRAY)
|
|
{
|
|
CLASS_ARRAY *adesc = class->load->array[ctype.value];
|
|
CLASS *aclass = CARRAY_get_array_class(class, adesc->ctype);
|
|
int acount = CARRAY_get_static_count(adesc);
|
|
int i, count;
|
|
CARRAY *src;
|
|
VALUE temp;
|
|
char *saddr;
|
|
|
|
VALUE_conv(value, (TYPE)aclass);
|
|
src = (CARRAY *)value->_object.object;
|
|
|
|
ctype = adesc->ctype;
|
|
|
|
count = src->count;
|
|
if (count > acount)
|
|
count = acount;
|
|
|
|
saddr = CARRAY_get_data(src, 0);
|
|
|
|
for (i = 0; i < count; i++)
|
|
{
|
|
VALUE_class_read(class, &temp, saddr, ctype, src);
|
|
//BORROW(&temp);
|
|
VALUE_class_write(class, &temp, addr, ctype);
|
|
RELEASE(&temp);
|
|
saddr += src->size;
|
|
addr += src->size;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
VALUE_write(value, addr, (TYPE)ctype.id);
|
|
}
|
|
}
|
|
|
|
void VALUE_class_constant(CLASS *class, VALUE *value, int ind)
|
|
{
|
|
VALUE_class_constant_inline(class, value, ind);
|
|
}
|
|
|
|
|
|
bool VALUE_is_null(VALUE *val)
|
|
{
|
|
static void *jump[16] = {
|
|
&&__FALSE, &&__FALSE, &&__FALSE, &&__FALSE, &&__FALSE, &&__FALSE, &&__FALSE, &&__FALSE, &&__DATE,
|
|
&&__STRING, &&__STRING, &&__POINTER, &&__VARIANT, &&__FALSE, &&__FALSE, &&__NULL
|
|
};
|
|
|
|
TYPE type = val->type;
|
|
|
|
if (TYPE_is_object(type))
|
|
return val->_object.object == NULL;
|
|
else
|
|
goto *jump[type];
|
|
|
|
__NULL:
|
|
return TRUE;
|
|
|
|
__STRING:
|
|
return val->_string.addr == 0 || val->_string.len == 0;
|
|
|
|
__DATE:
|
|
return val->_date.date == 0 && val->_date.time == 0;
|
|
|
|
__POINTER:
|
|
return val->_pointer.value == NULL;
|
|
|
|
__VARIANT:
|
|
|
|
if (val->_variant.vtype == T_NULL)
|
|
return TRUE;
|
|
|
|
if (val->_variant.vtype == T_STRING)
|
|
return val->_variant.value._string == NULL;
|
|
|
|
if (val->_variant.vtype == T_DATE)
|
|
return val->_variant.value.data == 0;
|
|
|
|
if (val->_variant.vtype == T_POINTER)
|
|
return val->_variant.value._pointer == NULL;
|
|
|
|
if (TYPE_is_object(val->_variant.vtype))
|
|
return val->_variant.value._object == NULL;
|
|
|
|
__FALSE:
|
|
return FALSE;
|
|
}
|
|
|
|
|
|
void VALUE_convert_boolean(VALUE *value)
|
|
{
|
|
static const void *jump[16] =
|
|
{
|
|
&&__NR, &&__OK, &&__c2b, &&__h2b, &&__i2b, &&__l2b, &&__g2b, &&__f2b,
|
|
&&__d2b, &&__s2b, &&__s2b, &&__N, &&__v2, &&__func, &&__N, &&__n2b
|
|
};
|
|
|
|
char *addr;
|
|
TYPE type = value->type;
|
|
|
|
if (TYPE_is_object(type))
|
|
{
|
|
if (value->_object.object)
|
|
{
|
|
OBJECT_just_unref(value->_object.object);
|
|
value->_boolean.value = -1;
|
|
}
|
|
value->type = T_BOOLEAN;
|
|
return;
|
|
}
|
|
else
|
|
goto *jump[type];
|
|
|
|
__c2b:
|
|
__h2b:
|
|
__i2b:
|
|
|
|
value->_integer.value = (value->_integer.value != 0) ? -1 : 0;
|
|
value->type = T_BOOLEAN;
|
|
return;
|
|
|
|
__l2b:
|
|
|
|
value->_integer.value = (value->_long.value != 0) ? -1 : 0;
|
|
value->type = T_BOOLEAN;
|
|
return;
|
|
|
|
__g2b:
|
|
|
|
value->_integer.value = (value->_single.value != 0) ? -1 : 0;
|
|
value->type = T_BOOLEAN;
|
|
return;
|
|
|
|
__f2b:
|
|
|
|
value->_integer.value = (value->_float.value != 0) ? -1 : 0;
|
|
value->type = T_BOOLEAN;
|
|
return;
|
|
|
|
__d2b:
|
|
|
|
value->_integer.value = (value->_date.date != 0 || value->_date.time != 0) ? -1 : 0;
|
|
value->type = T_BOOLEAN;
|
|
return;
|
|
|
|
__s2b:
|
|
|
|
addr = value->_string.addr;
|
|
value->_integer.value = ((addr != NULL) && (value->_string.len != 0)) ? -1 : 0;
|
|
if (value->type == T_STRING)
|
|
STRING_unref(&addr);
|
|
value->type = T_BOOLEAN;
|
|
return;
|
|
|
|
__n2b:
|
|
|
|
value->_integer.value = 0;
|
|
value->type = T_BOOLEAN;
|
|
return;
|
|
|
|
__v2:
|
|
{
|
|
static const void *jumpv[] = { &&__NR, &&__bv2b, &&__bv2b, &&__hv2b, &&__iv2b, &&__lv2b, &&__iv2b, &&__lv2b, &&__lv2b, &&__sv2b, &&__sv2b, &&__pv2b, &&__N, &&__N, &&__N, &&__nv2b };
|
|
int test;
|
|
|
|
type = value->_variant.vtype;
|
|
if (TYPE_is_object(type))
|
|
goto __ov2b;
|
|
else
|
|
goto *jumpv[type];
|
|
|
|
__bv2b:
|
|
test = value->_variant.value._boolean != 0;
|
|
goto __VOK;
|
|
|
|
__hv2b:
|
|
test = value->_variant.value._short != 0;
|
|
goto __VOK;
|
|
|
|
__iv2b:
|
|
test = value->_variant.value._integer != 0;
|
|
goto __VOK;
|
|
|
|
__lv2b:
|
|
test = value->_variant.value._long != 0;
|
|
goto __VOK;
|
|
|
|
__pv2b:
|
|
test = value->_variant.value._pointer != 0;
|
|
goto __VOK;
|
|
|
|
__ov2b:
|
|
test = value->_variant.value._object != 0;
|
|
OBJECT_UNREF(value->_variant.value._object);
|
|
goto __VOK;
|
|
|
|
__sv2b:
|
|
test = value->_variant.value._string && *value->_variant.value._string;
|
|
STRING_unref(&value->_variant.value._string);
|
|
goto __VOK;
|
|
|
|
__nv2b:
|
|
test = FALSE;
|
|
|
|
__VOK:
|
|
value->type = T_BOOLEAN;
|
|
value->_integer.value = test ? -1 : 0;
|
|
return;
|
|
}
|
|
|
|
__func:
|
|
|
|
//if (unknown_function(value))
|
|
// goto __CONV;
|
|
//else
|
|
goto __N;
|
|
|
|
__N:
|
|
|
|
THROW_TYPE(T_BOOLEAN, type);
|
|
|
|
__NR:
|
|
|
|
THROW(E_NRETURN);
|
|
|
|
__OK:
|
|
return;
|
|
}
|
|
|
|
|
|
void VALUE_convert_integer(VALUE *value)
|
|
{
|
|
static const void *jump[16] =
|
|
{
|
|
&&__NR, &&__TYPE, &&__TYPE, &&__TYPE, &&__OK, &&__l2i, &&__g2i, &&__f2i,
|
|
&&__d2i, &&__s2i, &&__s2i, &&__N, &&__v2, &&__func, &&__N, &&__N
|
|
};
|
|
|
|
char *addr;
|
|
|
|
__CONV:
|
|
|
|
goto *jump[value->type];
|
|
|
|
__l2i:
|
|
|
|
#if DO_NOT_CHECK_OVERFLOW
|
|
value->_integer.value = (int)value->_long.value;
|
|
#else
|
|
if (__builtin_add_overflow(value->_long.value, 0, &value->_integer.value))
|
|
THROW_OVERFLOW();
|
|
#endif
|
|
goto __TYPE;
|
|
|
|
__g2i:
|
|
|
|
value->_integer.value = (int)value->_single.value;
|
|
goto __TYPE;
|
|
|
|
__f2i:
|
|
|
|
value->_integer.value = (int)value->_float.value;
|
|
goto __TYPE;
|
|
|
|
__d2i:
|
|
|
|
value->_integer.value = value->_date.date;
|
|
goto __TYPE;
|
|
|
|
__s2i:
|
|
|
|
addr = value->type == T_STRING ? value->_string.addr : NULL;
|
|
|
|
if (NUMBER_from_string(NB_READ_INTEGER, value->_string.addr + value->_string.start, value->_string.len, value))
|
|
goto __N;
|
|
|
|
STRING_unref(&addr);
|
|
goto __TYPE;
|
|
|
|
__v2:
|
|
|
|
undo_variant(value);
|
|
if (TYPE_is_object(value->type))
|
|
goto __N;
|
|
else
|
|
goto __CONV;
|
|
|
|
__func:
|
|
|
|
//if (unknown_function(value))
|
|
// goto __CONV;
|
|
//else
|
|
goto __N;
|
|
|
|
__TYPE:
|
|
|
|
value->type = T_INTEGER;
|
|
|
|
__OK:
|
|
|
|
return;
|
|
|
|
__N:
|
|
|
|
THROW_TYPE(T_INTEGER, value->type);
|
|
|
|
__NR:
|
|
|
|
THROW(E_NRETURN);
|
|
}
|
|
|
|
|
|
void VALUE_convert_float(VALUE *value)
|
|
{
|
|
static const void *jump[16] =
|
|
{
|
|
&&__NR, &&__b2f, &&__c2f, &&__h2f, &&__i2f, &&__l2f, &&__g2f, &&__OK,
|
|
&&__d2f, &&__s2f, &&__s2f, &&__N, &&__v2, &&__func, &&__N, &&__N
|
|
};
|
|
|
|
char *addr;
|
|
|
|
__CONV:
|
|
|
|
if (TYPE_is_object(value->type))
|
|
goto __N;
|
|
else
|
|
goto *jump[value->type];
|
|
|
|
__b2f:
|
|
__c2f:
|
|
__h2f:
|
|
__i2f:
|
|
|
|
value->_float.value = value->_integer.value;
|
|
value->type = T_FLOAT;
|
|
return;
|
|
|
|
__l2f:
|
|
|
|
value->_float.value = value->_long.value;
|
|
value->type = T_FLOAT;
|
|
return;
|
|
|
|
__g2f:
|
|
|
|
value->_float.value = value->_single.value;
|
|
value->type = T_FLOAT;
|
|
return;
|
|
|
|
__d2f:
|
|
|
|
value->_float.value = (double)value->_date.date + (double)value->_date.time / 86400000.0;
|
|
value->type = T_FLOAT;
|
|
return;
|
|
|
|
__s2f:
|
|
|
|
addr = value->type == T_STRING ? value->_string.addr : NULL;
|
|
|
|
if (NUMBER_from_string(NB_READ_FLOAT, value->_string.addr + value->_string.start, value->_string.len, value))
|
|
goto __N;
|
|
|
|
STRING_unref(&addr);
|
|
return;
|
|
|
|
__v2:
|
|
|
|
undo_variant(value);
|
|
if (TYPE_is_object(value->type))
|
|
goto __N;
|
|
else
|
|
goto __CONV;
|
|
|
|
__func:
|
|
|
|
//if (unknown_function(value))
|
|
// goto __CONV;
|
|
//else
|
|
goto __N;
|
|
|
|
__N:
|
|
|
|
THROW_TYPE(T_FLOAT, value->type);
|
|
|
|
__NR:
|
|
|
|
THROW(E_NRETURN);
|
|
|
|
__OK:
|
|
|
|
return;
|
|
}
|
|
|
|
|
|
void VALUE_convert_string(VALUE *value)
|
|
{
|
|
static const void *jump[16] =
|
|
{
|
|
&&__NR, &&__b2s, &&__c2s, &&__h2s, &&__i2s, &&__l2s, &&__g2s, &&__f2s,
|
|
&&__d2s, &&__OK, &&__OK, &&__N, &&__v2, &&__func, &&__N, &&__n2s
|
|
};
|
|
|
|
int len;
|
|
char *addr;
|
|
|
|
__CONV:
|
|
|
|
goto *jump[value->type];
|
|
|
|
__b2s:
|
|
|
|
if (value->_boolean.value)
|
|
STRING_char_value(value, 'T');
|
|
else
|
|
STRING_void_value(value);
|
|
return;
|
|
|
|
__c2s:
|
|
__h2s:
|
|
__i2s:
|
|
|
|
NUMBER_int_to_string(value->_integer.value, 0, 10, value);
|
|
BORROW(value);
|
|
return;
|
|
|
|
__l2s:
|
|
|
|
NUMBER_int_to_string(value->_long.value, 0, 10, value);
|
|
BORROW(value);
|
|
return;
|
|
|
|
__g2s:
|
|
|
|
LOCAL_format_number(value->_single.value, LF_GENERAL_NUMBER, NULL, 0, &addr, &len, FALSE);
|
|
STRING_new_temp_value(value, addr, len);
|
|
BORROW(value);
|
|
return;
|
|
|
|
__f2s:
|
|
|
|
LOCAL_format_number(value->_float.value, LF_GENERAL_NUMBER, NULL, 0, &addr, &len, FALSE);
|
|
STRING_new_temp_value(value, addr, len);
|
|
BORROW(value);
|
|
return;
|
|
|
|
__d2s:
|
|
|
|
len = DATE_to_string(COMMON_buffer, value);
|
|
STRING_new_temp_value(value, COMMON_buffer, len);
|
|
BORROW(value);
|
|
return;
|
|
|
|
__n2s:
|
|
|
|
STRING_void_value(value);
|
|
return;
|
|
|
|
__v2:
|
|
|
|
undo_variant(value);
|
|
if (TYPE_is_object(value->type))
|
|
goto __N;
|
|
else
|
|
goto __CONV;
|
|
|
|
__func:
|
|
|
|
//if (unknown_function(value))
|
|
// goto __CONV;
|
|
//else
|
|
goto __N;
|
|
|
|
__OK:
|
|
|
|
return;
|
|
|
|
__N:
|
|
|
|
THROW_TYPE(T_STRING, value->type);
|
|
|
|
__NR:
|
|
|
|
THROW(E_NRETURN);
|
|
}
|
|
|
|
|
|
void VALUE_convert_variant(VALUE *value)
|
|
{
|
|
static const void *jump[16] =
|
|
{
|
|
&&__NR, &&__2v, &&__2v, &&__2v, &&__2v, &&__2v, &&__2v, &&__2v,
|
|
&&__2v, &&__s2v, &&__s2v, &&__2v, &&__OK, &&__func, &&__2v, &&__2v
|
|
};
|
|
|
|
char *addr;
|
|
|
|
//__CONV:
|
|
|
|
if (TYPE_is_object(value->type))
|
|
goto __2v;
|
|
else
|
|
goto *jump[value->type];
|
|
|
|
__s2v:
|
|
|
|
addr = STRING_copy_from_value_temp(value);
|
|
|
|
if (addr != value->_string.addr)
|
|
{
|
|
STRING_ref(addr);
|
|
|
|
if (value->type == T_STRING)
|
|
STRING_unref(&value->_string.addr);
|
|
}
|
|
|
|
value->_variant.value._string = addr;
|
|
value->_variant.vtype = T_STRING;
|
|
|
|
goto __TYPE;
|
|
|
|
__2v:
|
|
|
|
/* VALUE_put ne fonctionne pas avec T_STRING ! */
|
|
if (value->type != T_NULL)
|
|
VALUE_put(value, &value->_variant.value, value->type);
|
|
|
|
value->_variant.vtype = value->type;
|
|
goto __TYPE;
|
|
|
|
__func:
|
|
|
|
//if (unknown_function(value))
|
|
// goto __CONV;
|
|
//else
|
|
goto __N;
|
|
|
|
__TYPE:
|
|
|
|
value->type = T_VARIANT;
|
|
|
|
__OK:
|
|
|
|
return;
|
|
|
|
__N:
|
|
|
|
THROW_TYPE(T_VARIANT, value->type);
|
|
|
|
__NR:
|
|
|
|
THROW(E_NRETURN);
|
|
}
|
|
|
|
|
|
void VALUE_undo_variant(VALUE *value)
|
|
{
|
|
undo_variant(value);
|
|
}
|