You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@etch.apache.org by jd...@apache.org on 2009/04/22 19:25:51 UTC

svn commit: r767594 [16/43] - in /incubator/etch/trunk/binding-c/runtime/c: ./ ext/ ext/hashtab/ ext/lib/ inc/ lib/ project/ project/$etchstop/ project/bin/ project/etch/ project/logcli/ project/logsrv/ project/notes/ project/test/ project/test/logcli/...

Added: incubator/etch/trunk/binding-c/runtime/c/src/bindings/msg/etch_valufact.c
URL: http://svn.apache.org/viewvc/incubator/etch/trunk/binding-c/runtime/c/src/bindings/msg/etch_valufact.c?rev=767594&view=auto
==============================================================================
--- incubator/etch/trunk/binding-c/runtime/c/src/bindings/msg/etch_valufact.c (added)
+++ incubator/etch/trunk/binding-c/runtime/c/src/bindings/msg/etch_valufact.c Wed Apr 22 17:25:43 2009
@@ -0,0 +1,172 @@
+/* $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. 
+ */ 
+
+/*
+ * etch_valufact.c
+ * value factory
+ */
+
+#include <stdio.h>
+#include "etch_valufact.h"
+#include "etch_tagdata_out.h"
+#include "etch_global.h"
+
+
+/**
+ * value factory virtual function default implementations
+ */
+
+etch_type* vf_add_type (void* vf, etch_type* t) 
+{
+    return NULL;
+}
+
+
+etch_type* vf_get_type_by_id (void* vf, const unsigned id)
+{
+    return NULL;
+}
+
+
+etch_type* vf_get_type_by_name (void* vf, const wchar_t* name) 
+{
+    return NULL;
+}
+	
+
+etch_arraylist* vf_get_types (void* vf)
+{
+    return NULL;
+}
+
+
+wchar_t* vf_get_string_encoding (void* vf)
+{
+    return NULL;
+}
+
+
+etch_int64* vf_get_message_id (void* vf, etch_message* msgobj)
+{
+    return NULL;
+}
+
+
+int vf_set_message_id (void* vf, etch_message* msgobj, etch_int64* msgid)
+{
+    return 0;
+}
+
+  
+etch_int64* vf_get_in_reply_to (void* vf, etch_message* msgobj)
+{
+    return NULL;
+}
+	
+
+int vf_set_in_reply_to (void* vf, etch_message* msgobj, etch_int64* msgid)
+{
+    return 0;
+}
+   
+  
+etch_structvalue* vf_export_custom_value (void* vf, objmask* value)
+{
+    return NULL;
+}
+	
+
+objmask* vf_import_custom_value (void* vf, etch_structvalue* svobj)
+{
+    return NULL;
+}
+
+
+etch_type* vf_get_custom_struct_type (void* vf, const unsigned etchclass)
+{
+    return NULL;
+}
+	
+
+etch_type* vf_get_mt_exception (void* vf)
+{
+    return NULL;
+}
+	
+
+
+
+/**
+ * new_value_factory()
+ * value factory constructor 
+ */
+etch_value_factory* new_value_factory(const int objlen)
+{
+    etch_value_factory* vf = NULL;
+    i_value_factory*  vtab = NULL;
+    const unsigned short CLASS_ID = CLASSID_VALUEFACTORY;
+    int result = 0, objsize = objlen? objlen: sizeof(etch_value_factory);
+
+    vf = (etch_value_factory*) new_object
+         (objsize, ETCHTYPEB_VALUEFACTORY, CLASSID_VALUEFACTORY);
+    vf->destroy = destroy_valuefactory;
+    vf->clone   = clone_null;
+
+    vtab = cache_find(get_vtable_cachehkey(CLASS_ID), 0);
+
+    if(!vtab)  
+    {   
+        vtab = new_vtable(NULL, sizeof(i_value_factory), CLASS_ID);
+
+        /* default virtual function implementations */
+        vtab->add_type              = vf_add_type;
+        vtab->export_custom_value   = vf_export_custom_value;
+        vtab->get_in_reply_to       = vf_get_in_reply_to;
+        vtab->get_message_id        = vf_get_message_id;
+        vtab->get_string_encoding   = vf_get_string_encoding;
+        vtab->get_type_by_id        = vf_get_type_by_id;
+        vtab->get_type_by_name      = vf_get_type_by_name;
+        vtab->get_types             = vf_get_types;
+        vtab->import_custom_value   = vf_import_custom_value;
+        vtab->set_in_reply_to       = vf_set_in_reply_to;
+        vtab->set_message_id        = vf_set_message_id;
+        vtab->get_custom_struct_type= vf_get_custom_struct_type;
+        vtab->get_mt_exception      = vf_get_mt_exception;
+
+        cache_insert(vtab->hashkey, vtab, FALSE);
+    } 
+ 
+    vf->vtab = vtab;   
+    return vf; 
+}
+
+
+int destroy_valuefactory(etch_value_factory* vf)
+{
+    if (vf->refcount > 0 && --vf->refcount > 0) return -1;  
+
+    if (!is_etchobj_static_content(vf))
+        if (vf->impl)
+            vf->impl->destroy(vf->impl);
+
+    return destroy_objectex((objmask*)vf);  
+}
+
+
+
+

