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