For this example we'll be creating our own custom type of eina value. Eina value can already store struct timeval(man gettimeofday for more information) but it has no type to store struct timezone, so that's what this example will do.
- Note
- struct timezone is actually obsolete, so using it in real world programs is probably not a good idea, but this is an example so, bear with us.
To create our own custom eina value type we need to define functions to do the following operations on it:
- Setup
- Flush
- Copy
- Compare
- Set
- Get
- Conversion
Most of this functions are very simple, so let's look at them, starting with setup which only clear the memory so that we can be certain we won't be using stale data:
#include <sys/time.h>
{
}
#define EINA_TRUE
boolean value TRUE (numerical value 1)
Definition eina_types.h:299
unsigned char Eina_Bool
Type to mimic a boolean.
Definition eina_types.h:287
struct _Eina_Value_Type Eina_Value_Type
Describes the data contained by the value.
Definition eina_value.h:313
unsigned int value_size
byte size of value
Definition eina_value.h:3374
Now the flush function, which is even simpler, it does nothing, that's because there is nothing we need to do, all the necessary steps are taken by eina value itself:
Our next function, copy, is a bit more interesting, but not much, it just casts our void pointers to struct timezone pointers and does the copy:
{
struct timezone *tzsrc = src;
struct timezone *tzdst = dst;
*tzdst = *tzsrc;
}
- Note
- By now you might be wondering why our functions receive void pointers instead of pointers to struct timezone, and this is a good point. The reason for this is that eina value doesn't know anything about our type so it must use a generic void pointer, casting that pointer into a proper value is the job of the implementor of the new type.
Next we have the comparison function, which compares the tz_minuteswest
field of struct timezone, we don't compare tz_dsttime
because that field is not used in linux:
{
struct timezone tza = *(struct timezone*)a;
struct timezone tzb = *(struct timezone*)b;
if (tza.tz_minuteswest < tzb.tz_minuteswest)
return -1;
else if (tza.tz_minuteswest > tzb.tz_minuteswest)
return 1;
return 0;
}
Next we have setting, this however requires not one but rather two functions, the reason for this is because to be able to receive arguments of any type eina value uses variadic functions, so we need a function to get the argument from a va_list and another to actually to the setting.
Lets first look at the pset function which sets the received value to a pointer:
{
*(struct timezone*)mem = *(struct timezone*)ptr;
}
Next we have the vset function which get the argument from the va_list and passes it to the pset function:
{
const struct timezone tz = va_arg(args, struct timezone);
return _tz_pset(type, mem, &tz);
}
And now the function to get the value, a very simple copying of the value to the given pointer:
And finally our conversion function, this is our longest and most interesting one. For numeric type we simply assign the value of tz_minuteswest
to the new type and call a set function using it:
{
struct timezone v = *(struct timezone*)type_mem;
{
unsigned char other_mem = v.tz_minuteswest;
}
{
unsigned short other_mem = v.tz_minuteswest;
}
{
unsigned int other_mem = v.tz_minuteswest;
}
{
unsigned long other_mem = v.tz_minuteswest;
}
{
uint64_t other_mem = v.tz_minuteswest;
}
{
char other_mem = v.tz_minuteswest;
}
{
short other_mem = v.tz_minuteswest;
}
{
int other_mem = v.tz_minuteswest;
}
{
long other_mem = v.tz_minuteswest;
}
{
int64_t other_mem = v.tz_minuteswest;
}
void eina_error_set(Eina_Error err)
Set the last error.
Definition eina_error.c:256
const Eina_Value_Type * EINA_VALUE_TYPE_ULONG
manages unsigned long type.
Definition eina_value.c:5082
const Eina_Value_Type * EINA_VALUE_TYPE_CHAR
manages char type.
Definition eina_value.c:5085
const Eina_Value_Type * EINA_VALUE_TYPE_USHORT
manages unsigned short type.
Definition eina_value.c:5080
const Eina_Value_Type * EINA_VALUE_TYPE_UINT64
manages unsigned integer of 64 bits type.
Definition eina_value.c:5084
const Eina_Value_Type * EINA_VALUE_TYPE_UCHAR
manages unsigned char type.
Definition eina_value.c:5079
const Eina_Value_Type * EINA_VALUE_TYPE_LONG
manages long type.
Definition eina_value.c:5088
const Eina_Value_Type * EINA_VALUE_TYPE_INT64
manages integer of 64 bits type.
Definition eina_value.c:5089
const Eina_Value_Type * EINA_VALUE_TYPE_DOUBLE
manages double type.
Definition eina_value.c:5091
const Eina_Value_Type * EINA_VALUE_TYPE_INT
manages int type.
Definition eina_value.c:5087
const Eina_Value_Type * EINA_VALUE_TYPE_TIMESTAMP
manages unsigned long type used for timestamps.
Definition eina_value.c:5083
const Eina_Value_Type * EINA_VALUE_TYPE_FLOAT
manages float type.
Definition eina_value.c:5090
const Eina_Value_Type * EINA_VALUE_TYPE_UINT
manages unsigned int type.
Definition eina_value.c:5081
const Eina_Value_Type * EINA_VALUE_TYPE_SHORT
manages short type.
Definition eina_value.c:5086
static Eina_Bool eina_value_type_pset(const Eina_Value_Type *type, void *mem, const void *ptr)
Set memory using type descriptor and pointer.
- Note
- It would be a good idea to add checks for over and underflow for these types and return EINA_FALSE in thoses cases, we omit this here for brevity.
For string types we use snprintf()
to format our tz_minuteswest
field and put it in a string(again tz_dsttime
is ignored because it's not used):
{
const char *other_mem;
char buf[64];
snprintf(buf, sizeof(buf), "%d", v.tz_minuteswest);
other_mem = buf;
}
const Eina_Value_Type * EINA_VALUE_TYPE_STRING
manages string type.
Definition eina_value.c:5093
const Eina_Value_Type * EINA_VALUE_TYPE_STRINGSHARE
manages stringshared string type.
Definition eina_value.c:5092
Finally we handle any other types by returning an error in that case:
}
#define EINA_FALSE
boolean value FALSE (numerical value 0)
Definition eina_types.h:293
int EINA_ERROR_VALUE_FAILED
Error identifier corresponding to value check failure.
Definition eina_value.c:5109
Now that we have all the functions, we can populate an Eina_Value_Type
to later use it with eina_value_setup()
:
sizeof(struct timezone),
"struct timezone",
_tz_setup,
_tz_flush,
_tz_copy,
_tz_compare,
_tz_convert_to,
NULL,
_tz_vset,
_tz_pset,
_tz_pget
};
#define EINA_VALUE_TYPE_VERSION
Current API version, used to validate type.
Definition eina_value.h:3363
We can now finally use our new TZ_TYPE with eina value, so lets conclude our example by practicing that by setting its value and printing it:
int main(int argc, char **argv)
{
struct timeval tv;
struct timezone tz;
char *s;
gettimeofday(&tv, &tz);
printf("time: %s\n", s);
free(s);
printf("timezone: %s\n", s);
free(s);
}
int eina_init(void)
Initialize the Eina library.
Definition eina_main.c:244
const Eina_Value_Type * EINA_VALUE_TYPE_TIMEVAL
manages 'struct timeval' type
Definition eina_value.c:5097
struct _Eina_Value Eina_Value
Store generic values.
Definition eina_value.h:305
char * eina_value_to_string(const Eina_Value *value)
Convert value to string.
Definition eina_value.c:5203
static void eina_value_flush(Eina_Value *value)
Create generic value storage.
static Eina_Bool eina_value_set(Eina_Value *value,...)
Set the generic value.
static Eina_Bool eina_value_setup(Eina_Value *value, const Eina_Value_Type *type)
Initialize generic value storage.
For the full source code see eina_value_03.c.