Added: incubator/etch/trunk/binding-c/runtime/c/src/bindings/support/default_valufact.c
URL: http://svn.apache.org/viewvc/incubator/etch/trunk/binding-c/runtime/c/src/bindings/support/default_valufact.c?rev=767594&view=auto
==============================================================================
--- incubator/etch/trunk/binding-c/runtime/c/src/bindings/support/default_valufact.c (added)
+++ incubator/etch/trunk/binding-c/runtime/c/src/bindings/support/default_valufact.c Wed Apr 22 17:25:43 2009
@@ -0,0 +1,340 @@
+/**
+ * default_valufact.c 
+ * default value factory from which all others inherit
+ */
+
+#include <stdio.h>
+#include "etch_global.h"
+#include "etch_objects.h"
+#include "etchexcp.h"
+#include "etchutl.h"
+
+#include "default_valufact.h"
+
+etch_hashtable* new_vf_id_name_map(const int initialsize);
+
+
+/**
+ * def_vf_impl_destructor
+ * destructor for def_vf_impl
+ */
+int def_vf_impl_destructor(def_vf_impl* impl)  
+{
+    impl_destroy_handler destroy = NULL; /* TODO ifdef sanity checks */
+    int result = verify_object((objmask*)impl, ETCHTYPEB_VALUEFACTIMP, CLASSID_DEF_VF_IMPL, NULL);
+    if (result == -1) return -1; /* specified object was not expected object */
+
+    /* invoke base class destructor */
+    destroy_instancedata(impl->base_impl, impl->base_type); 
+
+    /* destroy this class' instance data */
+    //impl->mf_message_id_obj ->vtab->destroy(impl->mf_message_id_obj);
+    //impl->mf_in_reply_to_obj->vtab->destroy(impl->mf_in_reply_to_obj);
+
+    destroy_hashtable(impl->types,  TRUE, TRUE);
+    destroy_hashtable(impl->fields, TRUE, TRUE);
+
+    /* destroy this object */
+    etch_free(impl); 
+    return 0;
+}
+
+
+/**
+ * new_def_vf_impl()
+ * constructor for default vf instance data
+ */
+def_vf_impl* new_def_vf_impl(void* base_impl, const short base_type)
+{
+    def_vf_impl* data = etch_malloc(sizeof(def_vf_impl), ETCHTYPEB_INSTANCEDATA);
+    memset(data, 0, sizeof(def_vf_impl));
+    data->obj_type   = ETCHTYPEB_VALUEFACTIMP;
+    data->class_id   = CLASSID_DEF_VF_IMPL;
+    data->base_impl  = base_impl;
+    data->base_type  = base_type;
+    data->destructor = def_vf_impl_destructor;
+
+    data->types  = new_vf_id_name_map(ETCH_DEFVF_IDNMAP_DEFINITSIZE);
+    data->fields = new_vf_id_name_map(ETCH_DEFVF_IDNMAP_DEFINITSIZE);
+
+    //data->mf_message_id_obj  = new_etch_field(L"_messageId"); 
+    //data->mf_in_reply_to_obj = new_etch_field(L"_inReplyTo");  
+    //data->mf_message_id  = data->mf_message_id_obj->value_ptr_to;
+    //data->mf_in_reply_to = data->mf_in_reply_to_obj->value_ptr_to;    
+
+    return data;
+}
+
+
+/**
+ * defvf_add_type()
+ * adds a type to set of types
+ * @param type caller must supply a disposable type object
+ * @return the argument. If there is a collision with an id and name, 
+ * the existing type is returned in place of the supplied type. 
+ * @throws IllegalArgumentException (NULL return indicates as such)
+ */
+etch_type* defvf_add_type (etch_value_factory* vf, etch_type* type) 
+{
+    def_vf_impl* data = vf->impl; /* TODO unit test the defvf */
+    
+    const int result = data->types->vtab->insert
+        (data->types->realtable, type, HASHSIZE_TYPE, NULL, 0, 0, 0); 
+
+    return result == 0? type: NULL;  
+}
+
+
+etch_type* defvf_get_type_by_id (etch_value_factory* vf, const unsigned id)
+{
+    etch_hashitem  hashbucket; 
+    etch_hashitem* thisitem = &hashbucket;
+    def_vf_impl* data = vf->impl;  
+    
+    const int result = data->types->vtab->findh
+        (data->types->realtable, id, 0, &thisitem);     
+
+    return result == 0? (etch_type*) thisitem->key: NULL;  
+}
+
+
+etch_type* defvf_get_type_by_name (etch_value_factory* vf, const wchar_t* name) 
+{
+    def_vf_impl* data = vf->impl; 
+    unsigned bytelen  =(unsigned)(wcslen(name) + 1) * sizeof(wchar_t);
+    unsigned namehash = etchhash(name, bytelen, 0); 
+
+    return defvf_get_type_by_id(vf, namehash);  
+}
+	
+
+etch_arraylist* defvf_get_types (etch_value_factory* vf)
+{    
+    def_vf_impl* data = vf->impl; 
+
+    return get_map_keys(data->types);
+}
+
+
+/**
+ * defvf_add_field()
+ * adds a type to set of types
+ * @param type caller must supply a disposable field object
+ * @return the argument. If there is a collision with an id and name, 
+ * the existing field is returned in place of the supplied field. 
+ * @throws IllegalArgumentException (NULL return indicates as such)
+ */  
+etch_field* defvf_add_field (etch_value_factory* vf, etch_field* field) 
+{
+    def_vf_impl* data = vf->impl; /* TODO unit test the defvf */
+    
+    int result = data->fields->vtab->insert
+        (data->fields->realtable, field, HASHSIZE_FIELD, NULL, 0, 0, 0); 
+
+    return result == 0? field: NULL;  
+}
+
+
+etch_field* defvf_get_field_by_id (etch_value_factory* vf, const unsigned id)
+{
+    etch_hashitem  hashbucket; 
+    etch_hashitem* thisitem = &hashbucket;
+    def_vf_impl* data = vf->impl;  
+    
+    const int result = data->fields->vtab->findh
+        (data->fields->realtable, id, 0, &thisitem);     
+
+    return result == 0? (etch_field*) thisitem->key: NULL;
+}
+
+
+etch_field* defvf_get_field_by_name (etch_value_factory* vf, const wchar_t* name)
+{
+    def_vf_impl* data = vf->impl; 
+    unsigned bytelen  =(unsigned)(wcslen(name) + 1) * sizeof(wchar_t);
+    unsigned namehash = etchhash(name, bytelen, 0); 
+
+    return defvf_get_field_by_id(vf, namehash);  
+}
+
+
+etch_arraylist* defvf_get_fields (etch_value_factory* vf)
+{
+    def_vf_impl* data = vf->impl; 
+
+    return get_map_keys(data->fields);
+}
+
+
+wchar_t* defvf_get_string_encoding (etch_value_factory* vf)
+{
+    const static wchar_t* ETCH_STR_UTF8 = L"utf-8";   
+    return clone_wchar(ETCH_STR_UTF8);
+}
+
+  
+ETCH_STRUCTVALUE* defvf_export_custom_value (etch_value_factory* vf, etchobject* value)
+{
+    return NULL;
+}
+	
+
+etchobject* defvf_import_custom_value (etch_value_factory* vf, ETCH_STRUCTVALUE* svobj)
+{
+    return NULL;
+}
+	
+
+ETCH_TYPE* defvf_get_custom_struct_type (etch_value_factory* vf, unsigned class_id)
+{
+    return NULL;
+}
+	
+
+ETCH_CLASS* defvf_get_custom_type (etch_value_factory* vf, etch_type* t)
+{
+    return NULL;
+}
+
+
+/**
+ * defvf_get_message_id() -- valuefactory.get_message_id() implementation.
+ */
+ETCH_INT64* defvf_get_message_id (etch_value_factory* vf, ETCH_MESSAGE* msgobj)
+{
+    ETCH_INT64* idobj  = NULL;
+    def_vf_impl* data = vf->impl;
+
+    // idobj = message_get(msgobj, data->mf_message_id);
+
+    return verifyx(idobj, ETCHTYPE_BOXED_INT64, EXCPTYPE_INTERNALERR);
+}
+
+
+/**
+ * defvf_set_message_id() -- valuefactory.set_message_id() implementation.
+ */
+int defvf_set_message_id (etch_value_factory* vf, ETCH_MESSAGE* msgobj, ETCH_INT64* idobj)
+{
+    def_vf_impl* data = vf->impl;
+    // etch_type* keycopy = clone_type(data->mf_message_id);
+    etch_type* keycopy = 0; // *******
+
+    /* FYI this copy of the key is put to ETCH_MESSAGE* sent message, and gets   
+     * freed in msgobj.destroy() (recall that message owns its memory). 
+     * TODO clones should happen at a lower level */
+    message_put(msgobj, keycopy, idobj);   
+
+    return is_exception(msgobj)? -1: 0;
+}
+
+
+/**
+ * defvf_get_in_reply_to() -- valuefactory.get_in_reply_to() implementation.
+ */
+ETCH_INT64* defvf_get_in_reply_to (etch_value_factory* vf, ETCH_MESSAGE* msgobj)
+{
+    ETCH_INT64* idobj  = NULL;
+    def_vf_impl* data = vf->impl;
+
+    //idobj = message_get(msgobj, data->mf_in_reply_to);
+
+    return verifyx(idobj, ETCHTYPE_BOXED_INT64, EXCPTYPE_INTERNALERR);
+}
+
+
+/**
+ * defvf_set_in_reply_to() -- valuefactory.set_message_id() implementation.
+ */
+int defvf_set_in_reply_to (etch_value_factory* vf, ETCH_MESSAGE* msgobj, ETCH_INT64* idobj)
+{
+    def_vf_impl* data = vf->impl;
+    //etch_type* keycopy = clone_type(data->mf_in_reply_to);
+    etch_type* keycopy = 0; //*************
+
+    /* FYI this copy of the key is put to ETCH_MESSAGE* reply message, and gets  
+     * freed in newobj.destroy(), since recall that message owns its memory. 
+     * TODO clones should happen at a lower level */
+    message_put(msgobj, keycopy, idobj);  
+    return is_exception(msgobj)? -1: 0;
+}
+
+/*  
+ * value factory constructors/destructors
+ */
+
+
+
+/**
+ * new_default_value_factory()
+ * constructor for value factory implementation  
+ */
+ETCH_VALUEFACTORY* new_default_value_factory()  
+{
+    ETCH_VALUEFACTORY*  boxvf  = NULL;
+    etch_value_factory* defvf = NULL;
+    i_value_factory* vtab = NULL;
+    const int VTABSIZE = sizeof(i_value_factory);
+    const int VTAB_KEY = ETCHTYPE_VTABLE_DEF_VF;
+    int result = 0;
+   
+    boxvf  = new_boxed_value_factory();
+   
+    defvf = boxvf->value_ptr_to;
+
+    vtab = cache_find(VTAB_KEY,0);
+
+    if(!vtab)  
+    {    
+        vtab = new_vtable(defvf->vtab, VTABSIZE, ETCHTYPEB_VTABLE, CLASSID_DEF_VF_VTAB);
+
+        /* override four i_value_factory methods */
+
+        vtab->add_field             = defvf_add_field;
+        vtab->add_type              = defvf_add_type;
+        vtab->export_custom_value   = defvf_export_custom_value;
+        vtab->get_custom_type       = defvf_get_custom_type;
+        vtab->get_field_by_id       = defvf_get_field_by_id;
+        vtab->get_field_by_name     = defvf_get_field_by_name;
+        vtab->get_fields            = defvf_get_fields;
+        vtab->get_in_reply_to       = defvf_get_in_reply_to;
+        vtab->get_message_id        = defvf_get_message_id;
+        vtab->get_string_encoding   = defvf_get_string_encoding;
+        vtab->get_type_by_id        = defvf_get_type_by_id;
+        vtab->get_type_by_name      = defvf_get_type_by_name;
+        vtab->get_types             = defvf_get_types;
+        vtab->import_custom_value   = defvf_import_custom_value;
+        vtab->set_in_reply_to       = defvf_set_in_reply_to;
+        vtab->set_message_id        = defvf_set_message_id;
+        vtab->get_custom_struct_type = defvf_get_custom_struct_type;
+
+        vtab->vtab = defvf->vtab;       /* chain parent vtab to override vtab */
+        cache_insert(VTAB_KEY, vtab, 0); /* cache the new vtab */
+    } 
+
+    defvf->vtab = vtab;  /* set override vtab */
+
+    defvf->impl = new_def_vf_impl(NULL, 0); /* create vf instance data */
+
+    return boxvf;
+}
+
+
+/**
+ * new_vf_id_name_map()
+ * return a hashtable configured as expected for a vf  
+ */
+etch_hashtable* new_vf_id_name_map(const int initialsize)
+{
+    etch_hashtable* map = new_etch_hashtable(initialsize);  
+    if (map == NULL) return NULL;
+    map->content_type       = ETCHHASHTABLE_CONTENT_OBJECT;
+    map->is_tracked_memory  = TRUE;
+    map->is_readonly_keys   = FALSE;
+    map->is_readonly_values = FALSE;
+    map->callback           = NULL;
+    return map;
+}
+
+
+

Added: incubator/etch/trunk/binding-c/runtime/c/src/bindings/support/etch_resources.c
URL: http://svn.apache.org/viewvc/incubator/etch/trunk/binding-c/runtime/c/src/bindings/support/etch_resources.c?rev=767594&view=auto
==============================================================================
--- incubator/etch/trunk/binding-c/runtime/c/src/bindings/support/etch_resources.c (added)
+++ incubator/etch/trunk/binding-c/runtime/c/src/bindings/support/etch_resources.c Wed Apr 22 17:25:43 2009
@@ -0,0 +1,152 @@
+/* $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. 
+ */ 
+
+/*
+ * etch_resources.c
+ */
+
+#include "etch_resources.h"
+#include "etchmap.h"
+#include "etch_global.h"
+
+const wchar_t* ETCH_RESXKEY_SOCKET          = L"SOCKET";
+const wchar_t* ETCH_RESXKEY_ACCEPTED_CONX   = L"ACCEPTED_CONX";
+const wchar_t* ETCH_RESXKEY_POOLTYPE_FREE   = L"FREE_POOL";
+const wchar_t* ETCH_RESXKEY_POOLTYPE_QUEUED = L"QUEUED_POOL";
+const wchar_t* ETCH_RESXKEY_MSGIZER_FORMAT  = L"Messagizer.format";
+const wchar_t* ETCH_RESXKEY_MSGIZER_VALUFACT= L"Messagizer.valueFactory";
+const wchar_t* ETCH_RESXVAL_XPORTFMT_BINARY = L"binary";;
+const wchar_t* ETCH_RESXVAL_XPORTFMT_XML    = L"xml";
+const wchar_t* ETCH_XFACTKEY_TCP   = L"tcp";
+const wchar_t* ETCH_XPORTKEY_START = L"START";
+const wchar_t* ETCH_XPORTKEY_IS_UP = L"IS_UP";
+const wchar_t* ETCH_XPORTKEY_STOP  = L"STOP";
+const wchar_t* ETCH_XPORTKEY_START_AND_WAIT_UP  = L"START_AND_WAIT_UP";
+const wchar_t* ETCH_XPORTKEY_STOP_AND_WAIT_DOWN = L"STOP_AND_WAIT_DOWN";
+
+// TODO - lose the above strings, replacing them with integer constants
+
+const int ETCH_RESKEY_SOCKET           = 0x100;
+const int ETCH_RESKEY_POOLTYPE_FREE    = 0x101;
+const int ETCH_RESKEY_POOLTYPE_QUEUED  = 0x102;
+const int ETCH_RESKEY_MSGIZER_FORMAT   = 0x104;
+const int ETCH_RESKEY_MSGIZER_VALUFACT = 0x105;
+const int ETCH_RESVAL_XPORTFMT_BINARY  = 0x140;
+const int ETCH_RESVAL_XPORTFMT_XML     = 0x141;
+const int ETCH_XPKEY_TCP               = 0x142;
+const int ETCH_XPKEY_START             = 0x160;
+const int ETCH_XPKEY_IS_UP             = 0x161;
+const int ETCH_XPKEY_STOP              = 0x162;
+const int ETCH_XPKEY_START_AND_WAITUP  = 0x163;
+const int ETCH_XPKEY_STOP_AND_WAITDOWN = 0x164;
+const int ETCH_XPKEY_XPORTFMT_XML      = 0x165;
+
+// TODO - I don't think we need these at all, we should use class_id
+// since in this way the object can be identified and we don't need
+// to assume that the enclosing object is an etch_int32. however not
+// all of these IDs are objects, some are table IDs
+ 
+
+/*
+ * new_etch_resources 
+ * etch_resources constructor
+ */
+etch_resources* new_etch_resources(const int initialsize)
+{
+    etch_resources* resx   = new_hashtable(initialsize);
+    resx->content_type     = ETCHHASHTABLE_CONTENT_OBJECT; 
+    resx->content_obj_type = ETCHTYPEB_ETCHOBJECT;
+    resx->content_class_id = CLASSID_ANY;
+    resx->is_readonly_keys = resx->is_readonly_values = FALSE;
+    resx->freehook = string_to_object_clear_handler;  /* frees memory on clear */
+    return resx;
+}
+
+
+/*
+ * etch_resources_add()  
+ * adds specified key/value pair to specified resource map
+ */
+int etch_resources_add (etch_resources* resources, const wchar_t* key, objmask* val)
+{
+    const int hashkey = etchmap_insertxw(resources, (wchar_t*) key, val, TRUE);
+    return hashkey? 0: -1;   
+}
+
+
+/*
+ * etch_resources_get()  
+ */
+objmask* etch_resources_get (etch_resources* resources, const wchar_t* key)
+{
+    objmask* founditem = etchmap_findxw(resources, (wchar_t*) key, NULL);
+    return founditem;
+}
+
+
+/*
+ * etch_resources_clear()  
+ * clear a resources map, assuming all objects are owned unless marked as a static resource.
+ * @return count of items both removed from the map and freed.
+ */
+int etch_resources_clear (etch_resources* resources)
+{         // TODO lose this method or augment it to delete the hashtable entry memory also
+          // it leaves the memory the hashtable allocated for the key intact
+    int  freedcount = 0;
+    etch_iterator iterator;
+    wchar_t* thiskey = NULL;
+    if (!is_etch_hashtable(resources)) return 0;
+    set_iterator(&iterator, resources, &resources->iterable);
+
+    while(iterator.has_next(&iterator)) 
+    {
+        objmask* value = iterator.current_value;
+
+        if (value && !is_etchobj_static_resource(value))
+        {   value->destroy(value);
+            freedcount++;
+        }
+
+        thiskey = iterator.current_key;
+        etch_free(thiskey);
+
+        iterator.next(&iterator);
+    }
+
+    return freedcount;
+}
+
+
+/*
+ * etch_resources_replace()  
+ * adds specified key/value pair to specified resource map, first removing prior item.
+ */
+int etch_resources_replace (etch_resources* resources, const wchar_t* key, objmask* val)
+{
+    if (etch_resources_get (resources, key))
+    {
+        objmask* removedobj = etchmap_delxw (resources, (wchar_t*) key);
+
+        if (removedobj)
+            if (!is_etchobj_static_resource(removedobj))
+                removedobj->destroy(removedobj);
+    }
+
+    return etch_resources_add (resources, key, val);
+}
+

