blob: bb2db0aa89668219d029b070bd9b8946bd019546 [file] [log] [blame]
/* $Id$
*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to you under the Apache License, Version
* 2.0 (the "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/*
* etchobj.h
* etch object definitions
*/
#ifndef ETCHOBJ_H
#define ETCHOBJ_H
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include "etch.h"
#include "etch_mutex.h"
#ifdef __cplusplus
extern "C" {
#endif
struct etch_object;
struct vtabmask;
struct etchexception; /* declared in etchexcp.h which we can't include here */
/**
* function signatures for object virtuals
*/
typedef int (*etch_object_destructor)(void*); /* should tak etch_object or etch_object */
typedef void* (*etch_object_clone)(void*); /* should take and return etch_object or etch_object */
typedef uint32 (*obj_gethashkey)(void*); /* should take etch_object or etch_object */
typedef struct etchresult
{
int resultcode;
int reasoncode;
struct etchexception* exception;
} etchresult;
/**
* etch_object
* mask over all etch objects
*/
typedef struct etch_object
{
unsigned int hashkey; /* unique key used by a hash map */
unsigned short obj_type; /* type of this object */
unsigned short class_id; /* class identifier */
struct vtabmask* vtab; /* virtual function table */
etch_object_destructor destroy;
etch_object_clone clone;
obj_gethashkey get_hashkey; /* hash key calculation override */
struct etch_object* parent; /* class from which this derives */
etchresult* result; /* embedded result and exception */
unsigned int refcount; /* non-zero implies ref counted */
unsigned int length; /* byte count of the flat object */
unsigned char is_null; /* does object wrap a null value */
unsigned char is_copy; /* is object content not owned */
unsigned char is_static; /* should destructor free object */
unsigned char reserved; /* reserved for individual use */
etch_mutex_hookproc synchook; /* hook for synchronization */
etch_mutex_t* synclock; /* synchronization mutex */
} etch_object;
typedef struct etch_byte etch_byte;
typedef struct etch_boolean etch_boolean;
typedef struct etch_int8 etch_int8;
typedef struct etch_int16 etch_int16;
typedef struct etch_int32 etch_int32;
typedef struct etch_int64 etch_int64;
typedef struct etch_float etch_float;
typedef struct etch_double etch_double;
typedef struct etch_string etch_string;
typedef struct etch_date etch_date;
typedef struct etch_exception etch_exception;
/**
* etchparentinfo
* object inheritance list entry
*/
typedef struct etchparentinfo
{
union {
unsigned short obj_type;
unsigned short list_size; /* entry[0] in any inheritance list */
} o;
union {
unsigned short class_id;
unsigned short list_count; /* entry[0] in any inheritance list */
} c;
} etchparentinfo;
/**
* vtabmask
* mask over any vtable
*/
typedef struct vtabmask
{
etch_object object;
// inheritance list
etchparentinfo* inherits_from; // 4 byte
unsigned char unused[4]; // 4 byte
/* function pointers start here */
} vtabmask;
/**
* etch_byte - wrapped byte
* note that this and all CLASSID_PRIMITIVE_XXXX wrapped primitives are expected
* by code which generalizes such objects, to have the object's value as the first
* non-header item in the object.
*/
struct etch_byte
{
etch_object object;
signed char value; // 1 byte
};
/**
* etch_boolean - wrapped boolean
* note that this and all CLASSID_PRIMITIVE_XXXX wrapped primitives are expected
* by code which generalizes such objects, to have the object's value as the first
* non-header item in the object.
*/
struct etch_boolean
{
etch_object object;
unsigned char value; // 1 byte
};
/**
* etch_int8 - wrapped 8-bit integer
* note that this and all CLASSID_PRIMITIVE_XXXX wrapped primitives are expected
* by code which generalizes such objects, to have the object's value as the first
* non-header item in the object.
*/
struct etch_int8
{
etch_object object;
signed char value; // 1 byte
};
/**
* etch_int16 - wrapped 16-bit integer
* note that this and all CLASSID_PRIMITIVE_XXXX wrapped primitives are expected
* by code which generalizes such objects, to have the object's value as the first
* non-header item in the object.
*/
struct etch_int16
{
etch_object object;
signed short value; // 2 byte
};
/**
* etch_int32 - wrapped 32-bit integer
* note that this and all CLASSID_PRIMITIVE_XXXX wrapped primitives are expected
* by code which generalizes such objects, to have the object's value as the first
* non-header item in the object.
*/
struct etch_int32
{
etch_object object;
signed int value; // 4 byte
};
/**
* etch_int64 - wrapped 64-bit integer
* note that this and all CLASSID_PRIMITIVE_XXXX wrapped primitives are expected
* by code which generalizes such objects, to have the object's value as the first
* non-header item in the object.
*/
struct etch_int64
{
etch_object object;
int64 value; // 8 byte
};
/**
* etch_float - wrapped 32-bit float
* note that this and all CLASSID_PRIMITIVE_XXXX wrapped primitives are expected
* by code which generalizes such objects, to have the object's value as the first
* non-header item in the object.
*/
struct etch_float
{
etch_object object;
float value; // 4 byte
};
/**
* etch_double - wrapped 64-bit float
* note that this and all CLASSID_PRIMITIVE_XXXX wrapped primitives are expected
* by code which generalizes such objects, to have the object's value as the first
* non-header item in the object.
*/
struct etch_double
{
etch_object object;
double value; // 8 byte
};
typedef union etch_charptr
{
void* value;
wchar_t* valw;
char* valc;
} etch_charptr;
/**
* etch_string - wrapped pointer to unicode string
* note that this and all CLASSID_PRIMITIVE_XXXX wrapped primitives are expected
* by code which generalizes such objects, to have the object's value as the first
* non-header item in the object.
*/
struct etch_string
{
etch_object object;
union etch_charptr v; /* pointer to string value */
unsigned int char_count; /* number of characters */
unsigned int byte_count; /* including terminator */
unsigned char encoding;
};
/**
* etch_date - date object
*/
struct etch_date
{
etch_object object;
time_t value;
clock_t ticks;
};
typedef enum excptype
{
EXCPTYPE_NONE = 0x0,
EXCPTYPE_BUILTIN = 0x1,
EXCPTYPE_USERDEFINED = 0x2
} excptype_t;
/**
* etch_collection_mask
* masks etch object collections such as etch_nativearray, etch_arraylist,
* and etch_hashtable. not instantiated.
*/
typedef struct etch_collection_mask
{
etch_object object;
void* p;
unsigned short content_obj_type;
unsigned short content_class_id;
unsigned int n;
} etch_collection_mask;
/**
* etch_arraytype is used as a mask over etch_nativearray and etch_arrayvalue.
* a function using an etch_arraytype* parameter will test for one or the other
* and possibly convert the passed array to the other type.
*/
typedef struct etch_collection_mask etch_arraytype;
/**
* etch_objclass
* parameter structure identifying an etch object type
*/
typedef struct etch_objclass
{
unsigned short obj_type;
unsigned short class_id;
unsigned short content_obj_type;
unsigned short content_class_id;
unsigned short vtable_class_id;
unsigned int numdims;
etchparentinfo* inherits_from;
etch_object* parent;
} etch_objclass;
/**
* etch_component_type_params
* parameter and result structure for get_component_type() etc.
*/
typedef struct etch_component_type_params
{
unsigned int dimensions;
unsigned short origl_class_id;
unsigned short origl_obj_type;
unsigned short final_obj_type;
unsigned short final_class_id;
struct etch_nativearray* origl_array;
struct etch_nativearray* final_array;
} etch_component_type_params;
typedef struct etch_array_id_params
{
unsigned short array_obj_type;
unsigned short array_class_id;
unsigned short content_obj_type;
unsigned short content_class_id;
} etch_array_id_params;
/*
* default base object virtual method implementations
*/
int destroy_object(void*);
int destroy_objectex(etch_object*);
int destroy_string(void*);
void* clone_object (void*);
void* clone_string (void*);
void* clone_null(void*);
etch_object* new_object(const int objsize,
const unsigned short obj_type, const unsigned short class_id);
/*
* wide char string clone
*/
wchar_t* new_wchar(const wchar_t* s);
/*
* narrow char string clone
*/
char* new_char(const char* s);
typedef struct etch_who {
etch_object object;
void* value;
} etch_who;
typedef etch_int32 etch_event;
typedef etch_int32 etch_query;
typedef etch_int32 etch_control;
etch_who* new_who(void* whoobj);
etch_object* new_nullobj();
int destroy_etch_object_value(etch_object*);
etch_object* etchobj_assign_to(etch_object*, etch_object*);
/*
* etch primitive constructors
*/
etch_byte* new_byte(const signed char);
etch_boolean* new_boolean(boolean);
etch_int8* new_int8(signed char);
etch_int16* new_int16(short);
etch_int32* new_int32(int);
etch_int64* new_int64(int64);
etch_float* new_float(float);
etch_double* new_double(double);
etch_string* new_string(const void*, const unsigned char encoding);
etch_string* new_stringw(const void*);
etch_string* new_stringa(const void*);
etch_string* new_string_from(const void*, const unsigned char encoding);
etch_date* new_date();
etch_object* new_primitive(const unsigned, const unsigned short);
etchresult* new_etchresult(const int result, const int reason);
int32 etch_number_as_int32(const void* object);
/* these are wrapped integers for now. if we need more data, we can define dedicated objects */
etch_event* new_etch_event (const unsigned short class_id, const int value);
etch_query* new_etch_query (const unsigned short class_id, const int value);
etch_control* new_etch_control(const unsigned short class_id, const int value);
etch_status_t etch_object_destroy(void* object);
etch_object* etch_object_clone_func(void* pobject);
#define ETCH_NOREFCOUNT_MARKER 0xffffffff
#define is_etchobj_refcount_decremented(x) (x->get_hashkey(x) == ETCH_NOREFCOUNT_MARKER)
#define ETCHOBJCLASS(x) ETCHMAKECLASS(((etch_object*)x)->obj_type, ((etch_object*)x)->class_id)
#define ETCH_CONX_SIG 0xe5d4c3b2
typedef union
{
char vbyte; unsigned char vubyte; short vint16; int vint32; int64 vint64; double vdouble;
float vfloat; void* vaddr; etch_string* vstring;
struct etch_object* vetch_object;
struct etch_nativearray* vnatarray; struct etch_structvalue* vsv;
struct etch_arrayvalue* varrayval; struct etch_arraylist* varraylist;
int64 all;
} union_alltypes;
#define is_etch_byte(x) (x && ((etch_object*)x)->class_id == CLASSID_PRIMITIVE_BYTE)
#define is_etch_boolean(x) (x && ((etch_object*)x)->class_id == CLASSID_PRIMITIVE_BOOL)
#define is_etch_int8(x) (x && ((etch_object*)x)->class_id == CLASSID_PRIMITIVE_INT8)
#define is_etch_int16(x) (x && ((etch_object*)x)->class_id == CLASSID_PRIMITIVE_INT16)
#define is_etch_int32(x) (x && ((etch_object*)x)->class_id == CLASSID_PRIMITIVE_INT32)
#define is_etch_int64(x) (x && ((etch_object*)x)->class_id == CLASSID_PRIMITIVE_INT64)
#define is_etch_float(x) (x && ((etch_object*)x)->class_id == CLASSID_PRIMITIVE_FLOAT)
#define is_etch_double(x) (x && ((etch_object*)x)->class_id == CLASSID_PRIMITIVE_DOUBLE)
#define is_etch_primitive(x) (x && ((etch_object*)x)->obj_type == ETCHTYPEB_PRIMITIVE)
#define is_etch_struct(x) (x && ((etch_object*)x)->obj_type == ETCHTYPEB_STRUCTVAL)
#define is_etch_validator(x) (x && ((etch_object*)x)->obj_type == ETCHTYPEB_VALIDATOR)
#define is_etch_arraylist(x) (x && ((etch_object*)x)->obj_type == ETCHTYPEB_ARRAYLIST)
#define is_etch_arrayvalue(x) (x && ((etch_object*)x)->obj_type == ETCHTYPEB_ARRAYVAL)
#define is_etch_valuefact(x) (x && ((etch_object*)x)->obj_type == ETCHTYPEB_VALUEFACTORY)
#define is_etch_valuefactimpl(x)(x && ((etch_object*)x)->obj_type == ETCHTYPEB_VALUEFACTIMP)
#define is_etch_exception(x) (x && ((etch_object*)x)->obj_type == ETCHTYPEB_EXCEPTION)
#define is_etch_queue(x) (x && ((etch_object*)x)->obj_type == ETCHTYPEB_ETCHQUEUE)
#define is_etch_wait(x) (x && ((etch_object*)x)->obj_type == ETCHTYPEB_WAIT)
#define is_etch_mailbox(x) (x && ((etch_object*)x)->obj_type == ETCHTYPEB_MAILBOX)
#define is_etch_imailbox(x) (x && ((etch_object*)x)->obj_type == ETCHTYPEB_MAILBOXINT)
#define is_etch_mailboxmgr(x) (x && ((etch_object*)x)->obj_type == ETCHTYPEB_MBOXMGR_IMPL)
#define is_etch_imailboxmgr(x) (x && ((etch_object*)x)->obj_type == ETCHTYPEB_MBOX_MANAGER)
#define is_etch_sessionmsg(x) (x && ((etch_object*)x)->obj_type == ETCHTYPEB_SESSIONMSG)
#define is_etch_transportmsg(x) (x && ((etch_object*)x)->obj_type == ETCHTYPEB_TRANSPORTMSG)
#define is_etch_hashtable(x) (x && ((etch_object*)x)->obj_type == ETCHTYPEB_HASHTABLE)
#define is_etch_nativearray(x) (x && ((etch_object*)x)->obj_type == ETCHTYPEB_NATIVEARRAY)
#define is_etch_deliverysvc(x) (x && ((etch_object*)x)->obj_type == ETCHTYPEB_DELIVERYSVC_IMPL)
#define is_etch_ideliverysvc(x) (x && ((etch_object*)x)->obj_type == ETCHTYPEB_DELIVERYSVCINT)
#define is_etch_tcpserver(x) (x && ((etch_object*)x)->obj_type == ETCHTYPEB_TCPSERVER)
#define is_etch_sessionlxr(x) (x && ((etch_object*)x)->obj_type == ETCHTYPEB_SESSIONLXR)
#define is_etch_sessionpacket(x)(x && ((etch_object*)x)->obj_type == ETCHTYPEB_SESSIONPKT)
#define is_etch_transportpkt(x) (x && ((etch_object*)x)->obj_type == ETCHTYPEB_TRANSPORTPKT)
#define is_etch_sessiondata(x) (x && ((etch_object*)x)->obj_type == ETCHTYPEB_SESSIONDATA)
#define is_etch_transportdata(x)(x && ((etch_object*)x)->obj_type == ETCHTYPEB_TRANSPORTDATA)
#define is_etch_packetizer(x) (x && ((etch_object*)x)->obj_type == ETCHTYPEB_PACKETIZER)
#define is_etch_messagizer(x) (x && ((etch_object*)x)->obj_type == ETCHTYPEB_MESSAGIZER)
#define is_etch_serverimpl(x) (x && ((etch_object*)x)->obj_type == ETCHTYPEB_EXESERVERIMPL)
#define is_etch_serverbase(x) (x && ((etch_object*)x)->obj_type == ETCHTYPEB_EXESERVERBASE)
#define is_etch_factoryparams(x)(x && ((etch_object*)x)->obj_type == ETCHTYPEB_FACTORYPARAMS)
#define is_etch_clientsession(x)(x && ((etch_object*)x)->obj_type == ETCHTYPEB_CLIENT_SESSION)
#define is_etch_remote_server(x)(x && ((etch_object*)x)->obj_type == ETCHTYPEB_REMOTESERVER)
#define is_etch_client_impl(x) (x && ((etch_object*)x)->obj_type == ETCHTYPEB_EXECLIENTIMPL)
#define is_etch_client_stub(x) (x && ((etch_object*)x)->obj_type == ETCHTYPEB_CLIENTSTUB)
#define is_etch_server_stub(x) (x && ((etch_object*)x)->obj_type == ETCHTYPEB_SERVERSTUB)
#define is_etch_client_base(x) (x && ((etch_object*)x)->obj_type == ETCHTYPEB_EXECLIENTBASE)
#define is_etch_threadpool(x) (x && ((etch_object*)x)->obj_type == ETCHTYPEB_THREADPOOL)
#define is_etch_flexbuffer(x) (x && ((etch_object*)x)->obj_type == ETCHTYPEB_FLEXBUF)
#define is_etch_message(x) (x && ((etch_object*)x)->obj_type == ETCHTYPEB_MESSAGE)
#define is_etch_thread(x) (x && ((etch_object*)x)->obj_type == ETCHTYPEB_THREAD)
#define is_etch_string(x) (x && ((etch_object*)x)->class_id == CLASSID_STRING \
&& ((etch_object*)x)->obj_type == ETCHTYPEB_PRIMITIVE)
#define is_etch_date(x) (x && ((etch_object*)x)->class_id == CLASSID_DATE \
&& ((etch_object*)x)->obj_type == ETCHTYPEB_PRIMITIVE)
#define is_etch_object(x) (x && ((etch_object*)x)->obj_type == ETCHTYPEB_ETCHOBJECT)
#define is_etch_object_type(a,b)(a == ETCHTYPEB_ETCHOBJECT || b == CLASSID_OBJECT )
#define is_etch_nativearray_type(t,c) (t == ETCHTYPEB_NATIVEARRAY)
#define is_etch_arraylist_type(t,c) (t == ETCHTYPEB_ARRAYLIST)
#define is_etch_objarray_type(t,c) (c == CLASSID_ARRAY_OBJECT)
#define is_etch_tcpconnection(x) (x \
&& ((etch_object*)x)->obj_type == ETCHTYPEB_CONNECTION \
&& ((etch_object*)x)->class_id == CLASSID_TCP_CONNECTION)
#define is_etch_serverparams(x) (x \
&& ((etch_object*)x)->obj_type == ETCHTYPEB_FACTORYPARAMS \
&& ((etch_object*)x)->class_id == CLASSID_SERVERFACTORY)
#define is_etch_clientparams(x) (x \
&& ((etch_object*)x)->obj_type == ETCHTYPEB_FACTORYPARAMS \
&& ((etch_object*)x)->class_id == CLASSID_CLIENTFACTORY)
#define is_etch_combo_validator(x) (x \
&& ((etch_object*)x)->obj_type == ETCHTYPEB_VALIDATOR \
&& ((etch_object*)x)->class_id == CLASSID_COMBO_VALIDATOR)
#define is_etch_primitive_number(x) (x \
&& ((etch_object*)x)->class_id >= CLASSID_PRIMITIVE_BYTE \
&& ((etch_object*)x)->class_id <= CLASSID_PRIMITIVE_DOUBLE)
#define is_etch_arraytype(x) (x \
&& (((etch_object*)x)->obj_type >= ETCHTYPEB_NATIVEARRAY \
|| ((etch_object*)x)->obj_type <= ETCHTYPEB_ARRAYVAL))
#define is_etch_unwantedmsg(x) (x \
&& ((etch_object*)x)->obj_type == ETCHTYPEB_EVENT \
&& ((etch_object*)x)->class_id == CLASSID_EVENT_UNWANTMSG)
#define is_etch_objparams(x,a,b) (x && ((etch_object*)x)->obj_type == a && ((etch_object*)x)->class_id == b)
#define is_etch_connection(cx) (cx && (*(unsigned*)cx) == ETCH_CONX_SIG)
/**
* macros to interpret state of the object byteflag is_static
*/
#define ETCHOBJ_IMMUTABLE_SHELL 1 /* object shell not to be freed */
#define ETCHOBJ_IMMUTABLE_CONTENT 2 /* object content not to be freed */
#define ETCHOBJ_IMMUTABLE_ALL 3 /* entire object not to be freed */
#define ETCHOBJ_STATIC_RESOURCE 4 /* object will not be destroyed by resources mgr */
#define is_etchobj_static_shell(x) ( ( ((etch_object*)x)->is_static & ETCHOBJ_IMMUTABLE_SHELL ) != 0 )
#define is_etchobj_static_shellonly(x) ( ((etch_object*)x)->is_static == ETCHOBJ_IMMUTABLE_SHELL )
#define is_etchobj_static_content(x) ( ((etch_object*)x)->is_static >= ETCHOBJ_IMMUTABLE_CONTENT )
#define is_etchobj_static_contonly(x) ( ((etch_object*)x)->is_static == ETCHOBJ_IMMUTABLE_CONTENT )
#define is_etchobj_static_all(x) ( ((etch_object*)x)->is_static == ETCHOBJ_IMMUTABLE_ALL )
#define is_etchobj_static_resource(x) ( ( ((etch_object*)x)->is_static & ETCHOBJ_STATIC_RESOURCE) != 0 )
#define set_etchobj_static_all(x) ( ((etch_object*)x)->is_static |= ETCHOBJ_IMMUTABLE_ALL )
#define set_etchobj_static_shell(x) ( ((etch_object*)x)->is_static |= ETCHOBJ_IMMUTABLE_SHELL )
#define set_etchobj_static_content(x) ( ((etch_object*)x)->is_static |= ETCHOBJ_IMMUTABLE_CONTENT )
#define set_etchobj_static_resource(x) ( ((etch_object*)x)->is_static |= ETCHOBJ_STATIC_RESOURCE )
#define clear_etchobj_static_shell(x) ( ((etch_object*)x)->is_static &= ~ETCHOBJ_IMMUTABLE_SHELL )
#define clear_etchobj_static_content(x) ( ((etch_object*)x)->is_static &= ~ETCHOBJ_IMMUTABLE_CONTENT )
#define clear_etchobj_static_all(x) ( ((etch_object*)x)->is_static &= ~ETCHOBJ_IMMUTABLE_ALL )
#define clear_etchobj_static_resource(x)( ((etch_object*)x)->is_static &= ~ETCHOBJ_STATIC_RESOURCE )
/**
* macros to get size/count from etch object inheritance list
*/
#define has_parents(obj) {obj && ((vtabmask*)((etch_object*)obj)->vtab)->inherits_from \
&& ((vtabmask*)((etch_object*)obj)->vtab)->inherits_from[0].list_count > 0))
#define get_etchobj_parent_count(obj) \
(obj && ((etch_object*)obj)->vtab && ((vtabmask*)obj->vtab)->inherits_from? \
((vtabmask*)((etch_object*)obj)->vtab)->inherits_from[0].list_count: 0)
#define get_etchobj_parent_listsize(obj) \
(obj && ((etch_object*)obj)->vtab && ((vtabmask*)obj->vtab)->inherits_from? \
((vtabmask*)((etch_object*)obj)->vtab)->inherits_from[0].list_size: 0)
/**
* methods to access and/or instantiate object's inheritance hierarchy
*/
etchparentinfo* get_vtab_inheritance_list(etch_object*,
const short size, const short count, const short vtabclass);
etchparentinfo* new_etch_inheritance_list(const short size, const short count,
etchparentinfo* oldlist);
etchparentinfo* get_next_etch_parent(etch_object*, int current_index);
etchparentinfo* get_next_etch_parentex(const unsigned short class_id,
etchparentinfo* inhertlist, int current_index);
int etchobj_is_assignable_from(etch_objclass* target, etch_objclass* source);
int etchobj_is_assignable_fromobj(etch_object* targetobj, etch_object* sourceobj);
void set_etch_assignable_arg_from(etch_objclass*, etch_object*);
unsigned etch_get_char_hashkey (const char*);
unsigned etch_get_wchar_hashkey(const wchar_t*);
int is_derives_from_object(etch_object*);
int is_derives_from_object_class(const unsigned short class_id);
int verify_object(etch_object*, const unsigned short, const unsigned short, void** out);
void* new_vtable(const void* parentvtab, const size_t size, const short classid);
short short_type(unsigned i, unsigned j);
void* get_base_vtable(etch_object*);
unsigned etch_addref(etch_object*);
unsigned etch_release(etch_object*);
unsigned etch_release_wrapper(etch_object*);
uint32 defgethashkey(void*);
uint32 etch_number_get_hashkey(void*);
unsigned get_vtable_cachehkey(unsigned short class_id);
unsigned get_class_cachekey(unsigned short obj_type, unsigned short class_id);
#ifdef __cplusplus
}
#endif
#endif /* #ifndef ETCHOBJ_H */