Added: incubator/etch/trunk/binding-c/runtime/c/src/common/etch_apr.c
URL: http://svn.apache.org/viewvc/incubator/etch/trunk/binding-c/runtime/c/src/common/etch_apr.c?rev=767594&view=auto
==============================================================================
--- incubator/etch/trunk/binding-c/runtime/c/src/common/etch_apr.c (added)
+++ incubator/etch/trunk/binding-c/runtime/c/src/common/etch_apr.c Wed Apr 22 17:25:43 2009
@@ -0,0 +1,124 @@
+/* $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. 
+ */ 
+
+/*
+ * etch_apr.c
+ * common apr and service initialization and teardown
+ */
+
+#include "etch_apr.h"
+#include "etch_global.h"
+#include "etchthread.h"
+#include "etchlog.h"
+
+apr_pool_t* g_apr_mempool;
+const char* apr_pooltag = "etchpool";
+int etch_apr_setup();
+int etch_apr_teardown();
+
+
+/*
+ * etch_runtime_init_all()
+ * initialize system resources. 
+ * must be called early in any client or server executable.
+ * @param args reserved for future use.
+ */
+int etch_runtime_init_all (const int is_client)
+{
+    int result;
+    if (0 == (result = etch_apr_setup()))
+        result = etch_runtime_init(is_client);
+
+    return result;
+}
+
+
+/**
+ * etch_runtime_exit()
+ * frees system resources. 
+ * must be called at close of any client or server executable.
+ * @param args etch_runtime_exit_params*, may be null.
+ */
+int etch_runtime_exit (etch_runtime_exit_params* args)
+{
+    int result = 0;
+    const int is_show_leak_detail = args? args->is_show_leak_detail: FALSE;
+
+    check_etch_heap_bytes (is_show_leak_detail, TRUE);
+
+    etch_runtime_cleanup(0, 0);
+    etch_apr_teardown();
+    etchlog_close();
+    return result;
+}
+
+
+/**
+ * check_etch_heap_bytes()  
+ * check how many bytes remain allocated on etch heap.
+ * @param is_show_detail whether to log a line for each outsatnding allocation.
+ * @params is_log_result TRUE to log a line displaying number of bytes still allocated.
+ * @return number of bytes remaining allocated.
+ */
+int check_etch_heap_bytes (const int is_show_detail, const int is_log_result)
+{
+    int result = 0, leakedbytes = 0;
+
+    #if IS_TRACKING_ETCHHEAP
+    leakedbytes = etch_showmem (0, is_show_detail);
+    #endif
+
+    if (leakedbytes && is_log_result)   
+        etchlog("ETCH", ETCHLOG_ERROR, "%d bytes remain allocated\n", leakedbytes);
+
+    return leakedbytes;
+}
+
+
+/*
+ * etch_apr_setup()
+ * establish apache portable runtime environment
+ */
+int etch_apr_setup()
+{
+    int result;
+    if (0 == (result = apr_initialize()))
+    {   result = etch_apr_init();
+        g_apr_pool = etch_apr_mempool;
+    }
+    if  (g_apr_pool)
+         apr_pool_tag(g_apr_pool, apr_pooltag);
+    else result = -1;
+    return result;
+}
+
+
+/*
+ * etch_apr_teardown()
+ * free apache portable runtime environment
+ */
+int etch_apr_teardown()
+{
+    if (g_apr_pool)
+        apr_pool_destroy(g_apr_pool);
+    g_apr_pool = NULL;
+
+    apr_terminate();
+
+    return 0;
+}

Added: incubator/etch/trunk/binding-c/runtime/c/src/common/etch_arraylist.c
URL: http://svn.apache.org/viewvc/incubator/etch/trunk/binding-c/runtime/c/src/common/etch_arraylist.c?rev=767594&view=auto
==============================================================================
--- incubator/etch/trunk/binding-c/runtime/c/src/common/etch_arraylist.c (added)
+++ incubator/etch/trunk/binding-c/runtime/c/src/common/etch_arraylist.c Wed Apr 22 17:25:43 2009
@@ -0,0 +1,663 @@
+/* $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. 
+ */ 
+
+/**
+ * etch_arraylist.c -- implementation of arraylist.
+ */
+
+#include <stdio.h>
+#include "etch_arraylist.h"
+#include "etch_global.h"
+#include "etchmutex.h"
+
+int destroy_arraylist(etch_arraylist* list);
+
+
+
+/**
+ * new_arraylist()
+ * constructor for an etch_arraylist, which implements i_iterable.
+ * passed initial size, and initial expansion delta, both expressed as 
+ * number of entries.
+ */
+etch_arraylist* new_arraylist(const unsigned initsize, const unsigned deltsize)
+{
+    etch_arraylist* list = (etch_arraylist*) new_object
+        (sizeof(etch_arraylist), ETCHTYPEB_ARRAYLIST, CLASSID_ETCH_ARRAYLIST); 
+   
+    list->size  = initsize > 0? initsize: ETCHARRAYLIST_DEFSIZE;
+    list->delta = deltsize > 0? deltsize: list->size;
+    list->size *= sizeof(void**); list->delta *= sizeof(void**);
+    list->base  = etch_malloc(list->size, ETCHTYPEB_BYTES);
+    memset(list->base, 0, list->size);
+
+    list->destroy = destroy_arraylist;
+
+    new_iterable(&list->iterable, NULL, arraylist_iterable_first, 
+        arraylist_iterable_next, arraylist_iterable_has_next); 
+
+    return list;
+}
+
+
+/**
+ * new_arraylist_from()
+ */
+etch_arraylist* new_arraylist_from(etch_arraylist* thatlist)
+{
+    etch_arraylist* thislist
+     = new_arraylist(thatlist->size, thatlist->delta);
+
+    arraylist_copyattrs(thislist, thatlist);
+
+    memcpy(thislist->base, thatlist->base, thatlist->count * sizeof(void*));
+    thislist->count = thatlist->count;
+
+    return thislist;
+}
+
+
+/**
+ * arraylist_destroy()
+ * destructor for an etch_arraylist.
+ * destroys the underlying list, the list shell, and the list content if requested.
+ * note that arraylist always owns its buffer and mutex. setting static content on
+ * an arraylist object applies only to the array content objects, if indeed content
+ * consists of object. if content is other than object, static content has no effect
+ * since the content buffer is freed regardless. 
+ */
+void arraylist_destroy(etch_arraylist* list, const int is_free_content) 
+{    
+  if (list->synchook) 
+      if (0 != list->synchook(ETCH_SYNC_TRY, list->synclock))
+          return;  /* disallow multiple destroy */
+
+    if (list->refcount > 0)        /* if object is refcounted */                                     
+        if (--list->refcount > 0) /* destroy only if last ref */
+            return;   
+
+    if (!is_etchobj_static_content(list)) /* clear and free content */
+        arraylist_clear(list, is_free_content);
+
+    etch_free(list->base);  /* arraylist always owns its buffer */
+
+    if (list->synchook)    /* release and free mutex */
+    {   list->synchook(ETCH_SYNC_REL, list->synclock);
+        list->synchook(ETCH_SYNC_DEL, list->synclock);
+    }
+
+   if (!is_etchobj_static_shell(list))
+       etch_free(list);    /* free list object */
+}
+
+
+int destroy_arraylist(etch_arraylist* list)
+{
+    arraylist_destroy(list, !list->is_readonly);
+    return 0;
+}
+
+
+
+/* - - - - - - - - - - 
+ * list maintenance
+ * - - - - - - - - - - 
+ */
+
+/**
+ * arraylist_realloc()
+ * private method to resize an arraylist.
+ * if a size greater than current size is specified, the list is realloced to that size,
+ * otherwise it is realloced to current size plus the delta size specified at construction.
+ * @note presumed that this is invoked only via arraylist_checksize, thus synchronized.
+ */
+int arraylist_realloc(etch_arraylist* list, const unsigned size)    
+{
+    unsigned int copylength = 0, newsize = 0;
+    void* newbase = NULL;
+
+    newsize = size > list->size? size: list->size + list->delta;
+    newbase = etch_malloc(newsize, ETCHTYPEB_BYTES);
+    memset(newbase, 0, newsize);
+
+    copylength = list->count * sizeof(void**);
+    memcpy(newbase, list->base, copylength); 
+
+    etch_free(list->base);
+    list->base = newbase;
+    list->size = newsize;
+    return 0;
+}
+
+
+/**
+ * arraylist_checksize()
+ * private method ensures list has space required for pending content insertion.
+ */
+int arraylist_checksize(etch_arraylist* list,
+    const int pendingitems, const int is_locked)
+{
+    int result = 1;
+    unsigned currsize = 0, newspace = pendingitems * sizeof(void**);
+
+    if (list->synchook && !is_locked) /* acquire lock */
+        list->synchook(ETCH_SYNC_SET, list->synclock);
+
+    currsize = list->count * sizeof(void**);
+
+    if  (currsize + newspace > list->size)
+         arraylist_realloc(list, newspace > list->delta? newspace: 0);
+    else result = 0;
+
+    if (list->synchook && !is_locked) /* release lock */
+        list->synchook(ETCH_SYNC_REL, list->synclock);
+
+    return result;
+}
+
+
+/*
+ * arraylist_clear() 
+ * remove all content from the arraylist, freeing content memory only if requested. 
+ * note that the list buffer does not shrink, rather retaining its current size.
+ */
+void arraylist_clear(etch_arraylist* list, const int is_free_content) 
+{
+    void** p = NULL;
+    arraycallback callback = NULL;
+    int items = 0, is_obj_content = 0, i = 0, freehandled = 0;
+    if (NULL == list || NULL == list->base) return;
+
+    if (list->synchook) /* acquire lock */
+        list->synchook(ETCH_SYNC_SET, list->synclock);
+
+    is_obj_content = list->content_type == ETCHARRAYLIST_CONTENT_OBJECT;
+    callback = list->freehook;
+    items = list->count;
+    p = list->base;
+
+    if (is_free_content && !list->is_readonly)
+        for(; i < (const int) items; i++, p++)
+        {   
+            /* optional callback to handle free */                                    
+            freehandled = callback? callback(i, *p): FALSE; 
+
+            /* if we've marked the array as having etch object content, 
+             * we invoke the object's destructor. */
+            if  (freehandled);
+            else
+            if  (is_obj_content)
+                ((objmask*)*p)->destroy(*p);            
+            else etch_free(*p);
+        }
+
+    memset(list->base, 0, items * sizeof(void**)); 
+    list->count = 0;  
+
+    if (list->synchook) /* release lock */
+        list->synchook(ETCH_SYNC_REL, list->synclock);      
+}
+
+
+/* - - - - - - - - - - 
+ * list api
+ * - - - - - - - - - - 
+ */
+
+/*
+ * arraylist_add_from() 
+ * add entries to the end of the list.
+ * returns count if items entered, or -1 if error.
+ * note that if the target array is not marked read only, this method must be
+ * used with great caution. since an arraylist not so marked will attempt to
+ * destroy its content when destroyed, and since we are copying memory references
+ * from one array to another here, the second destructor would attempt to free
+ * memory already freed in the first destructor. so to be safe, this method 
+ * should be used only with arrays marked is_readonly = TRUE, and content_type =
+ * ETCHARRAYLIST_CONTENT_OBJECT.
+ */
+int arraylist_add_from(etch_arraylist* list, etch_arraylist* newitems, 
+    etch_comparator compare) 
+{
+    int count = 0;
+    etch_iterator iterator;
+    if (!list || !list->base) return -1; 
+    if (newitems->count == 0) return 0;
+
+    if (list->synchook) /* acquire lock */
+        list->synchook(ETCH_SYNC_SET, list->synclock);
+
+    set_iterator(&iterator, newitems, &newitems->iterable);
+
+    while(iterator.has_next(&iterator))
+    {
+        if (arraylist_contains(list, iterator.current_value, 0, compare))
+            continue;
+
+        arraylist_checksize(list, 1, TRUE);  
+
+        list->base[list->count++] = iterator.current_value;
+        count++;
+
+        iterator.next(&iterator); 
+    }
+ 
+    if (list->synchook) /* release lock */
+        list->synchook(ETCH_SYNC_REL, list->synclock);     
+
+    return count;
+}
+
+
+/*
+ * arraylist_add() 
+ * add an entry to the end of the list.
+ */
+int arraylist_add(etch_arraylist* list, void* content) 
+{
+    if (!list || !list->base) return -1; 
+
+    if (list->synchook) /* acquire lock */
+        list->synchook(ETCH_SYNC_SET, list->synclock);
+ 
+    arraylist_checksize(list, 1, TRUE);  
+
+    list->base[list->count++] = content;
+
+    if (list->synchook) /* release lock */
+        list->synchook(ETCH_SYNC_REL, list->synclock);     
+
+    return 0;
+}
+
+
+/*
+ * arraylist_insert() 
+ * add a node anywhere in the list, returning 0 if OK, or -1 if error.
+ * this implementation cannot insert past the current end of list,
+ * in other words to insert at index n, there must be at least n
+ * entries currently in the list (list->count >= n), that is to say,
+ * the insertion must expand the size of the list by exactly one slot.
+ */
+int arraylist_insert(etch_arraylist* list, const unsigned int i, void* content)
+{
+    unsigned shiftcount = 0, result = -1, j = 0;
+    void **p = NULL, **q = NULL;
+    if ((NULL == list) || (i < 0)) return -1;
+
+    if (list->synchook) /* acquire lock */
+        list->synchook(ETCH_SYNC_SET, list->synclock);
+
+    arraylist_checksize(list, 1, TRUE);
+
+    if (i <= list->count)
+    {
+        shiftcount = list->count - i;  /* shift higher entries up */
+        p = &list->base[list->count - 1];  
+        q = &list->base[list->count];
+
+        for(j = 0; j < (const unsigned) shiftcount; j++, p--, q--)
+            *q = *p;
+        
+        list->base[i] = content;
+        ++list->count;
+        result = 0;
+    }  
+
+    if (list->synchook) /* release lock */
+        list->synchook(ETCH_SYNC_REL, list->synclock);    
+
+    return result;
+}
+
+
+/*
+ * arraylist_containsp() 
+ * return 1 or 0 indicating if the list contains the supplied content pointer.
+ */
+int arraylist_containsp(etch_arraylist* list, void* content, const unsigned startat)
+{
+    return arraylist_indexofp(list, content, startat) == -1? FALSE: TRUE;
+}
+
+
+/*
+ * arraylist_indexofp() 
+ * if the list contains the supplied content pointer, return its index;
+ * return -1 if not found or if a parameter was in error.
+ */
+int arraylist_indexofp(etch_arraylist* list, void* content, const unsigned startat)
+{
+    void** p = NULL;
+    int result = -1;
+    unsigned int i = startat;
+    if ((NULL == list) || (i < 0)) return result;
+
+    if (list->synchook) /* acquire lock */
+        list->synchook(ETCH_SYNC_SET, list->synclock);
+
+    if (i < list->count)
+    {
+        p = &list->base[i];
+
+        for(; i < list->count; i++, p++)  
+        {       
+            if (*p == content) 
+            {   result = i;
+                break;
+            }
+        }
+    }  
+
+    if (list->synchook) /* release lock */
+        list->synchook(ETCH_SYNC_REL, list->synclock);    
+                 
+    return result;
+}
+
+
+/*
+ * arraylist_contains() 
+ * return 1 or 0 indicating if the list contains the supplied content. 
+ * caller must supply a comparator function int (*f)(void* this, void* that);  
+ * which should return -2 bad params, -1 compares less, 0 equal, 1 greater. 
+ */
+int arraylist_contains(etch_arraylist* list, void* content, const unsigned startat,
+    etch_comparator compare)
+{
+    return arraylist_indexof(list, content, startat, compare) == -1? FALSE: TRUE;
+}
+
+
+/*
+ * arraylist_indexof() 
+ * if the list contains the supplied content, return its index.
+ * return -1 if a parameter was in error.
+ * caller must supply a comparator function int (*f)(void* this, void* that); 
+ * which should return -2 bad params, -1 compares less, 0 equal, 1 greater. 
+ */
+int arraylist_indexof(etch_arraylist* list, 
+    void* content, const unsigned startat, etch_comparator compare)
+{
+    void** p   = NULL;
+    unsigned i = startat;
+    int result = -1;
+    if ((NULL == list) || (i < 0)) return result;
+
+    if (list->synchook) /* acquire lock */
+        list->synchook(ETCH_SYNC_SET, list->synclock);
+
+    if (i < list->count)  
+    {
+        p = &list->base[i];
+
+        for(; i < list->count; i++, p++)
+        {  
+            if (0 == compare(content, *p)) 
+            {   result = i;
+                break;
+            }
+        }
+    }  
+
+    if (list->synchook) /* release lock */
+        list->synchook(ETCH_SYNC_REL, list->synclock);    
+     
+    return result;
+}
+
+
+/*
+ * arraylist_set() 
+ * replace content at specified index position.
+ */
+int arraylist_set (etch_arraylist* list, const unsigned i, void* content)
+{
+    int result = -1;
+    if ((NULL == list) || (i < 0)) return -1;
+
+    if (list->synchook) /* acquire lock */
+        list->synchook(ETCH_SYNC_SET, list->synclock);
+
+    if (i < list->count)  
+    {
+        list->base[i] = content;
+        result = 0;
+    }
+
+    if (list->synchook) /* release lock */
+        list->synchook(ETCH_SYNC_REL, list->synclock);   
+
+    return result;
+}
+
+
+/*
+ * arraylist_get() 
+ * return content at specified index position, or NULL if parameter error.
+ * a non-disposable reference is returned. 
+ * todo: mark arraylist content objects static, such that destroy() is benign,
+ * unlocking them only at such time as the arraylist itself is cleared or 
+ * destroyed, or a remove() with is_free_content is requested.
+ */
+void* arraylist_get (etch_arraylist* list, const unsigned i)
+{
+    void* result = NULL;
+    if ((NULL == list) || (i < 0)) return NULL;
+
+    if (list->synchook) /* acquire lock */
+        list->synchook(ETCH_SYNC_SET, list->synclock);
+
+    if (i < list->count)  
+        result = list->base[i];
+
+    if (list->synchook) /* release lock */
+        list->synchook(ETCH_SYNC_REL, list->synclock);  
+
+    return result;
+}
+
+
+/*
+ * arraylist_remove() 
+ * remove entry at specified index position, freeing content memory if requested.
+ * return -1 if a parameter was in error, or zero if OK.
+ */
+int arraylist_remove (etch_arraylist* list, const unsigned i, const int is_free_content)
+{
+    unsigned j = 0, newcount = 0, is_obj_content = 0, freehandled = 0, result = -1;
+    arraycallback callback = NULL;
+    void *content = NULL, **p = NULL, **q = NULL;
+    if ((NULL == list) || (i < 0)) return -1;
+
+    if (list->synchook) /* acquire lock */
+        list->synchook(ETCH_SYNC_SET, list->synclock);
+
+    if (i < list->count) 
+    {
+        is_obj_content = list->content_type == ETCHARRAYLIST_CONTENT_OBJECT;
+        callback = list->freehook;
+        
+        if (is_free_content && !list->is_readonly)
+        {
+            if (content = list->base[i])
+            {                                            
+                freehandled = callback? callback(i, content): FALSE; 
+                if  (freehandled);
+                else
+                if  (is_obj_content)
+                    ((objmask*)content)->destroy(content);            
+                else etch_free(content);
+            }
+        }
+         
+        newcount = list->count - 1;
+        p = &list->base[i];      /* shift higher entries down */
+        q = &list->base[i + 1];  /* we eschew platform-dependent memmove() */
+
+        for(j = i; j < (const unsigned)newcount; j++, p++, q++)
+            *p = *q;
+
+        list->base[newcount] = NULL;  /* zero the now-extra slot */
+        list->count = newcount;
+        result = 0;
+    }  
+
+    if (list->synchook) /* release lock */
+        list->synchook(ETCH_SYNC_REL, list->synclock);  
+
+    return result;
+}
+
+
+/*
+ * arraylist_remove_content() 
+ * remove entry whose value is specified.
+ */
+int arraylist_remove_content(etch_arraylist* list, 
+    void* content, const unsigned startat, etch_comparator compare)
+{
+    int result = -1, index = 0;
+    if (NULL == list) return result;
+
+    if (list->synchook)  
+        list->synchook(ETCH_SYNC_SET, list->synclock);
+
+    if (-1 != (index = arraylist_indexof(list, content, startat, compare)))     
+        result = arraylist_remove(list, index, TRUE);  
+     
+    if (list->synchook)  
+        list->synchook(ETCH_SYNC_REL, list->synclock);   
+
+    return result; 
+}
+
+
+/* 
+ * arraylist_copyattrs()
+ * copy array attributes from one array to another
+ */
+void arraylist_copyattrs(etch_arraylist* to, etch_arraylist* from)
+{
+    to->class_id         = from->class_id;
+    to->content_obj_type = from->content_obj_type;
+    to->content_class_id = from->content_class_id; 
+    to->is_static        = from->is_static;
+    to->content_type     = from->content_type;
+    to->is_readonly      = from->is_readonly;
+    to->freehook         = from->freehook;
+}
+
+
+/* - - - - - - - - - - 
+ * iteration lock
+ * - - - - - - - - - - 
+ */
+
+/* 
+ * arraylist_getlock()
+ * explicitly set this list's synchronization lock, waiting if unavailable.
+ * this should be used only for locking a list prior to iterating the list.   
+ * for synchronization of list operations, the presence of list.synchook  
+ * and list.synclock is sufficient. 
+ */
+int arraylist_getlock (etch_arraylist* list)
+{
+    ETCH_ASSERT(list && list->synchook && list->synclock);
+    return list->synchook (ETCH_SYNC_SET, list->synclock);
+}
+
+
+/* 
+ * arraylist_trylock()
+ * explicitly set this list's synchronization lock, failing if unavailable.
+ * this should be used only for locking a list prior to iterating the list.   
+ * for synchronization of list operations, the presence of list.synchook  
+ * and list.synclock is sufficient. 
+ */
+int arraylist_trylock (etch_arraylist* list)
+{
+    ETCH_ASSERT(list && list->synchook && list->synclock);
+    return list->synchook (ETCH_SYNC_TRY, list->synclock);
+}
+
+ 
+/* 
+ * arraylist_rellock()
+ * release explicitly set this list's synchronization lock.
+ * this should be used only for unlocking a list after iterating the list.   
+ * for synchronization of list operations, the presence of list.synchook  
+ * and list.synclock is sufficient. 
+ */
+int arraylist_rellock (etch_arraylist* list) 
+{
+    ETCH_ASSERT(list && list->synchook && list->synclock);
+    return list->synchook (ETCH_SYNC_REL, list->synclock);
+}
+
+
+/* - - - - - - - - - - 
+ * i_iterable
+ * - - - - - - - - - - 
+ */
+
+/*
+ * arraylist_iterable_first() 
+ * i_iterable first() implementation
+ */
+int arraylist_iterable_first(etch_iterator* iter)
+{
+    etch_arraylist* list = NULL;
+    if (!iter || !iter->collection)  return -1;
+    list = iter->collection;
+    if (!list->base || !list->count) return -1;
+
+    iter->current_value = arraylist_get(list, 0);   
+    iter->ordinal = iter->current_value? 1: 0;
+    return iter->ordinal? 0: -1;
+}
+
+
+/*
+ * arraylist_iterable_next() 
+ * i_iterable next() implementation
+ * functions as first() if there is no current position.
+ */
+int arraylist_iterable_next(etch_iterator* iter)
+{
+    etch_arraylist* list = iter? iter->collection: NULL;
+    const int count = list? list->count: 0;
+    if (!count || !iter->ordinal) return -1;
+    
+    iter->current_value = arraylist_get(list, iter->ordinal); 
+    iter->ordinal = iter->current_value? ++iter->ordinal: 0;
+    return iter->ordinal? 0: -1;
+}
+
+
+/*
+ * arraylist_iterable_has_next() 
+ * i_iterable has_next() implementation.
+ */
+int arraylist_iterable_has_next(etch_iterator* iter)
+{
+    etch_arraylist* list = iter? iter->collection: NULL;
+    const int count = list? list->count: 0;
+    return count && iter->ordinal && (iter->ordinal <= count);
+}
+

Added: incubator/etch/trunk/binding-c/runtime/c/src/common/etch_collection.c
URL: http://svn.apache.org/viewvc/incubator/etch/trunk/binding-c/runtime/c/src/common/etch_collection.c?rev=767594&view=auto
==============================================================================
--- incubator/etch/trunk/binding-c/runtime/c/src/common/etch_collection.c (added)
+++ incubator/etch/trunk/binding-c/runtime/c/src/common/etch_collection.c Wed Apr 22 17:25:43 2009
@@ -0,0 +1,188 @@
+/* $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. 
+ */ 
+
+/**
+ * etch_collection.c -- collection support
+ */
+
+#include "etch_collection.h" 
+#include "etch_global.h"
+#include "etchobj.h"
+
+int default_iterable_first   (etch_iterator*);
+int default_iterable_next    (etch_iterator*);
+int default_iterable_has_next(etch_iterator*);
+
+
+/**
+ * new_iterable()
+ * constructor for an i_iterable interface
+ */
+i_iterable* new_iterable(i_iterable* thisp, i_iterable* parent, iterable_first func_first, 
+    iterable_next func_next, iterable_has_next func_hasnext)
+{
+    i_iterable* vtab = NULL;
+
+    if  (thisp) /* initializing existing object? */
+         vtab = thisp;
+    else vtab = new_vtable(parent, sizeof(i_iterable), CLASSID_ITERABLE_VTAB);
+
+    if (NULL == vtab) return NULL;
+
+    vtab->first    = func_first?   func_first:   default_iterable_first;
+    vtab->next     = func_next?    func_next:    default_iterable_next;
+    vtab->has_next = func_hasnext? func_hasnext: default_iterable_has_next;
+
+    return vtab;
+}
+
+
+/**
+ * destroy_iterator()
+ * iterator destructor
+ */
+int destroy_iterator(etch_iterator* iterator)
+{   
+    if (iterator->refcount > 0)       /* if object is refcounted */                                     
+        if (--iterator->refcount > 0) /* destroy only if last ref */
+            return -1;    
+
+    /* iterator owns itself, and possibly the collection. 
+     * its vtable is owned by the collection. */
+    if (!is_etchobj_static_shell(iterator))
+    {
+        if (iterator->is_own_collection)
+           ((objmask*)iterator->collection)->destroy(iterator->collection);
+            
+        etch_free(iterator); 
+    }
+
+    return 0;
+}
+
+
+/**
+ * clone_iterator()
+ * iterator copy constructor
+ */
+etch_iterator* clone_iterator(etch_iterator* iterator)
+{   
+    etch_iterator* newobj = etch_malloc(sizeof(struct etch_iterator), ETCHTYPEB_ITERATOR); 
+    memcpy(newobj, iterator, sizeof(struct etch_iterator));
+    return newobj;
+}
+
+
+/**
+ * new_iterator()
+ * constructor for an etch_iterator object.
+ */
+etch_iterator* new_iterator(void* collection, i_iterable* iterable)
+{
+    etch_iterator* iterator = etch_malloc(sizeof(etch_iterator), ETCHTYPEB_ITERATOR);
+
+    set_iterator(iterator, collection, iterable);
+
+    return iterator;
+}
+
+
+/**
+ * set_iterator()
+ * constructor for an existing etch_iterator object.
+ */
+int set_iterator(etch_iterator* iterator, void* collection, i_iterable* iterable)
+{
+    memset(iterator, 0, sizeof(etch_iterator));
+
+    iterator->obj_type = ETCHTYPEB_ITERATOR;
+    iterator->class_id = CLASSID_ITERATOR; 
+
+    iterator->vtab = iterable;
+    iterator->collection = collection;
+
+    iterator->destroy  = destroy_iterator;
+    iterator->clone    = clone_iterator;
+
+    iterator->first    = iterable->first;
+    iterator->next     = iterable->next;
+    iterator->has_next = iterable->has_next;
+
+    iterator->first(iterator); /* establish initial position */
+    return 0;
+}
+
+
+/**
+ * new_empty_iterator()
+ * constructor for an empty etch_iterator object, i.e. has_next() is false
+ */
+etch_iterator* new_empty_iterator()
+{
+    etch_iterator* iterator = etch_malloc(sizeof(etch_iterator), ETCHTYPEB_ITERATOR);
+
+    iterator->obj_type = ETCHTYPEB_ITERATOR;
+    iterator->class_id = CLASSID_ITERATOR; 
+    iterator->destroy  = destroy_iterator;
+
+    iterator->first    = default_iterable_first;
+    iterator->next     = default_iterable_next;
+    iterator->has_next = default_iterable_has_next;
+
+    return iterator;
+}
+
+
+/**
+ * default_iterable_first()
+ * i_iterable first() default virtual method 
+ */
+int default_iterable_first(etch_iterator* i) 
+{
+    return -1;
+}
+
+
+/**
+ * default_iterable_next()
+ * i_iterable next() default virtual method 
+ */
+int default_iterable_next(etch_iterator* i) 
+{
+    return -1;
+}
+
+
+/**
+ * default_iterable_has_next()
+ * i_iterable has_next() default virtual method 
+ */
+int default_iterable_has_next (etch_iterator* i)
+{
+    return FALSE;
+}
+
+
+/**
+ * etch_comparator_noteq(), etch_comparator_equal
+ * comparators to use when a result not dependent on parameters is desired,
+ * such as when using an add_from method to add to a collection when the
+ * target collection is empty and thus no contains() comparison is needed. 
+ */
+int etch_comparator_noteq(void* a, void* b) { return -1;}
+int etch_comparator_equal(void* a, void* b) { return 0; }
\ No newline at end of file

Added: incubator/etch/trunk/binding-c/runtime/c/src/common/etch_config.c
URL: http://svn.apache.org/viewvc/incubator/etch/trunk/binding-c/runtime/c/src/common/etch_config.c?rev=767594&view=auto
==============================================================================
--- incubator/etch/trunk/binding-c/runtime/c/src/common/etch_config.c (added)
+++ incubator/etch/trunk/binding-c/runtime/c/src/common/etch_config.c Wed Apr 22 17:25:43 2009
@@ -0,0 +1,456 @@
+/* $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. 
+ */ 
+
+/*
+ * etch_config.c
+ * config items and config file parse.
+ * config file is formatted as a java-style properties file expected as ansi or utf-8.
+ */
+#include <stdlib.h>
+#include <stdarg.h>
+#include <stdio.h>
+#include <ctype.h>
+
+#pragma warning(disable:4996) /* "unsafe" function warning */
+#include "etch_config.h"  
+#include "etchlog.h"
+
+char* ETCHCFIG = "CFIG";
+
+#define ETCHMAXCONFIGLINESIZE 240
+#define ETCHCONFIG_TOKEN_FOUND 0
+#define ETCHCONFIG_LINE_IS_BLANK_OR_COMMENT 1
+
+#define ETCHCONFIG_DATATYPE_INT   1
+#define ETCHCONFIG_DATATYPE_FIXED 2
+#define ETCHCONFIG_DATATYPE_CHAR  3
+
+#define NOTWHITESPACE(p) (*p != ' '  && *p != '\t')
+#define ISWHITESPACE(p)  (*p == ' '  || *p == '\t')
+#define NOTENDOFLINE(p)  (*p != '\0' && *p != '\n' && *p != '\r')
+#define ISENDOFLINE(p)   (*p == '\0' || *p == '\n' || *p == '\r')
+
+#define ETCHSERVERDEFAULTCONFIGFILEPATH  "../etch-c-server.properties"
+#define ETCHCLIENTDEFAULTCONFIGFILEPATH  "../etch-c-client.properties"
+
+typedef struct ndx {int id; char* key;} ndx; 
+
+typedef struct etchconfig_work
+{ int  keycount, item, datatype, length, value, is_bool;
+  char *beg, *end, *endobj, *begkey, *equal, *begval, *endval;
+  double fixedval;
+} etchconfig_work;
+
+int etchconfig_identify_value (etchconfig_work*);
+int etchconfig_assign_value   (const etchconfig_work*); 
+int etchconfig_identify_item  (etchconfig_work*, char* line, ndx* keys);  
+
+
+/**
+ * get_etch_server_configfile_path()
+ * return the path to the server config file. 
+ */
+char* get_etch_server_configfile_path()
+{
+    static char* path = ETCHSERVERDEFAULTCONFIGFILEPATH;
+    return path;
+}
+
+
+/**
+ * get_etch_client_configfile_path()
+ * return the path to the client config file. 
+ */
+char* get_etch_client_configfile_path()
+{
+    static char* path = ETCHCLIENTDEFAULTCONFIGFILEPATH;
+    return path;
+}
+
+
+/**
+ * open_etch_configfile() 
+ */
+int open_etch_configfile (const int is_client, FILE** f)
+{
+    int result = 0;   
+    char* path = is_client? get_etch_client_configfile_path(): get_etch_server_configfile_path();
+
+    if (NULL == (*f = fopen(path, "r")))
+    {   path = is_client?  ETCHCLIENTDEFAULTCONFIGFILEPATH: ETCHSERVERDEFAULTCONFIGFILEPATH;
+
+        if (NULL == (*f = fopen(path, "r")))   
+        {  etchlog(ETCHCFIG, ETCHLOG_WARNING, "could not open config %s - using defaults\n", path);
+           result = -1;
+        }
+    }
+
+    return result;
+}
+
+
+/**
+ * etch_reset_config()
+ * initialize global config items with etch defaults.  
+ * @remarks whenever a new config item is added, a setter for it must be coded 
+ * herein in order to ensure that a default value exists for the item, and thus
+ * it will have an appropriate value if either no config file entry is coded for
+ * it, or if a config file can't be located and read.
+ */
+int etch_reset_config (const int is_client)
+{
+    memset(&config, 0, sizeof(struct etch_config));
+    config.memory_watch_id = 0;
+    config.log_level = ETCHCONFIGDEF_LOG_LEVEL;
+    config.loglevel  = get_etch_loglevel(ETCHCONFIGDEF_LOG_LEVEL);
+    config.max_log_files = ETCHCONFIGDEF_MAX_LOGFILES;
+    config.max_log_lines = ETCHCONFIGDEF_MAX_LOGLINES;
+    config.is_validate_on_read  = ETCHCONFIGDEF_IS_VALIDATE_ON_READ;
+    config.is_validate_on_write = ETCHCONFIGDEF_IS_VALIDATE_ON_WRITE;
+    config.is_log_to_file = ETCHCONFIGDEF_IS_LOG_TO_FILE;
+    config.is_log_to_console = ETCHCONFIGDEF_IS_LOG_TO_CONSOLE;
+    config.is_log_memory_leak_detail = ETCHCONFIGDEF_IS_LOG_MEMORY_LEAK_DETAIL;
+    config.is_destroy_messages_with_mailbox = ETCHCONFIGDEF_IS_DESTROY_MESSAGES_WITH_MAILBOX;
+    config.default_mailbox_read_waitms = ETCHCONFIGDEF_DEFAULT_MAILBOX_READ_WAITMS;
+    config.sleepSecondsPriorClientExit = ETCHCONFIGDEF_SLEEP_SECONDS_PRIOR_CLIENT_EXIT;
+    strncpy(config.example_string, ETCHCONFIGDEF_EXAMPLE_STRING_VALUE, ETCHCONFIGDEF_EXAMPLE_STRING_MAXLEN);
+
+    return 0;
+}
+
+
+/**
+ * etch_read_configfile()
+ * read and validate config file, populate global config items. 
+ * @param is_client boolean indicating if reading config on client side.
+ * @param is_reset boolean indicating if global config items should be reset
+ * to default values prior to reading the config file.
+ * @return 0 success, -1 failure.
+ * @remarks whenever a new config item is added, a mapping from that item's 
+ * key to its external config file name must be coded herein.
+ */
+int etch_read_configfile (const int is_client, const int is_reset)
+{
+    int  result = 0, linenum = 0, itemcount = 0;
+    char line [ETCHMAXCONFIGLINESIZE+1];  
+    etchconfig_work work; 
+    FILE* f = 0;
+
+    ndx config_keys[] =                     
+    { {ETCHCONFIGKEY_LOG_LEVEL,  "logLevel"},
+      {ETCHCONFIGKEY_MAX_LOGFILES, "maxLogFiles"},
+      {ETCHCONFIGKEY_MAX_LOGLINES, "maxLogLines"},
+      {ETCHCONFIGKEY_ETCH_WATCH_ID, "memoryWatchID"},
+      {ETCHCONFIGKEY_IS_LOG_TO_FILE,  "isLogToFile"},
+      {ETCHCONFIGKEY_IS_LOG_TO_CONSOLE,  "isLogToConsole"},
+      {ETCHCONFIGKEY_IS_VALIDATE_ON_READ,   "isValidateOnRead"},
+      {ETCHCONFIGKEY_IS_VALIDATE_ON_WRITE,  "isValidateOnWrite"},
+      {ETCHCONFIGKEY_IS_DESTROY_MESSAGES_WITH_MAILBOX, "isDestroyMessagesWithMailbox"},
+      {ETCHCONFIGKEY_IS_DISPLAY_MEMORY_LEAK_DETAIL,    "isDisplayMemoryLeakDetail"},
+      {ETCHCONFIGKEY_DEFAULT_MAILBOX_READ_WAITMS  ,    "defaultMailboxReadWaitms"},
+      {ETCHCONFIGKEY_SLEEP_SECONDS_PRIOR_CLIENT_EXIT,  "sleepSecondsPriorClientExit"},
+      {ETCHCONFIGKEY_TEST_STRING, "testString"},  /* for testing only */
+      {ETCHCONFIGKEY_TEST_INT,    "testInt"},     /* for testing only */
+      {ETCHCONFIGKEY_TEST_BOOL,   "testBool"},    /* for testing only */
+      {ETCHCONFIGKEY_TEST_FIXED,  "testFixed"},   /* for testing only */
+    };
+
+    memset(&work, 0, sizeof(etchconfig_work));
+    work.keycount = sizeof(config_keys) / sizeof(ndx);
+
+    if (is_reset)  /* reset config entries to etch defaults */
+        etch_reset_config (is_client);
+  
+    if (-1 == open_etch_configfile (is_client, &f))  /* open config file */
+        return -1;
+
+    while(1) /* while not eof on config file ... */
+    {
+        if (NULL == fgets (line, ETCHMAXCONFIGLINESIZE, f)) break;
+        work.item = 0;
+        linenum++;
+
+        result = etchconfig_identify_item (&work, line, config_keys);
+        if (ETCHCONFIG_LINE_IS_BLANK_OR_COMMENT == result) continue; 
+
+        if (-1 == result) 
+        {   etchlog(ETCHCFIG, ETCHLOG_ERROR, "at line %d: name not recognized\n", linenum);
+            continue;
+        } 
+
+        if((-1 == etchconfig_identify_value(&work)) || (-1 == etchconfig_assign_value(&work)))
+        {
+            etchlog(ETCHCFIG, ETCHLOG_ERROR, "at line %d: invalid item value\n", linenum);
+            continue;
+        }
+
+        if (*work.endval == ';') /* warning that a semicolon may have been typed in error */
+            etchlog(ETCHCFIG, ETCHLOG_WARNING, "at line %d: value ends with semicolon\n", linenum);
+
+        itemcount++;
+    }
+       
+    fclose(f);
+    etchlog(ETCHCFIG, ETCHLOG_DEBUG, "%d config entries read\n", itemcount);
+    return itemcount;
+}
+
+
+/**
+ * etchconfig_identify_item()
+ * parse out and identify object token   
+ */
+int etchconfig_identify_item (etchconfig_work* work, char* line, ndx* keys)  
+{
+    int  i;
+    ndx  *keyi = keys;
+    char csave, *q, *p = line;
+
+    while(ISWHITESPACE(p)) p++;  /* find first noblank character */
+    if (ISENDOFLINE(p)) return ETCHCONFIG_LINE_IS_BLANK_OR_COMMENT;
+    work->beg = p;               /* mark initial character */ 
+
+    while(*p && *p != '#' && *p != '=') p++;  /* find equal sign */              
+    if (*p == '#')      return ETCHCONFIG_LINE_IS_BLANK_OR_COMMENT;
+    if (ISENDOFLINE(p)) return -1;
+
+    work->equal = p;             /* mark equal sign */
+
+    q = work->equal; q--;
+    while(ISWHITESPACE(q))  q--; /* strip trailing whitespace */
+
+    work->end = q;               /* mark final character */
+    q++;                         /* point after item name */
+    csave = *q;                  /* save character at that position */
+    *q = '\0';                   /* and terminate item name string */
+    
+    for(i = 0, work->item = 0; i < (const int) work->keycount; i++, keyi++)
+    {   /* compare found item name with expected item names */
+        if (stricmp(keyi->key, work->beg) == 0)
+        {   work->item = keyi->id;
+            break;
+        }
+    }
+ 
+    *q = csave;  /* restore character replaced above */
+    return work->item? ETCHCONFIG_TOKEN_FOUND: -1;
+}
+
+
+/**
+ * etchconfig_identify_item()
+ * parse out item value and determine its data type.   
+ */                                            
+int etchconfig_identify_value (etchconfig_work* work)             
+{
+    char *p = NULL, *q = NULL;
+    int  i = 0, digits = 0, expecteddigits = 0, dots = 0, isnegative = 0; 
+    work->length = work->datatype = work->is_bool = 0;
+    work->begval = work->endval = NULL; 
+
+    p = work->equal; p++;                     /* start after equal sign */
+    while(*p && ISWHITESPACE(p)) p++;         /* find first noblank character */
+    if (ISENDOFLINE(p) || *p == '#') return -1;
+
+    q = p;
+    while(NOTENDOFLINE(q) && *q != '#') q++;  /* find end of line or comment */
+    q--;
+    while(ISWHITESPACE(q)) q--;               /* strip trailing whitespace */
+              
+    /* calculate length of value */                              
+    work->length = (int) ((size_t) q - (size_t) p + 1);    
+    if (work->length < 1) return -1; 
+
+    if (*p == '\"')                 /* if quoted string ... */
+    {   if (*q != '\"') return -1;  /* test for close quote */
+        p++; q--;                   /* remove quotes */
+        work->datatype = ETCHCONFIG_DATATYPE_CHAR;
+    }
+
+    work->begval = p;   /* set value boundaries */
+    work->endval = q;
+    *++q = '\0';        /* add terminator for logging */
+
+    if (work->datatype) /* data type now known? */
+        return ETCHCONFIG_TOKEN_FOUND;
+                     
+    /* determine data type of value */   
+    expecteddigits = work->length; 
+        
+    for(; i < (const int) work->length; i++, p++)
+    {
+      if  (isdigit(*p))
+           digits++;
+      else
+      if  (*p == '-' && i == 0)  /* negative sign? */
+           isnegative = TRUE;
+      else                       /* decimal point? */
+      if  (*p == '.')
+           dots++;      
+    }
+
+    if (digits > 0)
+    {   if (isnegative) expecteddigits--;
+        if (dots == 1)  expecteddigits--;
+    }
+
+    if (digits == expecteddigits && dots == 0)
+    {    /* integral value e.g. 314159 */
+         work->datatype = ETCHCONFIG_DATATYPE_INT;
+         work->value = atoi(work->begval);
+         if (work->value == 0 ||work->value == 1)
+             work->is_bool = TRUE;  /* integer is boolean-valued */
+    }
+    else
+    if  (digits == expecteddigits && dots == 1)
+    {    /* fixed decimal value e.g. 3.14159 */
+         work->datatype = ETCHCONFIG_DATATYPE_FIXED;
+         work->fixedval = strtod(work->begval, &q);
+    }    /* unquoted string */
+    else work->datatype = ETCHCONFIG_DATATYPE_CHAR;
+
+    return ETCHCONFIG_TOKEN_FOUND;
+}
+
+
+/**
+ * get_etch_loglevel()
+ * convert log level from character supplied in config to ordinal used by logger. 
+ */  
+int get_etch_loglevel (const unsigned char loglvl)
+{
+    int thislevel = -1;
+    switch(toupper(loglvl))
+    { case 'D': thislevel = ETCHLOG_DEBUG;   break;   
+      case 'I': thislevel = ETCHLOG_INFO;    break;  
+      case 'X': thislevel = ETCHLOG_XDEBUG;  break;   
+      case 'E': thislevel = ETCHLOG_ERROR;   break;   
+      case 'W': thislevel = ETCHLOG_WARNING; break;   
+    }
+    return thislevel;
+}
+
+
+/**
+ * etchconfig_assign_value()
+ * edit value from config file and assign to internal config item. 
+ * @remarks whenever a new config item is added, its key, plus code 
+ * to validate the value, must be added to the switch herein.
+ */  
+int etchconfig_assign_value (const etchconfig_work* work)                   
+{
+    const int datatype = work->datatype; 
+    const int ivalue   = work->value, is_bool_value = work->is_bool;
+    const char* cvalue = work->begval;
+    int result = 0, n = 0;
+
+    switch(work->item)
+    { 
+      case ETCHCONFIGKEY_LOG_LEVEL:
+           if (datatype != ETCHCONFIG_DATATYPE_CHAR) 
+               result = -1; 
+           else  /* translate character level to ordinal */
+           if (-1 == (n = get_etch_loglevel (*cvalue)))
+               result = -1;
+           else 
+           {  config.loglevel = n;   /* ordinal level */
+              config.log_level = *cvalue;  /* character level */
+           }
+           break;
+
+      case ETCHCONFIGKEY_MAX_LOGFILES:
+           if (datatype != ETCHCONFIG_DATATYPE_INT) result = -1;
+           else config.max_log_files = ivalue;
+           break;
+
+      case ETCHCONFIGKEY_MAX_LOGLINES:
+           if (datatype != ETCHCONFIG_DATATYPE_INT) result = -1;
+           else config.max_log_lines = ivalue;
+           break;
+
+      case ETCHCONFIGKEY_ETCH_WATCH_ID:
+           if (datatype != ETCHCONFIG_DATATYPE_INT) result = -1;
+           else config.memory_watch_id = ivalue;
+           break;
+
+      case ETCHCONFIGKEY_DEFAULT_MAILBOX_READ_WAITMS:
+           if (datatype != ETCHCONFIG_DATATYPE_INT || ivalue < (-1)) 
+               result = -1;
+           else config.default_mailbox_read_waitms = ivalue;
+           break;
+
+      case ETCHCONFIGKEY_IS_LOG_TO_FILE:
+           if (!is_bool_value) result = -1; 
+           else config.is_log_to_file = ivalue;
+           break;
+
+      case ETCHCONFIGKEY_IS_LOG_TO_CONSOLE:
+           if (!is_bool_value) result = -1; 
+           else config.is_log_to_console = ivalue;
+           break;
+
+      case ETCHCONFIGKEY_IS_VALIDATE_ON_READ:
+           if (!is_bool_value) result = -1; 
+           else config.is_validate_on_read = ivalue;
+           break;
+
+      case ETCHCONFIGKEY_IS_VALIDATE_ON_WRITE:
+           if (!is_bool_value) result = -1; 
+           else config.is_validate_on_write = ivalue;
+           break;
+
+      case ETCHCONFIGKEY_IS_DESTROY_MESSAGES_WITH_MAILBOX:
+           if (!is_bool_value) result = -1; 
+           else config.is_destroy_messages_with_mailbox = ivalue;
+           break;
+
+      case ETCHCONFIGKEY_IS_DISPLAY_MEMORY_LEAK_DETAIL:
+           if (!is_bool_value) result = -1; 
+           else config.is_log_memory_leak_detail = ivalue;
+           break;
+
+      case ETCHCONFIGKEY_SLEEP_SECONDS_PRIOR_CLIENT_EXIT:
+           if (datatype != ETCHCONFIG_DATATYPE_INT || ivalue < 0) 
+               result = -1;
+           else config.sleepSecondsPriorClientExit = ivalue;
+           break;
+
+      /* test items for testing config file parsing */
+      case ETCHCONFIGKEY_TEST_STRING: /* example for a string config entry */
+           if (datatype != ETCHCONFIG_DATATYPE_CHAR) result = -1;
+           else if (strlen(cvalue) > ETCHCONFIGDEF_EXAMPLE_STRING_MAXLEN) result = -1; 
+           else strcpy(config.example_string, cvalue);
+           break;
+
+      case ETCHCONFIGKEY_TEST_INT:
+           if (datatype != ETCHCONFIG_DATATYPE_INT) result = -1;
+           break;
+
+      case ETCHCONFIGKEY_TEST_BOOL:
+           if (!is_bool_value) result = -1; 
+           break;
+
+      case ETCHCONFIGKEY_TEST_FIXED:
+           if (datatype != ETCHCONFIG_DATATYPE_FIXED) result = -1;
+           break;
+
+      default: result = -1; 
+    }
+
+    return result;
+}

Added: incubator/etch/trunk/binding-c/runtime/c/src/common/etch_encoding.c
URL: http://svn.apache.org/viewvc/incubator/etch/trunk/binding-c/runtime/c/src/common/etch_encoding.c?rev=767594&view=auto
==============================================================================
--- incubator/etch/trunk/binding-c/runtime/c/src/common/etch_encoding.c (added)
+++ incubator/etch/trunk/binding-c/runtime/c/src/common/etch_encoding.c Wed Apr 22 17:25:43 2009
@@ -0,0 +1,221 @@
+/* $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. 
+ */ 
+
+/**
+ * etch_encoding.c -- character encoding
+ */
+
+/* we include an APR header only to get required platform specific headers (windows.h or whatever */
+#include <apr_thread_cond.h> 
+#include "etch_encoding.h"
+#include "etch_global.h"
+#include "etchlog.h"
+
+#if IS_WINDOWS_ETCH
+#include "winnls.h" /* for WideCharToMultiByte etc */
+#endif
+char* ETCH_ENCODING_LOGID = "ENCO";
+char* ETCH_ENCODING_EMASK = "encoding conversion error %d\n";
+void etch_encoding_errcheck(const int);
+
+
+/*
+ * etch_unicode_to_8bit()
+ * currently windows-specific. todo need portable version.
+ * @param unicode_string_in a character string, caller retains ownership.
+ * @param which which codepage to use, utf-8 (1) or ansi (0)
+ * @return an 8-bit character string, via the out parameter,
+ * caller assumes ownership of this memory.
+ * @return 0 or -1
+ */
+int etch_unicode_to_8bit(char** bit8_string_out, wchar_t* unicode_string_in, const which)
+{
+    const int charcount_in = (int) wcslen(unicode_string_in);
+    int   bit8_charcount = 0, bytecount_out = 0, codepage = 0, result = -1;
+    char* bit8_buf = NULL;
+    if (NULL == bit8_string_out) return -1;
+
+    #if IS_WINDOWS_ETCH  /* todo: portable implementation */
+
+    codepage = which == 1? CP_UTF8: CP_ACP;
+
+    /* call system first to calculate utf-8 buffer size required for 
+     * given unicode input and output code page. out buffer length zero 
+     * instructs system to do so. */
+    bit8_charcount = WideCharToMultiByte(codepage, 0, 
+        unicode_string_in, charcount_in, bit8_buf, bit8_charcount, NULL, NULL); 
+
+    bit8_buf = etch_malloc(++bit8_charcount, ETCHTYPEB_BYTES); /* add null term */
+    memset(bit8_buf, 0, bit8_charcount);
+
+    bytecount_out = WideCharToMultiByte(codepage, 0, /* do conversion */ 
+        unicode_string_in, charcount_in, bit8_buf, bit8_charcount, NULL, NULL); 
+
+    result = bytecount_out > 0? 0: -1;  
+
+    if (result == 0)    /* transfer ownership of out buffer to caller */  
+       *bit8_string_out = bit8_buf; 
+    else
+    {  *bit8_string_out = NULL; 
+        etch_free(bit8_buf); bit8_buf = NULL;
+    }   
+    
+    etch_encoding_errcheck(result);
+
+    #endif /* IS_WINDOWS_ETCH */ 
+
+    return result;
+}
+
+
+/*
+ * etch_unicode_to_utf8()
+ * @param unicode_string_in a character string owned by caller.
+ * @return a UTF-8 encoded string, via the out parameter, 
+ * caller assumes ownership of this memory.
+ * @return 0 or -1 
+ */
+int etch_unicode_to_utf8(char** utf8_string_out, wchar_t* unicode_string_in)
+{
+    return etch_unicode_to_8bit(utf8_string_out, unicode_string_in, 1);
+}
+
+
+/*
+ * etch_unicode_to_ansi()
+ * @param unicode_string_in a character string owned by caller.
+ * @return an ascii encoded string, via the out parameter, 
+ * caller assumes ownership of this memory, which must be etch_free()'d
+ * @return 0 or -1 
+ */
+int etch_unicode_to_ansi(char** ansi_string_out, wchar_t* unicode_string_in)
+{
+    return etch_unicode_to_8bit(ansi_string_out, unicode_string_in, 0);
+}
+
+
+/*
+ * etch_unicode_to_8bit()
+ * currently windows-specific. todo need portable version.
+ * @param bit8_string_in a character string owned by caller.
+ * @return a unicode string, via the out parameter, 
+ * caller assumes ownership of this memory, which must be etch_free()'d
+ * @return 0 or -1 
+ */
+int etch_8bit_to_unicode(wchar_t** unicode_string_out, char* bit8_string_in, const which)
+{
+    const int charcount_in = (int) strlen(bit8_string_in);
+    int unicode_bufsize = 0, charcount_out = 0, codepage = 0, result = -1;
+    wchar_t* ubuf = NULL;
+    if (NULL == unicode_string_out) return -1;
+
+    #if IS_WINDOWS_ETCH  /* todo: portable implementation */
+
+    codepage = which == 1? CP_UTF8: CP_ACP;
+
+    unicode_bufsize = (charcount_in + 1) * 2; 
+    ubuf = etch_malloc(unicode_bufsize, ETCHTYPEB_BYTES); 
+    memset(ubuf, 0, unicode_bufsize);
+
+    charcount_out = MultiByteToWideChar(codepage, 0, /* do conversion */ 
+        bit8_string_in, charcount_in + 1, ubuf, unicode_bufsize); 
+
+    result = charcount_out > 0? 0: -1;  
+
+    if (result == 0)    /* transfer ownership of out buffer to caller */  
+       *unicode_string_out = ubuf; 
+    else
+    {  *unicode_string_out = NULL; 
+        etch_free(ubuf); ubuf = NULL;
+    }   
+
+    etch_encoding_errcheck(result);
+
+    #endif /* IS_WINDOWS_ETCH */ 
+
+    return result;
+}
+
+
+/*
+ * etch_utf8_to_unicode()
+ * @param utf8_string_in a character string owned by caller.
+ * @return a UTF-16 encoded string, via the out parameter, 
+ * caller assumes ownership of this memory, which must be etch_free()'d
+ * @return 0 or -1 
+ */
+int etch_utf8_to_unicode(wchar_t** unicode_string_out, char* utf8_string_in)
+{
+    return etch_8bit_to_unicode(unicode_string_out, utf8_string_in, 1);
+}
+
+
+/*
+ * etch_ansi_to_unicode()
+ * @param ascii_string_in a character string owned by caller.
+ * @return a UTF-16 encoded string, via the out parameter, 
+ * caller assumes ownership of this memory, which must be etch_free()'d
+ */
+int etch_ansi_to_unicode(wchar_t** unicode_string_out, char* ascii_string_in)
+{
+    return etch_8bit_to_unicode(unicode_string_out, ascii_string_in, 0);
+}
+
+
+/*
+ * etch_encoding_errcheck()
+ * private method to check result of an encoding conversion and log error.
+ */
+void etch_encoding_errcheck(const int result)
+{
+    int ecode, whicherr;
+    if (result == 0) return;
+
+    #if IS_WINDOWS_ETCH
+
+    ecode = GetLastError();
+    switch(whicherr = ecode)
+    {   case ERROR_INSUFFICIENT_BUFFER: whicherr = 1; break;
+        case ERROR_INVALID_FLAGS:       whicherr = 2; break; 
+        case ERROR_INVALID_PARAMETER:   whicherr = 3; break;
+    }
+    etchlog(ETCH_ENCODING_LOGID,ETCHLOG_ERROR,ETCH_ENCODING_EMASK, whicherr); 
+
+   #endif  
+}
+
+
+/*
+ * etch_get_unicode_bytecount()
+ * @param widestring a unicode string.
+ * @return number of bytes in the string, including the null terminator.
+ */
+size_t etch_get_unicode_bytecount (wchar_t* widestring)
+{
+    wchar_t* q = NULL;
+    size_t bytecount = 0;
+    const int charcount = widestring? (int) wcslen(widestring): 0;
+    if (0 == charcount) return 0;
+    q = &widestring[charcount];
+    q++;  
+    bytecount = ((size_t)(char*) q) - ((size_t)(char*) widestring);
+    return bytecount;
+}
+
+
+

Added: incubator/etch/trunk/binding-c/runtime/c/src/common/etch_global.c
URL: http://svn.apache.org/viewvc/incubator/etch/trunk/binding-c/runtime/c/src/common/etch_global.c?rev=767594&view=auto
==============================================================================
--- incubator/etch/trunk/binding-c/runtime/c/src/common/etch_global.c (added)
+++ incubator/etch/trunk/binding-c/runtime/c/src/common/etch_global.c Wed Apr 22 17:25:43 2009
@@ -0,0 +1,231 @@
+/* $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. 
+ */ 
+
+/**
+ * etch_global.c -- logically global methods, "static" methods, etc.
+ * methods which can logically be executed from any context.
+ */
+
+#include <stdio.h>
+#ifdef WIN32
+#include <windows.h>
+#endif
+
+#include "etch_global.h"
+#include "etchlog.h"
+#include "etchutl.h"
+#include <conio.h>
+wchar_t* etch_emptystru = L"";
+char*    etch_emptystra = "";
+char*    ETCHGLOB = "ETCH";
+
+void etch_instantiate_global_constants();
+void etch_free_global_constants();
+
+
+/**
+ * etch_runtime_init()
+ * global etch runtime startup initialization.
+ */
+int etch_runtime_init(const int is_client)
+{
+    int result = 0;
+    if (is_runtime_initialized) return 1;
+    etchlog_open(is_client);               /* open log file */
+    etch_read_configfile(is_client, TRUE); /* initialize config - read config file */
+    etchlog(ETCHGLOB, ETCHLOG_INFO, "log priority level is '%c'\n", config.log_level);
+
+    etch_instantiate_global_constants();   /* initialize quasi-static constants */
+
+    #if IS_TRACKING_ETCHHEAP               /* warning re memory tracking overhead */
+    etchlog(ETCHGLOB, ETCHLOG_WARNING, "IS_TRACKING_ETCHHEAP is ON (normally off)\n");
+    /* etch_watch_id is the global allocator ordinal for memory leak analysis. 
+     * if etch_watch_id is nonzero, and if IS_TRACKING_ETCHHEAP is compiled TRUE, 
+     * a debug break will occur at the specified memory allocation ordinal. 
+     */ 
+    etch_watch_id = config.memory_watch_id;
+    if (etch_watch_id)
+        etchlog(ETCHGLOB, ETCHLOG_WARNING, 
+           "memory watch ID found - break to debugger may occur\n");
+    #endif
+    #if(0)
+    #if IS_USING_ALLOC_ID   
+    etchlog(ETCHGLOB, ETCHLOG_INFO, "IS_USING_ALLOC_ID is compiled ON (normally off)\n");
+    #endif
+    #endif
+
+    is_runtime_initialized = TRUE;
+
+    result = cache_create()? 0: -1;  /* instantiate runtime cache */
+    
+    if (0 == result)                 /* initialize running count of log files */
+        etchlog_set_logfile_count (etchlog_countfiles (etchlog_get_dirpath()));
+
+    return result;
+}
+
+
+/**
+ * etch_runtime_cleanup()
+ * global etch runtime cleanup
+ * clears and frees the memory tracking table, and finally the runtime cache
+ */
+int etch_runtime_cleanup(int n, int m)
+{
+    is_memtable_instance = TRUE;
+    etch_free_global_constants();
+    destroy_hashtable(memtable, TRUE, TRUE);
+    memtable = NULL;
+    is_memtable_instance = FALSE;
+    cache_destroy();
+    return 0;
+}
+
+
+/**
+ * memtable_clear()
+ * global memory tracking table checkpoint.
+ * clears all entries from the memory tracking table but leaves table intact.
+ * we would use this for example between unit tests which uncovered memory leaks,
+ * but we did not want to carry forward the leaks to the next tests.
+ */
+int memtable_clear()
+{
+    etchheap_currbytes = 0;
+    if (NULL == memtable) return 0;
+
+    is_memtable_instance = TRUE;
+    memtable->vtab->clear(memtable->realtable, TRUE, TRUE, memtable, 0); 
+    is_memtable_instance = FALSE;
+    return 0;
+}
+
+
+/**
+ * etch_strbytes()
+ * @param s a unicode string.
+ * @return number of bytes in s
+ */
+size_t etch_strbytes(const wchar_t* s) 
+{
+    return s? (wcslen(s) + 1) * sizeof(wchar_t): 0;
+}
+
+
+/**
+ * etch_instantiate_global_constants()
+ * instantiate global constants. these are constants which can't be statically intialized.
+ * some of these may need to be freed in etch_free_global_constants in order that tests
+ * can show all memory freed. any etch objects instantiated here may need to have their  
+ * is_static marker set in order that they remain instantiated throughout execution.
+ */
+void etch_instantiate_global_constants()
+{
+    etchgc.etch_charsetname_us_ascii = L"us-ascii";
+    etchgc.etch_charsetname_utf8     = L"utf-8";
+    etchgc.etch_charsetname_utf16    = L"utf-16";
+    etchgc.pctd = "%d";
+}
+
+
+/**
+ * etch_free_global_constants()
+ * free memory for global constants. etch objects freed here may need to have their  
+ * is_static marker reset to zero so that their destructors will free them.
+ */
+void etch_free_global_constants()
+{
+
+}
+
+
+/**
+ * get_dynamic_classid()
+ * get a class ID for objects not known to the binding.  
+ * assignment is currently non-atomic.
+ */
+unsigned short get_dynamic_classid() 
+{
+    if (g_etch_curr_classid == 0)
+        g_etch_curr_classid = CLASSID_DYNAMIC_START;
+
+    return g_etch_curr_classid++;
+} 
+
+
+/**
+ * get_dynamic_classid_unique()
+ * if specified ID already assigned, return it; otherwise generate and return. 
+ * assignment is currently non-atomic.
+ */
+unsigned short get_dynamic_classid_unique(unsigned short* globalid) 
+{
+    if (*globalid == 0) 
+        *globalid = get_dynamic_classid();
+    return (*globalid);
+} 
+
+
+/**
+ * is_bad_pointer()
+ * not sure how portable this is, but it catches freed windows heap content
+ * such as pointer values 0xcccccccc, 0xfeeefeee, etc. it judges the specified
+ * pointer to be bad if the high nibble is non-zero.
+ */
+boolean is_bad_pointer(void* p)
+{
+    const static size_t mask = 0xf << (((sizeof(void*) - 1) * 8) + 4);
+    return ((size_t)p & mask) != 0;
+}
+
+
+/**
+ * waitkey()
+ * method to wait for a keypress. called from client and server exe's in order  
+ * to optionally not exit console window until a key is pressed.
+ */
+int waitkey(const int is_waitkey_enabled, const int result)
+{
+    if (is_waitkey_enabled)
+    {   printf("any key ..."); 
+        while(!_getch());
+        printf("\n");
+    }
+    return result;
+}
+
+
+/**
+ * etch_system_nanotime()
+ * operating system specific implementation of java System.nanotime().
+ */
+int64 etch_system_nanotime()
+{
+    int64 result = 0;
+
+    #ifdef WIN32  
+
+    LARGE_INTEGER li;
+    QueryPerformanceCounter(&li);
+    result = li.QuadPart;
+
+    #endif /* WIN32 */
+
+    return result;
+}
+