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 [19/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/common/etchobj.c
URL: http://svn.apache.org/viewvc/incubator/etch/trunk/binding-c/runtime/c/src/common/etchobj.c?rev=767594&view=auto
==============================================================================
--- incubator/etch/trunk/binding-c/runtime/c/src/common/etchobj.c (added)
+++ incubator/etch/trunk/binding-c/runtime/c/src/common/etchobj.c Wed Apr 22 17:25:43 2009
@@ -0,0 +1,1234 @@
+/* $Id$ 
+ * 
+ * Licensed to the Apache Software Foundation (ASF) under one or more 
+ * contributor license agreements. See the NOTICE file distributed with  
+ * this work for additional information regarding copyright ownership. 
+ * The ASF licenses this file to you under the Apache License, Version  
+ * 2.0 (the "License"); you may not use this file except in compliance  
+ * with the License. You may obtain a copy of the License at 
+ * 
+ * http://www.apache.org/licenses/LICENSE-2.0 
+ * 
+ * Unless required by applicable law or agreed to in writing, software 
+ * distributed under the License is distributed on an "AS IS" BASIS, 
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and 
+ * limitations under the License. 
+ */ 
+
+/* 
+ * etchobj.c  
+ */
+
+#include "etch_global.h"
+#include "etchexcp.h"
+  
+
+unsigned int primitive_objsize[] =
+{
+    sizeof(etch_byte),  sizeof(etch_boolean), sizeof(etch_int8),  sizeof(etch_int16), 
+    sizeof(etch_int32), sizeof(etch_int64),   sizeof(etch_float), sizeof(etch_double),
+    sizeof(etch_string),sizeof(etch_date),  
+};
+
+
+/**
+ * destroy_object()
+ * default virtual destructor for an objmask* based object 
+ * (other than etch_object), invoked by all other object dtors. 
+ */
+int destroy_object(objmask* thisobj)
+{
+    objmask* parentobj = NULL;
+    if (thisobj == NULL) return -1;  
+    parentobj = thisobj->parent;   
+
+    /* if a calling destructor did not already decrement the refcount ... */
+    if (!is_etchobj_refcount_decremented(thisobj))
+        if (thisobj->refcount > 0)        /* if object is refcounted */                                     
+            if (--thisobj->refcount > 0) /* destroy only if last ref */
+                return -1;    
+
+    if (thisobj->result)
+    {    
+        destroy_exception(thisobj->result->exception);
+        etch_free(thisobj->result);
+    }
+ 
+    if (!is_etchobj_static_shell(thisobj))
+        etch_free(thisobj); 
+
+    if (parentobj && parentobj->destroy)
+        parentobj->destroy(parentobj);
+    
+    return 0;
+}
+
+
+/**
+ * destroy_objectex()
+ * mark object as "refcount already decremented" and invoke destroy_object
+ */
+int destroy_objectex(objmask* thisobj)
+{   /* we usurp hashkey for this purpose since object is being destroyed anyway */
+    if (thisobj) thisobj->hashkey = ETCH_NOREFCOUNT_MARKER;
+    return destroy_object(thisobj);
+}
+
+
+/**
+ * destroy_etch_object()
+ * default virtual destructor for an anonymous object wrapper.
+ * such a wrapper is final (it will not have a parent)
+ */
+int destroy_etch_object(etch_object* thisobj)
+{
+    objmask* childobj  = NULL;
+    int is_childobj_etchobj = 0, is_childobj_owned = 0, is_static_content = 0;
+    if (thisobj == NULL) return -1; 
+
+    if (thisobj->refcount > 0)        /* if object is refcounted */                                     
+        if (--thisobj->refcount > 0) /* destroy only if last ref */
+            return -1;    
+
+    if (thisobj->result)
+    {   /* a result object pointer is not part of static content since never copied */
+        destroy_exception(thisobj->result->exception);
+        etch_free(thisobj->result);
+    }
+
+    childobj = thisobj->value;
+    is_childobj_etchobj = thisobj->is_value_object;
+    is_childobj_owned   = thisobj->is_value_owned;
+    is_static_content   = is_etchobj_static_content(thisobj);
+
+    if (!is_etchobj_static_shell(thisobj))
+        etch_free(thisobj); 
+
+    if (childobj && is_childobj_owned && !is_static_content)
+    {   if  (is_childobj_etchobj)
+             childobj->destroy(childobj);
+        else etch_free(childobj);
+    }
+    
+    return 0;
+}
+
+
+/**
+ * destroy_etch_object_value()
+ * destroy the content of an object wrapper.
+ * this is not called by the object destructor because it destroys the wrapper first.
+ */
+int destroy_etch_object_value(etch_object* x)
+{
+    int  result = 0;
+
+    if  (is_etchobj_static_content(x))
+         result = -1;
+    else
+    if  (x->is_value_owned)
+         if  (x->is_value_object)
+             ((objmask*)x->value)->destroy(x->value);
+         else etch_free(x->value);
+    else result = -1;
+
+    return result;
+}
+
+
+/**
+ * set_etch_assignable_arg_from()
+ * populate an argument to etchobj_is_assignable_from() from specified object
+ */
+void set_etch_assignable_arg_from(etch_objclass* arg, objmask* obj)
+{
+    vtabmask* vtab = NULL;
+    memset(arg, 0, sizeof(etch_objclass));
+    if (NULL == obj) return;
+
+    arg->obj_type = obj->obj_type;
+    arg->class_id = obj->class_id;
+    arg->parent   = obj->parent;
+
+    if (vtab = (vtabmask*) obj->vtab)
+    {   arg->vtable_class_id = vtab->class_id;
+        arg->inherits_from   = vtab->inherits_from;
+    }   
+
+    switch(obj->obj_type)
+    { case ETCHTYPEB_NATIVEARRAY:
+           arg->numdims          = ((etch_nativearray*)obj)->numdims;
+           arg->content_obj_type = ((etch_nativearray*)obj)->content_obj_type;
+           arg->content_class_id = ((etch_nativearray*)obj)->content_class_id;
+           break;
+      case ETCHTYPEB_ARRAYVAL:
+           arg->numdims          = ((etch_collection_mask*)obj)->n;
+           arg->content_obj_type = ((etch_collection_mask*)obj)->content_obj_type;
+           arg->content_class_id = ((etch_collection_mask*)obj)->content_class_id;
+           break;
+      case ETCHTYPEB_ARRAYLIST:
+           arg->numdims          = 1;
+           arg->content_obj_type = ((etch_collection_mask*)obj)->content_obj_type;
+           arg->content_class_id = ((etch_collection_mask*)obj)->content_class_id;
+    }
+}
+
+
+/**
+ * etchobj_is_assignable_from()
+ * determines if the class of thisobj is the same as, or is a superclass of,
+ * the class specified by that_class_id. tests whether the type represented 
+ * by that_obj_type and that_class_id can be converted to the type of thisobj 
+ * via an identity conversion or via a widening reference conversion. 
+ *
+ * @param target the class of left side of the assignment (to). 
+ * during validation, this is the class of object the validator expects
+ * to validate. if target object is an array, this is the array content class.
+
+ * @param source the class of right side of the assignment (from). 
+ * during validation, this is the class of the object being validated.
+ * if target object is an array, this is the array content class.
+ */
+int etchobj_is_assignable_from(etch_objclass* target, etch_objclass* source)  
+{
+    if (source->class_id == target->class_id && source->numdims == 0) 
+        return TRUE;  /* identity case */
+
+    /* if left side is Object wrapper (not Object[]), anything can be assigned 
+     * to it, since the c binding does not receive anything that is unwrapped.
+     * i.e. in java Object.class is not assignable from int.class; however here
+     * we don't have an int.class, only wrapped integers. if this were not the
+     * case this test would come after the etch primitives test, since a class
+     * not derived from object can't be assigned to object.
+     */
+    if (is_etch_object_type(target->obj_type, target->class_id)) return TRUE;
+
+    if (target->obj_type == ETCHTYPEB_PRIMITIVE   
+     || source->obj_type == ETCHTYPEB_PRIMITIVE) return FALSE;  
+
+    /* if left (target) side is an array, and right (source) side is an 
+     * array of the same dimensions, and either of the same content type,    
+     * or an array of Object, then it is assignable.
+     * this code is not robust - need to rethink assignability for default
+     * array validator with various validation object array types.
+     * currently we are validating very loosely for array types. we need
+     * a more general means of validating arrays, i.e. common attributes
+     * among array types (native, value, list)
+     */
+    if (is_etch_objarray_type   (target->obj_type, target->class_id)
+     || is_etch_arraylist_type  (target->obj_type, target->class_id) 
+     || is_etch_nativearray_type(target->obj_type, target->class_id))
+    {   
+        if (target->numdims == source->numdims)
+        {
+           /* this line added to pass anything using default array validator */
+           if (target->content_obj_type == 0 && target->content_class_id == 0)
+               return TRUE;
+
+           if (target->content_class_id == CLASSID_UNWRAPPED)
+               return target->content_obj_type == source->content_obj_type;
+                 
+           if (target->content_class_id == CLASSID_OBJECT 
+            || target->content_class_id == source->content_class_id) 
+               return TRUE; 
+        }
+      
+        return FALSE;   
+    }
+    else /* if source inherits from target, source can be assigned to target */ 
+    if (source->parent)
+    {   /* inheritance model 2 - inherited objects are instantiated and chained */
+        objmask* thisparent = source->parent;   
+
+        while(thisparent) /* walk source object's inheritance chain */
+        {
+            if (thisparent->class_id == target->class_id) return TRUE;
+            thisparent = thisparent->parent;
+        }
+    }
+    else
+    {   int ndx = 0;
+        etchparentinfo* parentinfo;
+        /* inheritance model 1 - inherited data flattened into single object */
+
+        while(1) /* iterate source object's inheritance list */
+        { 
+            if (NULL == (parentinfo = get_next_etch_parentex 
+                   (source->class_id, source->inherits_from, ndx++)))
+                break;
+
+            if (parentinfo->class_id == target->class_id)
+                return TRUE;
+        } 
+    } 
+
+    return FALSE;  
+}
+
+
+/**
+ * etchobj_is_assignable_from_ex()
+ * see comments for etchobj_is_assignable_from()
+ */
+int etchobj_is_assignable_fromobj(objmask* targetobj, objmask* sourceobj)
+{
+    etch_objclass targetarg, sourcearg;  
+    set_etch_assignable_arg_from(&targetarg, targetobj);
+    set_etch_assignable_arg_from(&sourcearg, sourceobj);
+    return etchobj_is_assignable_from(&targetarg, &sourcearg);
+}
+
+
+/*
+ * etchobj_assign_to() 
+ * assign object b to object a, if legal to do so.
+ * handles assignments of wrapped objects, array objects, and scalar objects. 
+ * @return 0 or -1
+ */
+objmask* etchobj_assign_to(objmask* a, objmask* b)
+{ 
+    objmask* resultobj = a;
+
+    if (is_etch_object(a))
+    {        
+        if  (is_etch_object(b))  
+        {    /* both sides are wrappers so just copy right value to left */
+             destroy_etch_object_value((etch_object*)a);   
+            ((etch_object*)a)->value = ((etch_object*)b)->value;   
+            ((etch_object*)a)->is_value_object = ((etch_object*)b)->is_value_object;
+            ((etch_object*)a)->is_value_owned  = ((etch_object*)b)->is_value_owned;
+        }
+        else /* left side is a wrapper, right side is not a wrapper */
+        {    /* so embed right side value inside left side wrapper */
+             destroy_etch_object_value((etch_object*)a); 
+            ((etch_object*)a)->value = b; /* wrap b inside a */
+            ((etch_object*)a)->is_value_object = TRUE;
+            ((etch_object*)a)->is_value_owned  = FALSE;
+        }
+    }
+    else
+    if (is_etch_object(b))
+    {   /* left side is not a wrapper, right side is a wrapper */
+        /* we do not currently support copying right side wrapped content
+         * to the left side, although technically we could easily do so.
+         */ 
+        resultobj = NULL;
+    }
+    else
+    if (!etchobj_is_assignable_fromobj(a, b)) 
+    {   /* source object is not legally assignable to target */
+        resultobj = NULL;
+    }
+    else  /* neither side is a wrapper, right side is assignable to left */
+    if (is_etch_nativearray(a)) 
+    {     /* both sides are arrays per is_assignable_from(), 
+           * attempt to copy right side array to left */ 
+        resultobj = (objmask*) etch_nativearray_assign_to   
+           ((etch_nativearray*) a, (etch_nativearray*) b);  
+    }  
+    else /* both sides are scalar */
+    if (b->parent != NULL)
+    {    /* inheritance type 2: parent object(s) is/are instantiated 
+          * and chained to the inheritor. with this type of inheritance, 
+          * it is possible that the memory reference we return is not the 
+          * same as the target reference we pass. this is because we can't 
+          * copy source to target to do the assignment, since the child 
+          * object we would want to assign to it may in fact be larger 
+          * than the target object.
+          */
+         objmask* thisparent = b;
+         resultobj = NULL;
+
+         while(thisparent) /* walk the parent chain */
+         {   if (thisparent->class_id == a->class_id)
+             {   resultobj = thisparent;
+                 break;
+             }
+             else thisparent = thisparent->parent;
+         }          
+    }
+    else /* inheritance type 1: parent data are members of child object. */  
+    {    /* since the right side is derived from left, and since we enforce  
+          * a rule that derived objects must append instance data to the end 
+          * of the parent object, we can simply copy memory from the source
+          * to the target, limited to the known shorter length of the target;
+          * and then restore the individual fields which should be retained.
+          * this scheme of course depends on object constructors populating 
+          * obj->length with sizeof(instantiated struct), in all cases. */
+         
+          /* save off items we need to restore post-copy */
+          objmask save, *saved = &save; 
+          memcpy(saved, a, sizeof(objmask));
+
+          /* mark target shell immutable so destructor will not free it */
+          set_etchobj_static_shell(a);
+
+          /* invoke target destructor to free any content owned by target */
+          a->destroy(a);
+
+          /* copy source to target */
+          memcpy(a, b, a->length);
+
+          /* mark target as a copy, its content not owned by it */
+          a->is_copy = TRUE;
+          clear_etchobj_static_shell(a);
+          set_etchobj_static_content(a);     
+
+          /* finally restore the retained target fields */
+          a->obj_type = saved->obj_type;
+          a->class_id = saved->class_id;
+          a->refcount = saved->refcount;  
+          a->result   = saved->result; 
+          a->destroy  = saved->destroy;
+          a->clone    = saved->clone; 
+          a->get_hashkey = saved->get_hashkey;
+          if (is_etchobj_static_shell(saved))
+              set_etchobj_static_shell(a);
+    }
+
+    return resultobj;
+}
+
+
+/**
+ * etch_addref()
+ * increment object's reference count. if previously zero, begins reference
+ * counting of an object. obj.refcount > 0 indicates that the object is 
+ * reference counted. conversely, if obj.refcount is zero, an object is not 
+ * reference counted. if an object is refcounted, then invocation of its 
+ * destructor implies decrementing the refcount, destroying the object only
+ * if the refcount is now zero.
+ */
+unsigned etch_addref(objmask* thisobj)
+{
+    return ++thisobj->refcount;
+}
+
+
+/**
+ * etch_release()
+ * decrement object's reference count and destroy the object if now zero.
+ * returns new reference count. zero indicates the object was destroyed.
+ * use of this method is optional, since invocation of a refcounted object's
+ * destructor does an implicit decrement of the refcount. however it is
+ * included since coding destroy() might be misleading to the reader.
+ */
+unsigned etch_release(objmask* thisobj) 
+{
+    return destroy_object(thisobj) == 0? 0: thisobj->refcount;
+}
+
+
+/**
+ * etch_release_wrapper()
+ * see comments above at etch_release()
+ */
+unsigned etch_release_wrapper(etch_object* thisobj) 
+{
+    return destroy_etch_object(thisobj) == 0? 0: thisobj->refcount;
+}
+
+
+/**
+ * destroy_string()
+ */
+int destroy_string(etch_string* thisp) 
+{
+    if (thisp->refcount > 0 && --thisp->refcount > 0) return -1;
+    if (!is_etchobj_static_content(thisp))
+        etch_free(thisp->v.value);  /* OK if null */
+    destroy_objectex((objmask*)thisp);
+    return 0;
+}
+
+
+/**
+ * default virtual copy constructor for etch object.   
+ */
+objmask* clone_object(objmask* pthis)
+{
+    void* object_value = NULL;
+    void* pnew = NULL; 
+    unsigned objsize = pthis->length;
+    if (objsize < sizeof(objmask)) objsize = sizeof(objmask);
+    
+    pnew = etch_malloc (objsize, pthis->obj_type); 
+    memcpy(pnew, pthis, objsize);  
+
+    return (objmask*) pnew;  
+}
+
+
+/**
+ * default virtual copy constructor for objects requiring deep copy  
+ */
+objmask* clone_null(objmask* pthis)
+{
+    return NULL;
+}
+
+
+/**
+ * clone_string()
+ */
+etch_string* clone_string(etch_string* thisp) 
+{
+    etch_string* newobj = (etch_string*) clone_object((objmask*)thisp);
+    newobj->v.value = thisp->encoding == ETCH_ENCODING_UTF16?
+        (void*) new_wchar(thisp->v.valw): (void*) new_char (thisp->v.valc);
+    return newobj;
+}
+
+
+/**
+ *  new_etchresult()
+ *  generate etchobject result object
+ */
+etchresult* new_etchresult(const int result, const int reason)
+{
+    etchresult* newresult = etch_malloc(sizeof(etchresult), ETCHTYPEB_RESULT);
+    memset(newresult, 0, sizeof(etchresult));
+    newresult->resultcode = result;
+    newresult->reasoncode = reason;
+    return newresult;
+}
+
+ 
+/**
+ * defgethashkey
+ * default hashkey computation for an etch object
+ */
+unsigned defgethashkey(objmask *obj)
+{
+    void* hashitem = obj; /* uses the object address as hash source */
+    if (NULL == hashitem) return 0;
+    return obj->hashkey = etchhash((char*)&hashitem, sizeof(void*), 0);
+}
+
+
+/**
+ *  new_object()
+ *  basic object constructor 
+ *  sets type, class, size, default destructor, and copy constructor. 
+ */
+objmask* new_object(const int objsize, const unsigned short obj_type, const unsigned short class_id)
+{
+    objmask* newobj = etch_malloc(objsize, obj_type);
+    memset(newobj, 0, objsize);
+    newobj->obj_type = obj_type;
+    newobj->class_id = class_id;
+    newobj->length   = objsize;
+    newobj->destroy  = destroy_object; 
+    newobj->clone    = clone_object;
+    newobj->get_hashkey = defgethashkey;
+    newobj->get_hashkey(newobj);  
+    return newobj;
+}
+
+
+/**
+ * clone_etch_object()
+ * clone_etch_object copy constructor
+ */ 
+objmask* clone_etch_object(objmask* thatobj)
+{
+    objmask* newobj = clone_object(thatobj);
+    ((etch_object*) newobj)->is_value_owned = FALSE;
+    newobj->is_copy = TRUE;
+    return newobj;
+}
+
+
+/**
+ *  new_etch_object() 
+ *  wrapper object constructor
+ */
+etch_object* new_etch_object(const unsigned short class_id, objmask* childobj)   
+{
+    etch_object* newobj = (etch_object*) new_object
+        (sizeof(etch_object), ETCHTYPEB_ETCHOBJECT, class_id); 
+
+    newobj->is_value_object = FALSE; /* when TRUE dtor calls destroy() */
+    newobj->is_value_owned  = TRUE;  /* when TRUE dtor frees content */
+    newobj->value   = childobj;
+    newobj->destroy = destroy_etch_object;
+    newobj->clone   = clone_etch_object; 
+   
+    return newobj;  
+}
+
+
+/**
+ * short_type()
+ * return a 16-bit type code of 2 8-bit parts
+ */
+short short_type(unsigned i, unsigned j) 
+{ 
+    return (short) (  ( ((byte)i) << 16 ) | ((byte)j)  );
+} 
+
+
+/**
+ * clear_lastresult()
+ * clear the global lastresult object
+ */
+void clear_lastresult() 
+{ 
+    (lastresobj = &_lastresobj)->result = &lastresult;
+    if (lastresult.exception) destroy_exception(lastresult.exception);
+    memset(&lastresult, 0, sizeof(struct etchresult));
+} 
+
+
+/**
+ * verify_object()
+ * verify that the object passed is of the specified type and class.
+ * zero is a match for either so pass zero to not validate either.
+ */
+int verify_object(objmask* obj, const unsigned short type, const unsigned short id, void** out)
+{
+    if (obj == NULL) return -1;
+    if (type != 0 && obj->obj_type != type) return -1;
+    if (id   != 0 && obj->class_id != id)   return -1;  
+    return 0; 
+}
+
+
+/**
+ * get_base_vtable()
+ * walks a vtable chain returning the final vtab in the chain
+ */
+void* get_base_vtable(objmask* obj) 
+{
+    vtabmask* basevtab = obj->vtab;
+    while (basevtab && basevtab->vtab) basevtab = basevtab->vtab;
+    return basevtab;
+}
+
+
+/**
+ * destroy_vtable()
+ */
+int destroy_vtable(objmask* vtab) 
+{
+    etchparentinfo* inheritlist = ((vtabmask*)vtab)->inherits_from;
+
+    if (inheritlist && !is_etchobj_static_content(vtab))
+        free(inheritlist); /* vtables not tracked */
+
+    if (!is_etchobj_static_shell(vtab))
+        free(vtab); /* vtables not tracked */
+
+    return 0;
+}
+
+
+/**
+ * get_class_cachekey()
+ * get the unique value used for keying the indicated class in a class cache.
+ */
+unsigned get_class_cachekey(unsigned short obj_type, unsigned short class_id)
+{
+    unsigned key = (obj_type << 16) | class_id;
+    return etchhash(&key, 4, 0);
+}
+
+
+/**
+ * get_vtable_cachehkey()
+ * calculates ad returns the *cache* key for specified vtable object
+ * the hashkey on the vtable object is not an object key, it is a class key,
+ * since vtables are cached by class.
+ */
+unsigned get_vtable_cachehkey(unsigned short class_id)
+{
+    return get_class_cachekey(ETCHTYPEB_VTABLE, class_id);
+}
+
+
+ /**
+ * get_vtabobj_hashkey()
+ * sets and gets the *cache* key for specified vtable object
+ * the hashkey on the vtable object is not an object key, it is a class key,
+ * since vtables are cached by class.
+ */
+unsigned get_vtabobj_hashkey(objmask* vtabobj)
+{
+    return vtabobj->hashkey = get_vtable_cachehkey(vtabobj->class_id);
+}
+
+
+/**
+ * new_vtable()
+ * instantiate a new virtual function table of the specified type, 
+ * defaulting all methods to those of specified parent if requested
+ */
+void* new_vtable(const void* parentvtab, const size_t size, const short classid)
+{
+    objmask* newvtab = malloc(size);  /* vtable memory is not tracked */
+
+    if  (parentvtab)
+         memcpy(newvtab, parentvtab, size);
+    else memset(newvtab, 0, size);
+   
+    newvtab->obj_type = ETCHTYPEB_VTABLE;   
+    newvtab->class_id = classid;
+    newvtab->length   = (unsigned) size;
+    newvtab->destroy  = destroy_vtable;
+    newvtab->clone    = clone_object;
+
+    newvtab->get_hashkey = get_vtabobj_hashkey;
+    newvtab->get_hashkey(newvtab);
+
+    return newvtab;
+}
+
+
+/**
+ * get_vtab_inheritance_list()
+ * add an inheritance list to the specified object, or fetch existing list.
+ * an inheritance list exists in the vtable since we don't need to duplicate it
+ * for every instance. if there is no vtable in the specified object, a place-
+ * holder vtable is instantiated in the object. recall that vtables are freed
+ * when the global cache is cleared. the first entry in an inheritance list 
+ * contains the list attributes, therefore the list is one-based. 
+ * if an appropriately-sized list is already cached, the cached list is 
+ * returned. if a shorter list exists it is resized, copied, and returned. 
+ * @param size total number of entries to be allocated
+ * @param count number of populated entries 
+ */ 
+etchparentinfo* get_vtab_inheritance_list(objmask* obj, 
+   const short size, const short count, const short vtabclass)
+{
+   etchparentinfo *oldlist = NULL, *newlist = NULL;
+
+   /* if such a list is already cached, return it now */
+   vtabmask* vtab = obj->vtab? obj->vtab: cache_find(get_vtable_cachehkey(vtabclass), 0); 
+   oldlist = vtab? vtab->inherits_from: NULL; 
+   
+   if (oldlist && oldlist->list_size >= size)
+   {
+       oldlist[0].list_count = count;
+       obj->vtab = vtab;
+       return oldlist;
+   }
+
+   newlist = new_etch_inheritance_list(size, count, oldlist);
+   if (newlist == NULL) return NULL;
+      
+   /* note that we are creating a placeholder vtable here. we could not add
+    * virtuals to such a vtable, since this vtable consists of the vtable 
+    * header only, per sizeof(vtabmask), following.
+    */
+   if (vtab == NULL) 
+   {   vtab = new_vtable(NULL, sizeof(vtabmask), vtabclass);
+       vtab->inherits_from = newlist;
+       cache_insert(vtab->hashkey, vtab, FALSE);
+       obj->vtab = vtab;
+   }
+       
+   vtab->inherits_from = newlist;
+   return newlist;
+}
+
+
+/**
+ * new_etch_inheritance_list()
+ * allocate and return an inheritance list of the specified size
+ * @param size total number of entries to be allocated
+ * @param count number of populated entries 
+ */ 
+etchparentinfo* new_etch_inheritance_list(const short size, const short count, 
+   etchparentinfo* oldlist)
+{
+   etchparentinfo *newlist = NULL;
+   const int newbytes = size * sizeof(etchparentinfo), MAXPARENTS = 15;
+   if (count < 0 || count > MAXPARENTS || size < 0 || count > size) 
+       return NULL;
+  
+   newlist = malloc(newbytes);  /* vtables not tracked */
+   memset(newlist, 0, newbytes);
+
+   if (oldlist) /* we may be expanding an existing list, copy into new list */
+   {   const int oldbytes = oldlist->list_size * sizeof(etchparentinfo);
+       memcpy(newlist, oldlist, oldbytes);  
+       free(oldlist); /* vtables not tracked */
+       oldlist = NULL;
+   }
+   else newlist[0].list_count = count;
+
+   newlist[0].list_size = size;  /* list attributes are in first entry */     
+   return newlist;
+}
+
+
+/**
+ * is_derives_from_object()
+ * determine if specified object derives from object. 
+ * all objmask-masked objects are etch c objects by definition; however it is
+ * here that we would artificially specify that certain wrapped objects are not
+ * derived from object in the logical etch sense, if such a need arises.
+ */ 
+int is_derives_from_object(objmask* obj)
+{
+    return obj? is_derives_from_object_class(obj->class_id): FALSE;
+}
+
+
+/**
+ * is_derives_from_object_class()
+ * see comments at is_derives_from_object()
+ */ 
+int is_derives_from_object_class(const unsigned short class_id)
+{
+    return TRUE;
+}
+
+
+/**
+ * get_next_etch_parent()
+ * see comments at get_next_etch_parentex() below
+ */ 
+etchparentinfo* get_next_etch_parent(objmask* obj, int current_index)
+{
+    etchparentinfo* inherit_list = obj && obj->vtab? obj->vtab->inherits_from: NULL;
+    return get_next_etch_parentex(obj->class_id, inherit_list, current_index);
+}
+
+
+/**
+ * get_next_etch_parentex()
+ * returns a non-disposable reference to etchparentinfo struct containing the
+ * class of next parent in this object's inheritance hierarchy, relative to the
+ * specified index. if specified object does in fact inherit from other than
+ * object, its inheritance list must have been previously instantiated via
+ * get_vtab_inheritance_list(), above, and populated accordingly, presumably
+ * int the object's constructor. the inheritance list implicitly ends with 
+ * object, if the specified object's class derives from object; however object 
+ * does not explicitly appear in the list and in fact must not be so populated. 
+ * @param obj the etch object for which a parent is requested.
+ * @param current_index the index of the currently requested parent. on the
+ * first call specify zero, on subsequent calls increment current_index.
+ * @return etchparentinfo as described above, or NULL if no more parents.
+ * the returned reference is valid while its containing inheritance list remains
+ * instantiated, which ordinarily is while its associated vtable exists, which
+ * ordinarily is until service teardown.
+ */ 
+etchparentinfo* get_next_etch_parentex
+(const unsigned short class_id, etchparentinfo* inherit_list, int current_index)
+{
+    static etchparentinfo object_parent = { ETCHTYPEB_ETCHOBJECT, CLASSID_OBJECT };
+    etchparentinfo* nextparent  = NULL;
+
+    if  (NULL == inherit_list && current_index > 0);
+    else
+    if ((NULL == inherit_list) || (current_index == inherit_list[0].list_count))    
+         if  (is_derives_from_object_class(class_id))
+              nextparent = &object_parent;
+         else; 
+    else
+    if  (current_index < inherit_list[0].list_count) 
+         nextparent = &inherit_list[++current_index]; /* list is one-based */
+
+    return nextparent;
+}
+
+
+/**
+ * new_primitive()
+ * allocate, initialize and return a primitive object
+ */
+objmask* new_primitive(const unsigned obj_len, const unsigned short class_id) 
+{
+    objmask* newobj  = new_object(obj_len, ETCHTYPEB_PRIMITIVE, class_id);
+    newobj->destroy  = destroy_object;
+    newobj->clone    = clone_object;
+    newobj->get_hashkey = etch_number_get_hashkey;
+    return newobj;
+}
+
+
+/**
+ * new_wchar()
+ * wide character string clone
+ */
+wchar_t* new_wchar(const wchar_t* s)
+{   
+    #pragma warning(disable:4996) /* wcscpy unsafe warning */
+    unsigned bytelen;
+    wchar_t* clone; 
+    if (NULL == s) return NULL;
+    bytelen = (unsigned)(wcslen(s) + 1) * sizeof(wchar_t);
+    clone   = etch_malloc(bytelen, ETCHTYPEB_STRING);
+    wcscpy(clone, s);
+    return clone;
+}
+
+
+/**
+ * new_char()
+ * narrow character string clone
+ */
+char* new_char(const char* s)
+{   
+    char* clone; 
+    if (NULL == s) return NULL;
+    clone = etch_malloc(strlen(s) + 1, ETCHTYPEB_STRING);
+    return strcpy(clone, s);
+}
+
+
+/**
+ * new_byte()
+ */
+etch_byte* new_byte(const signed char v)
+{
+    etch_byte* newobj = (etch_byte*) new_primitive
+        (sizeof(struct etch_byte), CLASSID_PRIMITIVE_BYTE);
+    newobj->value = v;
+    newobj->get_hashkey((objmask*)newobj);
+    return newobj;
+}
+
+
+/**
+ * new_boolean()
+ */ 
+etch_boolean* new_boolean(boolean v) 
+{
+    etch_boolean* newobj = (etch_boolean*) new_primitive
+        (sizeof(struct etch_boolean), CLASSID_PRIMITIVE_BOOL);
+    newobj->value = v? TRUE: FALSE;
+    newobj->get_hashkey((objmask*)newobj);
+    return newobj;
+}
+
+
+/**
+ * new_int8()
+ */ 
+etch_int8* new_int8(signed char v) 
+{
+    etch_int8* newobj = (etch_int8*) new_primitive
+        (sizeof(struct etch_int8), CLASSID_PRIMITIVE_INT8);
+    newobj->value = v;
+    newobj->get_hashkey((objmask*)newobj);
+    return newobj;
+}
+
+
+/**
+ * new_int16()
+ */  
+etch_int16* new_int16(short v) 
+{
+    etch_int16* newobj = (etch_int16*) new_primitive
+        (sizeof(struct etch_int16), CLASSID_PRIMITIVE_INT16);
+    newobj->value = v;
+    newobj->get_hashkey((objmask*)newobj);
+    return newobj;
+}
+
+
+/**
+ * new_int32()
+ */
+etch_int32* new_int32(int v) 
+{
+    etch_int32* newobj = (etch_int32*) new_primitive
+            (sizeof(struct etch_int32), CLASSID_PRIMITIVE_INT32);
+    newobj->value = v;
+    newobj->get_hashkey((objmask*)newobj);
+    return newobj;
+}
+
+ 
+/**
+ * new_int64()
+ */
+etch_int64* new_int64(int64 v) 
+{
+    etch_int64* newobj = (etch_int64*) new_primitive
+            (sizeof(struct etch_int64), CLASSID_PRIMITIVE_INT64);
+    newobj->value = v;
+    newobj->get_hashkey((objmask*)newobj);
+    return newobj;
+}
+
+
+/**
+ * new_float()
+ */ 
+etch_float* new_float(float v) 
+{
+    etch_float* newobj = (etch_float*) new_primitive
+            (sizeof(struct etch_float), CLASSID_PRIMITIVE_FLOAT);
+    newobj->value = v;
+    newobj->get_hashkey((objmask*)newobj);
+    return newobj;
+}
+
+
+/**
+ * new_double()
+ */  
+etch_double* new_double(double v) 
+{
+    etch_double* newobj = (etch_double*) new_primitive
+            (sizeof(struct etch_double), CLASSID_PRIMITIVE_DOUBLE);
+    newobj->value = v;
+    newobj->get_hashkey((objmask*)newobj);
+    return newobj;
+}
+
+
+/**
+ * etch_string_get_hashkey
+ * hashkey computation override for an etch_string.
+ * hash key is computed using the raw string as hash source.
+ */
+unsigned etch_string_get_hashkey(objmask* etchobj)
+{
+    etch_string* sobj = (etch_string*) etchobj;
+    sobj->hashkey = ETCH_ENCODING_UTF16 == sobj->encoding?
+          etch_get_wchar_hashkey(sobj->v.valw):
+          etch_get_char_hashkey(sobj->v.valc);     
+    return sobj->hashkey;
+}
+
+
+ /**
+ * etch_string_init()
+ * private constructor for opaque string
+ */ 
+etch_string* etch_string_init(const void* s, const unsigned char encoding)
+{
+    etch_string* newobj = (etch_string*) 
+        new_primitive(sizeof(struct etch_string), CLASSID_STRING);
+
+    switch(encoding)
+    { case ETCH_ENCODING_UTF16:
+      case ETCH_ENCODING_ASCII:
+      case ETCH_ENCODING_UTF8:
+           newobj->encoding = encoding;
+           break;
+      default: newobj->encoding = ETCH_ENCODING_DEFAULT;
+    }
+
+    if (s)
+    {   switch(encoding)
+        { case ETCH_ENCODING_UTF16:
+               newobj->char_count  = (unsigned) wcslen((wchar_t*)s);
+               newobj->byte_count  = (newobj->char_count + 1) * sizeof(wchar_t);
+               break;
+          default:              
+               newobj->char_count  = (unsigned) strlen((char*)s);
+               newobj->byte_count  = (newobj->char_count + 1) * sizeof(char);
+        }
+    }
+    else newobj->is_null = TRUE;
+
+    newobj->destroy = destroy_string;
+    newobj->clone   = clone_string;
+
+    return newobj;
+}
+
+
+/**
+ * new_string()
+ * clones supplied string
+ * @param s a raw string to be assigned to the new string object.
+ * caller retains ownership of s.
+ */ 
+etch_string* new_string(const void* s, const unsigned char encoding) 
+{
+    etch_string* newobj = etch_string_init(s, encoding); 
+       
+    if (s)
+    {   switch(encoding)
+        { case ETCH_ENCODING_UTF16:             
+               newobj->v.valw = etch_malloc(newobj->byte_count, ETCHTYPEB_STRING);
+               wcscpy(newobj->v.valw, (wchar_t*)s); 
+               break;
+          default:                          
+              newobj->v.valc = etch_malloc(newobj->byte_count, ETCHTYPEB_STRING);
+              strcpy(newobj->v.valc, (char*)s); 
+        }
+    }
+
+    newobj->get_hashkey = etch_string_get_hashkey;
+    newobj->get_hashkey((objmask*)newobj);
+
+    return newobj;
+}
+
+
+/**
+ * new_stringw()
+ * convenience constructor for string type ETCH_ENCODING_UTF16;
+ * @param s a raw string to be assigned to the new string object.
+ * caller retains ownership of s.
+ */ 
+etch_string* new_stringw(const void* s) 
+{
+    return new_string(s, ETCH_ENCODING_UTF16);
+}
+ 
+
+/**
+ * new_stringa()
+ * convenience constructor for string type ETCH_ENCODING_UTF8);
+ * @param s a raw string to be assigned to the new string object.
+ * caller retains ownership of s.
+ */ 
+etch_string* new_stringa(const void* s) 
+{
+    return new_string(s, ETCH_ENCODING_UTF8);
+}
+
+
+/**
+ * new_string_from()
+ * does not clone supplied string
+ * @param s a disposable raw string to be assigned to the new string object.
+ * caller relinquishes ownership of s.
+ */ 
+etch_string* new_string_from(const void* s, const unsigned char encoding) 
+{
+    etch_string* newobj = etch_string_init(s, encoding); 
+    newobj->v.value = (void*) s;
+    return newobj;
+}
+
+
+/**
+ * new_etch_event()
+ */ 
+etch_event* new_etch_event(const unsigned short class_id, const int value) 
+{
+    etch_event* newobj = (etch_event*) new_int32(value);
+    if (class_id) newobj->class_id = class_id; 
+    return newobj;
+}
+
+
+/**
+ * new_etch_query()
+ */ 
+etch_query* new_etch_query(const unsigned short class_id, const int value) 
+{
+    etch_query* newobj = (etch_query*) new_int32(value);
+    if (class_id) newobj->class_id = class_id; 
+    return newobj;
+}
+
+
+/**
+ * new_etch_control()
+ */ 
+etch_control* new_etch_control(const unsigned short class_id, const int value) 
+{
+    etch_control* newobj = (etch_control*) new_int32(value);
+    if (class_id) newobj->class_id = class_id; 
+    return newobj;
+}
+
+
+/**
+ * new_date()
+ */ 
+etch_date* new_date() 
+{
+    etch_date* newobj = (etch_date*) 
+        new_primitive(sizeof(struct etch_date), CLASSID_DATE);
+
+    time (&newobj->value);  
+    newobj->ticks = clock();
+ 
+    return newobj;
+}
+
+
+/**
+ * new_who()
+ * a who is an etch_object wrapper around some etch object type, its purpose
+ * to be a disposable object which opaquely specifies the object which is the 
+ * sender or receiver component of a method. 
+ * @param whoobj the object which is the actual source or destination.
+ * if this object is a nondisposable refrerence, of course it must be assured
+ * that the object is not destroyed prior to destruction of the etch_who
+ * which references it. 
+ * @param is_owned if TRUE the etch_who destructor will destroy the whoobj.
+ */ 
+etch_who* new_who(void* whoobj, const int is_owned)
+{
+    etch_who* newobj = (etch_who*) new_etch_object(CLASSID_WHO, whoobj);
+    newobj->is_value_object = TRUE;
+    newobj->is_value_owned  = is_owned != FALSE;
+    return newobj;
+}
+
+
+/**
+ * new_nullobj()
+ * instantiate and return a logically null object
+ */
+objmask* new_nullobj()
+{
+   objmask* obj = (objmask*) new_etch_object(CLASSID_NONE, NULL);
+   obj->is_null = TRUE;
+   return obj;
+}
+
+
+/**
+ * etch_get_char_hashkey
+ * hashkey computation using a narrow string as source
+ */
+unsigned etch_get_char_hashkey(const char* s)
+{
+    unsigned keybytelen = 0, hashkey = 0;
+    if (NULL != s) 
+        keybytelen = (unsigned) strlen(s);
+    if (keybytelen) 
+        hashkey = etchhash(s, keybytelen, 0);
+    return hashkey;
+}
+
+
+/**
+ * etch_get_wchar_hashkey
+ * hashkey computation using a unicode string as source
+ */
+unsigned etch_get_wchar_hashkey(const wchar_t* s)
+{
+    unsigned keybytelen = 0, hashkey = 0;
+    if (NULL != s) 
+        keybytelen = (unsigned) (wcslen(s) * sizeof(wchar_t));
+    if (keybytelen) 
+        hashkey = etchhash(s, keybytelen, 0);
+    return hashkey;
+}
+
+ 
+/**
+ * etch_number_get_hashkey
+ * hashkey computation override for an etch wrapped primitive number.
+ * hash key is computed using the numeric value as hash source.
+ */
+unsigned etch_number_get_hashkey(objmask* etchobj)
+{
+    unsigned bytelength, hashkey;
+
+    switch(etchobj->class_id)
+    {   case CLASSID_PRIMITIVE_INT32: case CLASSID_PRIMITIVE_FLOAT:  bytelength = 4; break;
+        case CLASSID_PRIMITIVE_INT64: case CLASSID_PRIMITIVE_DOUBLE: case CLASSID_DATE: bytelength = 8; break;
+        case CLASSID_PRIMITIVE_INT16: bytelength = 2; break;
+        default: bytelength = 1;     
+    } 
+    
+    hashkey = etchhash(&((etch_int64*)etchobj)->value, bytelength, 0);
+    return etchobj->hashkey = hashkey;
+}

Added: incubator/etch/trunk/binding-c/runtime/c/src/common/etchrun.c
URL: http://svn.apache.org/viewvc/incubator/etch/trunk/binding-c/runtime/c/src/common/etchrun.c?rev=767594&view=auto
==============================================================================
--- incubator/etch/trunk/binding-c/runtime/c/src/common/etchrun.c (added)
+++ incubator/etch/trunk/binding-c/runtime/c/src/common/etchrun.c Wed Apr 22 17:25:43 2009
@@ -0,0 +1,592 @@
+/* $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. 
+ */ 
+
+/**
+ * etchrun.c -- runtime data management.
+ * the runtime cache database is where we cache object vtables etc.
+ */
+
+#include <stdio.h>
+#include "etch_global.h"
+
+#define ETCH_CACHE_USES_ALPHA_KEY
+#define CACHE_DEBUG FALSE
+
+/*
+ * ETCH_CACHE_USES_ALPHA_KEY switches on alpha cache keys rather than the normal
+ * 4-byte integer. experiencing a problem with either the hfirst or hnext 
+ * hashtable functionality, this was an attempt to determine if the 4-byte keys
+ * were causing the problem. it appears not, so we can probably use int keys again.
+ */
+#ifdef ETCH_CACHE_USES_ALPHA_KEY
+
+#define ETCHCACHEKEYBUFLEN 20
+char ckey[ETCHCACHEKEYBUFLEN];
+
+
+/*
+ * make_cache_key() 
+ * given 32-bit key constructs alpha key for the cache returning key byte length
+ */
+int make_cache_key(const unsigned int ikey)
+{
+   char* pkey = ckey;
+   /* memcpy(pkey+=4,"ca$h",4); */
+   _itoa_s(ikey, pkey, ETCHCACHEKEYBUFLEN, 10);
+   return (int)strlen(ckey);
+}
+
+
+/*
+ * cache_populate_out() 
+ * populate caller's out struct
+ */
+void cache_populate_out(etch_hashitem* useritem, etch_hashitem* curritem)
+{
+    useritem->key   = curritem->key;
+    useritem->value = curritem->value;
+    useritem->hash  = curritem->hash;
+}
+
+
+/*
+ * cache_findxl() 
+ */
+void* cache_findxl(char* key, unsigned keylen, void** out)
+{
+    etch_hashitem  hashbucket;
+    etch_hashitem* founditem = &hashbucket;
+
+    int result = jenkins_find
+       (global_cache->realtable, key, keylen, 0, &founditem);
+
+    #if CACHE_DEBUG
+    #pragma warning(disable:4313) 
+    if  (result == 0) 
+         printf("cache_found key %s len %d addr %08x\n", 
+                 key, keylen, founditem->value);
+    else printf("cache_notfound key %s len %d\n", key, keylen);
+    #endif 
+  
+    if (result == -1) return NULL;
+
+    if (out)
+        cache_populate_out(*out, founditem);        
+
+    return founditem->value;
+}
+
+
+/*
+ * cache_find() 
+ * locate cached object with specified key, returning it or NULL
+ */
+void* cache_find(const unsigned int objtype, void** out)
+{
+    unsigned keylen = make_cache_key(objtype);
+
+    return cache_findxl(ckey, keylen, out);
+}
+
+
+/*
+ * cache_findx() 
+ * locate cached object with specified ansi char key, returning it or NULL
+ */
+void* cache_findx(char* key, void** out)
+{
+    unsigned keylen = (unsigned)strlen(key);
+
+    return cache_findxl(key, keylen, out);
+}
+
+
+/*
+ * cache_find_by_hash() 
+ * locate cached object with specified hashkey, returning it or NULL
+ */
+void* cache_find_by_hash(const unsigned hash, void** out)
+{
+    int result;
+    etch_hashitem  hashbucket;
+    etch_hashitem* founditem = &hashbucket;
+
+    result = jenkins_findh(global_cache->realtable, hash, 0, &founditem);
+
+    if (result == -1) return NULL;
+
+    if (out)
+        cache_populate_out(*out, founditem);       
+    
+    return founditem->value;
+}
+
+
+/*
+ * cache_current() 
+ * return cached object at current position
+ */
+etch_hashitem* cache_current()
+{
+    int result;
+    etch_hashitem  hashbucket;
+    etch_hashitem* founditem = &hashbucket;
+
+    result = jenkins_current(global_cache->realtable, 0, &founditem);
+
+    return (result == -1)? NULL: founditem;
+}
+
+
+/*
+ * cache_delxl() 
+ * Remove specified object from cache given ansi char key and length.
+ * Return pointer to cached object, which is not freed here.
+ */
+void* cache_delxl (char* key, const unsigned keylen)
+{
+    etch_hashitem hashbucket;
+    etch_hashitem* founditem = &hashbucket;
+
+    int result = jenkins_remove
+       (global_cache->realtable, ckey, keylen, 0, &founditem);
+
+    if (result == -1) return NULL;
+    free(founditem->key); /* free 4-byte key allocated in cache_add() */
+    return founditem->value;
+}
+
+
+/*
+ * cache_del() 
+ * Remove specified object from cache given integer key.
+ * Return pointer to cached object, which is not freed here.
+ */
+void* cache_del (const unsigned int objtype)
+{
+    unsigned keylen = make_cache_key(objtype);
+
+    return cache_delxl(ckey, keylen);
+}
+
+
+/*
+ * cache_delx() 
+ * Remove specified object from cache given ansi char key.
+ * Return pointer to cached object, which is not freed here.
+ */
+void* cache_delx (char* key)
+{
+    unsigned keylen = (unsigned)strlen(key);
+
+    return cache_delxl(key, keylen);
+}
+
+
+/*
+ * cache_insertxl() 
+ * Add specified object to cache given ansi char key and char length, 
+ * with existence test optional.
+ * Return hash of supplied key, or zero.
+ */
+int cache_insertxl (char* key, const unsigned keylen, void* data, const int is_check)
+{
+    int   result = 0, keylent = 0;
+    char* pkey = NULL;
+    void* pval = NULL;
+    etch_hashitem  hashbucket; 
+    etch_hashitem* inserteditem = &hashbucket;
+    memset(&hashbucket, 0, sizeof(etch_hashitem));
+
+    if (is_check)
+    {   pval = cache_findxl(key, keylen, &inserteditem);
+        if (pval) return inserteditem->hash; /* entry exists */
+    }
+
+    keylent = keylen + 1;/* add new entry */
+    pkey    = malloc(keylent); 
+    strcpy_s(pkey, keylent, key);
+
+    #if CACHE_DEBUG
+    #pragma warning(disable:4313) 
+    printf("cache_insertxl key %s len %d addr %08x\n", pkey, keylen, data); 
+    #endif
+
+    result = jenkins_insert
+       (global_cache->realtable, pkey, keylen, data, 0, 0, &inserteditem);
+
+    /* cache_dump(); */
+
+    return inserteditem->hash;
+} 
+
+
+/*
+ * cache_insert() 
+ * Add specified object to cache with existence test optional.
+ * Return inserted item hash, or zero.
+ */
+int cache_insert (const unsigned int key, void* data, const int is_check)
+{
+    int   keylen = 0;
+    void* pval = NULL;
+
+    keylen = make_cache_key(key);
+
+    return cache_insertxl(ckey, keylen, data, is_check);
+} 
+
+
+/*
+ * cache_insertx() 
+ * Add specified object to cache with existence test optional.
+ * Return inserted item hash, or zero.
+ */
+int cache_insertx (char* key, void* data, const int is_check)
+{
+    unsigned keylen = (unsigned)strlen(key);
+    
+    return cache_insertxl(key, keylen, data, is_check);
+} 
+
+
+/*
+ * cache_add() 
+ * Add specified object to cache given integer key.
+ * Return 0 or -1.
+ */
+int cache_add (const unsigned int objtype, void* data)
+{
+    return cache_insert (objtype, data, TRUE);
+} 
+
+
+/*
+ * cache_addx() 
+ * Add specified object to cache.
+ * Return 0 or -1.
+ */
+int cache_addx(char* key, void* data)
+{
+    return cache_insertx(key, data, TRUE);
+} 
+
+
+#else // #ifdef ETCH_CACHE_USES_ALPHA_KEY
+
+
+/*
+ * cache_find() 
+ * locate cached object with specified key, returning it or NULL
+ */
+void* cache_find(const unsigned int objtype)
+{
+    etch_hashitem hashbucket;
+    etch_hashitem* founditem = &hashbucket;
+    int result = jenkins_find
+       (global_cache->realtable, (char*)&objtype, sizeof(int), 0, &founditem);
+    return result == -1? NULL: founditem->value;
+}
+
+
+/*
+ * cache_del() 
+ * Remove specified object from cache.
+ * Return pointer to cached object, which is not freed here.
+ */
+void* cache_del (const unsigned int objtype)
+{
+    etch_hashitem hashbucket;
+    etch_hashitem* founditem = &hashbucket;
+    int result = jenkins_remove
+       (global_cache->realtable, (char*)&objtype, sizeof(int), 0, &founditem);
+    if (result == -1) return NULL;
+    free(founditem->key); /* free 4-byte key allocated in cache_add() */
+    return founditem->value;
+}
+
+
+*
+ * cache_add() 
+ * Add specified object to cache.
+ * Return pointer to item's data entry, which is not freed here.
+ */
+int cache_add (const unsigned int objtype, void* data)
+{
+    int result = 0;
+    char* pkey = 0;
+    void* pval = cache_find(objtype);
+    if (pval) return 0; /* entry exists */
+
+    pkey = malloc(sizeof(int)); /* add new entry */
+    memcpy(pkey, &objtype, sizeof(int));
+
+    result = jenkins_insert
+       (global_cache->realtable, pkey, sizeof(int), data, 0, 0, 0);
+    return result;
+} 
+
+
+#endif // #ifdef ETCH_CACHE_USES_ALPHA_KEY 
+
+
+/*
+ * cache_create() 
+ * create the global cache as an untracked hashtable
+ */
+etch_hashtable* cache_create() 
+{
+    global_cache = new_systemhashtable(INITIAL_CACHE_SIZE_ITEMS);
+    return global_cache; 
+}
+
+
+/*
+ * cache_clear() 
+ * remove all objects from the runtime list, freeing both key memory and
+ * data object memory for each. Returns the count of buckets so cleared.
+ */
+int cache_clear()
+{
+    int result = jenkins_clear(global_cache->realtable, TRUE, TRUE, 0, 0);
+    return result;
+}
+
+
+/*
+ * cache_destroy() 
+ * clear the cache and destroy the cache object
+ */
+int cache_destroy()
+{
+    int result = cache_clear();
+    result = jenkins_destroy(global_cache->realtable, 0, 0);
+    return result;
+}
+
+
+/*
+ * cache_count() 
+ * return number of items in the runtime cache
+ */
+int cache_count()
+{
+    return jenkins_count(global_cache->realtable, 0, 0);
+} 
+
+
+#pragma warning(disable:4311)
+
+/*
+ * cache_dump() 
+ * debug console display of pointers to each entry in the cache  
+ */
+int cache_dump()
+{
+    etch_hashitem  hashbucket;
+    etch_hashitem* myentry = &hashbucket;
+    const int count = jenkins_count(global_cache->realtable, 0, 0);
+    printf("\n%d entries in cache\n",count);
+    if (count == 0) return 0;
+
+    if  (0 == jenkins_first(global_cache->realtable, NULL, &myentry))   
+         printf("%08x: %08x\n", *(unsigned*)myentry->key, (unsigned)myentry->value);
+    else printf("cache.first() failed\n");  
+     
+    while(0 == jenkins_next(global_cache->realtable, NULL, &myentry))          
+          printf("%08x: %08x\n", *(unsigned*)myentry->key, (unsigned)myentry->value);
+  
+    return count;
+}
+ 
+
+/*
+ * - - - - -  old list cache code from here on  - - - - -
+ */
+
+#ifdef ETCH_CACHE_USES_LINKEDLIST
+
+objrec* cache_find(const unsigned int objtype)
+{
+    return objrec_find(objtype);
+}
+
+void* cache_get (const unsigned int objtype)
+{
+    return objrec_get(objtype);
+} 
+
+void* cache_del (const unsigned int objtype)
+{
+    return objrec_del(objtype); 
+}
+
+objrec* cache_add (const unsigned int objtype, void* data)
+{
+    return objrec_add(objtype, data);
+} 
+ 
+int cache_clear()
+{
+    return objtable_clear();
+}
+
+int cache_count()
+{
+    return objtable_count();
+}  
+
+
+/*
+ * objrec_find 
+ * look up an object in the runtable
+ */
+objrec* objrec_find(const unsigned int objtype)   
+{
+    objrec* p = runtable;
+
+    for(; p; p = p->next)     
+        if (p->obj_type == objtype) 
+            break;    
+
+    return p;
+}
+
+
+/*
+ * objrec_get 
+ * look up an object in the runtable, returning its data, or null.
+ */
+void* objrec_get(const unsigned int objtype)   
+{
+    objrec* p = objrec_find(objtype);
+    return  p?  p->obj_impl: NULL;
+}
+
+
+#pragma warning (disable:4311) // todo debug stmts
+
+
+/*
+ * objrec_add 
+ * if obj rec exists, return it, otherwise add a new obj rec and return it.
+ */
+objrec* objrec_add(const unsigned int objtype, void* data)   
+{
+    objrec* p = objrec_find(objtype);
+    if (p) return p;
+
+    /* we do not track allocations for the tracking hashtable      
+     * since the tracking table does of course not yet exist. */
+    p = is_memtable_instance?   
+       malloc(sizeof(objrec)):
+       malloc(sizeof(objrec));  /* we are currently not tracking the cache at all */ 
+       /* malloc(sizeof(objrec), ETCHTYPEA_CACHEREC); */
+
+    p->obj_type = objtype;  p->obj_impl = data;  p->next = NULL;
+
+    if (runtable == NULL) /* first entry? */
+        runtable = runtable_tail = p;
+    else                  /* chain entry */
+    {   assert(runtable_tail);    
+        runtable_tail->next = p;
+        runtable_tail = p; /* added to end - new entry is new tail */
+    }
+
+    /* printf("cache: add %08x\n",(unsigned)p); */
+
+    return p; 
+}
+
+
+/*
+ * objrec_del 
+ * Remove specified object record from list and free its bucket memory.
+ * Return pointer to item's data entry, which is not freed here.
+ */
+void* objrec_del(const unsigned int objtype)   
+{
+    void* data = NULL;
+    objrec* p = runtable, *prior = NULL;
+
+    for(; p; p = p->next)
+    {
+        if (p->obj_type != objtype)
+        {   prior = p;   /* not found yet */
+            continue;
+        }
+
+        if (prior)       /* found: chain around this entry */
+            prior->next = p->next;
+                         /* if last entry, adjust tail ptr */
+        if (runtable_tail == p)
+            runtable_tail = prior;
+                        /* if first entry, adjust head ptr */
+        if (runtable == p)
+            runtable = prior;
+                         /* save off data, free the bucket */
+        data = p->obj_impl;
+        free(p);
+        /* printf("cache: del %08x\n",(unsigned)p); */
+        break;       
+    }     
+        
+  return data;
+}
+
+
+/*
+ * objtable_count 
+ * returns the current count of cache buckets.
+ */
+int objtable_count()   
+{
+    objrec *p = NULL;
+    int count = 0;
+    for(p = runtable; p; p = p->next, count++);        
+    return count;
+}
+
+
+/*
+ * objtable_clear 
+ * remove all objects from the runtime list, freeing bucket memory and
+ * data memory for each. Returns the count of buckets so cleared.
+ */
+int objtable_clear()   
+{
+    objrec *p = NULL, *nextp = NULL;
+    int count = 0;
+
+    for(p = runtable; p; p = nextp, count++)
+    {   
+        /* note that we must be careful to not clear the cache before we 
+           are done accessing object vtables */
+        free(p->obj_impl);    /* free data memory */
+        nextp = p->next;
+        /* printf("cache: del %08x\n",(unsigned)p); */
+        free(p);              /* free bucket memory */
+    }
+
+  /* printf("cache: %d items cleared\n",count); */
+  runtable = runtable_tail = NULL;           
+  return count;
+}
+
+#endif // #ifdef ETCH_CACHE_USES_LINKEDLIST
+

Added: incubator/etch/trunk/binding-c/runtime/c/src/common/etchutl.c
URL: http://svn.apache.org/viewvc/incubator/etch/trunk/binding-c/runtime/c/src/common/etchutl.c?rev=767594&view=auto
==============================================================================
--- incubator/etch/trunk/binding-c/runtime/c/src/common/etchutl.c (added)
+++ incubator/etch/trunk/binding-c/runtime/c/src/common/etchutl.c Wed Apr 22 17:25:43 2009
@@ -0,0 +1,523 @@
+/* $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. 
+ */ 
+
+/*
+ * etchutl.c -- utility methods
+ */
+
+/* todo include a dummy windows.h for linux build */
+#include <windows.h>
+#include "etchutl.h"
+#include "etch_global.h"
+#include "etch_encoding.h"
+#include <sys/stat.h>
+#include <stdio.h>
+#include <errno.h>
+
+/**
+ * get_map_keys()
+ * return a collection of the specified map's keys.
+ * caller must invoke the destructor on the returned list. the returned list 
+ * is marked as readonly content, in order that arraylist_destroy() will not 
+ * attempt to free memory for the list content, which remains owned by the map.
+ */
+etch_arraylist* get_map_keys(etch_hashtable* map)
+{    
+    etch_iterator iterator; 
+    etch_arraylist* list = NULL;
+
+    const int typecount = map->vtab->count(map->realtable,0,0);
+    list = new_arraylist(typecount, 0);
+    list->content_type = ETCHARRAYLIST_CONTENT_OBJECT;
+    list->is_readonly  = TRUE; /* content is refs to objects owned by map */
+
+    set_iterator(&iterator, map, &map->iterable);
+
+    while(iterator.vtab->has_next(&iterator))
+    {
+        arraylist_add(list, iterator.current_key);
+        iterator.vtab->next(&iterator);
+    }
+
+    return list;
+}
+
+
+/**
+ * get_map_values()
+ * return a collection of the specified map's values.
+ * caller must invoke the destructor on the returned list. the returned list 
+ * is marked as readonly content, in order that arraylist_destroy() will not 
+ * attempt to free memory for the list content, which remains owned by the map.
+ */
+etch_arraylist* get_map_values(etch_hashtable* map)
+{    
+    etch_iterator iterator; 
+    etch_arraylist* list = NULL;
+
+    const int typecount = map->vtab->count(map->realtable,0,0);
+    list = new_arraylist(typecount, 0);
+    list->content_type = map->content_type;
+    list->is_readonly  = TRUE;  /* content is refs to objects owned by map */
+
+    set_iterator(&iterator, map, &map->iterable);
+
+    while(iterator.vtab->has_next(&iterator))
+    {
+        arraylist_add(list, iterator.current_value);
+        iterator.vtab->next(&iterator);
+    }
+
+    return list;
+}
+
+
+/**
+ * hexchar_to_int()
+ */
+int hexchar_to_int (const unsigned char hexchar)
+{
+    switch(hexchar) 
+    {   case '0': return 0;
+        case '1': return 1;
+        case '2': return 2;
+        case '3': return 3;
+        case '4': return 4;
+        case '5': return 5;
+        case '6': return 6;
+        case '7': return 7;
+        case '8': return 8;
+        case '9': return 9;
+        case 'a': case 'A': return 10;
+        case 'b': case 'B': return 11;
+        case 'c': case 'C': return 12;
+        case 'd': case 'D': return 13;
+        case 'e': case 'E': return 14;
+        case 'f': case 'F': return 15;
+    }
+    return -1;
+}
+
+
+/**
+ * hexwchar_to_int()
+ */
+int hexwchar_to_int (const wchar_t hexwchar)
+{
+    switch(hexwchar) 
+    {   case L'0': return 0;
+        case L'1': return 1;
+        case L'2': return 2;
+        case L'3': return 3;
+        case L'4': return 4;
+        case L'5': return 5;
+        case L'6': return 6;
+        case L'7': return 7;
+        case L'8': return 8;
+        case L'9': return 9;
+        case L'a': case L'A': return 10;
+        case L'b': case L'B': return 11;
+        case L'c': case L'C': return 12;
+        case L'd': case L'D': return 13;
+        case L'e': case L'E': return 14;
+        case L'f': case L'F': return 15;
+    }
+    return -1;
+}
+
+
+/**
+ * is_etcharray()
+ */
+#if(0) /* this method is not needed yet so is left out of the compile */
+
+int is_etcharray(objmask* obj, etch_arrayinfo* info)
+{
+    union_alltypes u;
+    if (info) memset(info, 0, sizeof(etch_arrayinfo));
+    if (NULL == obj) return FALSE;
+
+    switch(obj->obj_type)
+    {
+        case ETCHTYPEB_ARRAYLIST:
+        case ETCHTYPEB_ARRAYVALUE: 
+        case ETCHTYPEB_NATIVEARRAY:
+             break;
+        default: return FALSE;
+    }
+
+    if (NULL == info) return TRUE;
+
+    switch(obj->obj_type)
+    {
+        case ETCHTYPEB_ARRAYLIST:
+             u.varraylist = (etch_arraylist*) obj;
+             info->array_type = ETCH_ARRAYTYPE_LIST;
+             info->is_content_object 
+                = u.varraylist->content_type = ETCHARRAYLIST_CONTENT_OBJECT ;
+             info->numdims = 1;
+             info->numitems = u.varraylist->count;
+             break;
+             
+        case ETCHTYPEB_ARRAYVALUE: 
+             u.varrayval = (etch_arrayvalue*) obj;
+             info->array_type = ETCH_ARRAYTYPE_ARRAYVAL;
+             info->is_content_object = TRUE;
+             info->numdims  = u.varrayval->dim;
+             info->numitems = u.varrayval->length;
+             break;
+
+        case ETCHTYPEB_NATIVEARRAY:
+             u.vnatarray = (etch_nativearray*) obj;
+             info->array_type = ETCH_ARRAYTYPE_NATIVE;
+             info->is_content_object = u.vnatarray->content_class_id == CLASSID_NONE;
+             info->numdims  = u.vnatarray->numdims;
+             info->numitems = (int) u.vnatarray->dimension[info->numdims];
+             break;
+    }
+
+    return TRUE;
+}
+
+#endif /* this method is not needed yet so is left out of the compile */
+
+
+/**
+ * etch_existsfile()
+ * determine if specified path exists on the file system.
+ * @return boolean valued indicator.
+ */
+int etch_existsfile (char* path)
+{
+    struct stat fs; 
+    return 0 == stat(path, &fs);
+}
+
+
+/**
+ * etchlog_make_logfilepatha()
+ * build and return a path to specified log file.
+ * @return an etch_malloc'ed path string, caller owns it.
+ */
+char* etchlog_make_logfilepatha (char* dirpath, char* filename)
+{                 
+    const size_t pathlen = strlen(dirpath), namelen = strlen(filename);
+    const size_t pathbuflen = pathlen + namelen + sizeof('/') + sizeof('\0');
+    char* outpath = etch_malloc (pathbuflen, 0), *p = outpath;
+    memcpy (p, dirpath, pathlen);  p += pathlen;
+    *p++ = '/';
+    memcpy (p, filename, namelen); p += namelen;
+    *p = '\0'; 
+    return outpath;  /* caller must etch_free */
+}
+
+
+/**
+ * etchlog_make_logfilepathw()
+ * build and return a path to specified log file.
+ * @return an etch_malloc'ed path string, caller owns it.
+ */
+char* etchlog_make_logfilepathw (char* dirpath, wchar_t* filename)
+{
+    char* aname = NULL, *outpath = NULL;
+    etch_unicode_to_utf8 (&aname, filename);
+    outpath = etchlog_make_logfilepatha (dirpath, aname);
+    etch_free (aname);
+    return outpath;  /* caller must etch_free */
+}
+
+
+/**
+ * etchlog_is_logfilew()
+ * determine if specified path identifies a log file.
+ */
+int is_etch_logfilew (const wchar_t* filepath)
+{
+    int is_logfile = 0, extndx = 0;
+    const wchar_t* ETCHLOG_WIDEEXT = L".log";
+    const size_t extlen = wcslen(ETCHLOG_WIDEEXT);
+    const int wstrlen = (int) wcslen (filepath);
+    if (wstrlen < 1 || wstrlen > MAXPATHSIZE) return FALSE;
+    extndx = (int) wstrlen - (int) extlen;  /* point at .log extension */
+    is_logfile = (0 == wcscmp (&filepath[extndx], ETCHLOG_WIDEEXT));
+    return is_logfile;
+}
+
+
+/**
+ * etchlog_is_logfilea()
+ * determine if specified path identifies a log file.
+ */
+int is_etch_logfilea (const char* filepath)
+{
+    int is_logfile = 0, extndx = 0;
+    const char* ETCHLOG_LOGEXT = ".log";
+    const size_t extlen = strlen(ETCHLOG_LOGEXT);
+    const int astrlen = (int) strlen (filepath);
+    if (astrlen < 1 || astrlen > MAXPATHSIZE) return FALSE;
+    extndx = (int) astrlen - (int) extlen;  /* point at .log extension */
+    is_logfile = (0 == strcmp (&filepath[extndx], ETCHLOG_LOGEXT));
+    return is_logfile;
+}
+
+
+
+/**
+ * etchlog_countfiles()
+ * count log files in specified directory.
+ * @param dirpath narrow directory string, may be relative, can't be root or net.
+ * @return count of files in directory having .log file extension.
+ * @remarks do not invoke this until after etch runtime is initialized, since 
+ * encoding functions use etch_malloc(), which requires the global cache. 
+ * @remarks this uses the linux/unix idiom for enumerating files in a directory.
+ * etch emulations of those routines for windows are provided following.
+ */
+int etchlog_countfiles(char* dirpath)
+{    
+    int logfilecount = 0;
+    DIR* dirstream = NULL;
+    dirent* direntry = NULL;
+    assert(is_runtime_initialized);
+
+    dirstream = opendir(dirpath);
+
+    while(1)
+    {   if (NULL == (direntry = readdir (dirstream))) break;
+        if (is_etch_logfilew (direntry->d_name))
+            logfilecount++;
+    }
+
+    closedir(dirstream);  /* free DIR memory */
+    return logfilecount;
+}
+
+
+/**
+ * etchlog_purgefiles()
+ * purge up tp specified number of log files from specified directory.
+ * @param dirpath narrow directory string, can be relative, can't be root or net.
+ * @param count max number of files to purge.
+ * @param option not currently used.
+ * @return count of files so purged.
+ * @remarks do not invoke this until after etch runtime is initialized, since 
+ * encoding functions use etch_malloc(), which requires the global cache. 
+ * @remarks this uses the linux/unix idiom for enumerating files in a directory.
+ * etch emulations of those routines for windows are provided following.
+ */
+int etchlog_purgefiles (char* dirpath, const int count, const int option)
+{    
+    int purgedcount = 0;
+    DIR* dirstream = NULL;
+    dirent* direntry = NULL;
+    assert(is_runtime_initialized);
+    /* TODO not sure if we will be dealing with narrow or wide paths in
+     * linux dirent - if narrow, we'll need to modify code a bit here. 
+     */
+    dirstream = opendir(dirpath);
+
+    while(purgedcount < count)
+    {  
+        if (NULL == (direntry = readdir (dirstream))) break;
+
+        if (is_etch_logfilew (direntry->d_name)) 
+        {   
+            char* filepath = etchlog_make_logfilepathw (dirpath,  direntry->d_name);
+
+            if (0 == etch_deletefile (filepath)) /* delete this log file */
+                purgedcount++;
+
+            etch_free (filepath);
+        }
+    }
+
+    closedir(dirstream);  /* free DIR memory */
+    return purgedcount;
+}
+
+
+#if IS_WINDOWS_ETCH
+ 
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+ * etch windows emulation of POSIX directory browsing functions
+ * - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+ */
+
+/* turn off potentially unsafe function warnings for strcpy strcat wcscpy etc */
+#pragma warning (disable:4996)  
+
+/*
+ * opendir()
+ * etch win32 limited emulation of POSIX opendir(). 
+ * opens the specified "directory stream". the stream is positioned at the first entry. 
+ * @param dirname the narrow character directory path. assumed not a root or net path.
+ * @return a DIR*, or NULL if error, in which case system errno indicates the specific 
+ * error. caller owns memory referenced by returned address, and is expected to
+ * eventually relinquish this memory p by calling closedir(p).
+ * @remarks closedir() must eventually be called on the returned DIR*, or the DIR will 
+ * leak. it is assumed herein that _UNICODE is #defined ahead of windows.h, such that 
+ * windows' FindFirstFile and FindNextFile operate on and return wide character strings.
+ */
+DIR* opendir (char* dirname)
+{
+    DIR* dir = NULL;
+    int myerrno = 0;
+    wchar_t* wdirname = NULL;
+    const char* SLASHASTER = "/*";
+    char *dircopy = NULL, *p = NULL;
+    size_t namelen = dirname? strlen(dirname): 0;
+    size_t dircopylen = 0, widestrbytelen = 0, dirstructlen = 0;
+    struct stat st; memset(&st, 0, sizeof(struct stat));
+
+    do {
+
+    if (0 == namelen)
+    {   myerrno = EINVAL;
+        break;
+    }
+
+    /* clone caller's directory string */
+    dircopylen = namelen + strlen(SLASHASTER) + sizeof('\0'); 
+    dircopy = etch_malloc(dircopylen, 0);  
+    memset(dircopy, 0, dircopylen);
+    memcpy(dircopy, dirname, namelen);
+
+    /* lose trailing slash if present */
+    p = dircopy + namelen - 1;
+    if (*p == '/' || *p == '\\') 
+    {   *p = '/0';
+        namelen--;
+    } 
+
+    /* verify specified directory exists */
+    if (0 != stat (dircopy, &st) || 0 == (st.st_mode & S_IFDIR))
+    {   myerrno = ENOTDIR;
+        break;
+    }
+
+    /* add slash-asterisk expected by FindFirstFile() */
+    strcat(dircopy, SLASHASTER);
+
+    /* get an etch_malloc'ed unicode version of new path string 
+     * since we're assuming _UNICODE was defined to windows.h */
+    if (0 != etch_ansi_to_unicode (&wdirname, dircopy))
+    {   myerrno = EIO;
+        break;
+    }
+
+    /* allocate DIR big enough to contain unicode directory string */
+    widestrbytelen = etch_get_unicode_bytecount (wdirname);
+    dirstructlen = sizeof(DIR) + widestrbytelen;
+    dir = etch_malloc (dirstructlen, 0);
+    memset(dir, 0, dirstructlen);
+    dir->dirhandle = INVALID_HANDLE_VALUE; /* first file indicator */
+    wcscpy(dir->dirname, wdirname);
+
+    } while(0);
+
+    /* free work memory, fyi OK if null */
+    etch_free(dircopy);
+    etch_free(wdirname);
+    errno = myerrno;
+
+    return dir;  /* caller owns dir and must closedir() to free it */
+}
+
+
+/*
+ * readdir()
+ * etch win32 emulation of POSIX readdir().
+ * gets the next file from the specified directory stream.
+ * this implementation is not reentrant. caller does not own the memory 
+ * referenced by the returned address.
+ * @param dir the "directory stream" created by opendir(). caller retains.
+ * @return a pointer to a structure representing the directory entry at the current 
+ * position in the specified directory stream, and position the directory stream 
+ * at the next entry; or NULL if no more entries in the directory stream. 
+ * caller does not own this memory, function is not reentrant.
+ * @remarks regarding type of entity referenced by returned dirent->d_name, 
+ * at this writing we will only return files, not directories, since that is our
+ * current need. not completely sure how this works in linux, presumably d_name
+ * can be a file or a directory, and caller parses the name? not sure atm, but 
+ * since we're writing this to scan the log directory and we have no need to 
+ * recurse subdirectories, we can omit code to handle subdirectories for now. 
+ */
+dirent* readdir (DIR* dir)
+{
+    static WIN32_FIND_DATA fd;
+    int is_gotfile = FALSE, myerrno = dir? 0: EBADF;
+
+    while(!myerrno && !is_gotfile)
+    {    
+        if (dir->dirhandle == INVALID_HANDLE_VALUE) /* requesting first file in stream? */
+            if (INVALID_HANDLE_VALUE != (dir->dirhandle = FindFirstFile(dir->dirname, &fd)))
+                is_gotfile = TRUE;
+            else;
+        else
+        if (FindNextFile (dir->dirhandle, &fd))
+            is_gotfile = TRUE;
+
+        if (is_gotfile)   /* no doubt there are more attributes we should test for here */
+            if (fd.dwFileAttributes & (FILE_ATTRIBUTE_DIRECTORY | FILE_ATTRIBUTE_HIDDEN)) 
+                is_gotfile = FALSE;
+            else;
+        else switch(GetLastError())
+        {   case ERROR_NO_MORE_FILES: case ERROR_FILE_NOT_FOUND: case ERROR_PATH_NOT_FOUND:
+                 myerrno = ENOENT;
+                 break;
+            default: myerrno = EINVAL;
+        }
+    } 
+
+    errno = myerrno;
+    return myerrno? NULL: (dirent*) &fd.cFileName;
+} 
+
+
+/*
+ * closedir()
+ * etch win32 emulation of POSIX function closedir().
+ * @param dir the "directory stream" allocated by opendir(). this memory is freed here.
+ * @return 0.
+ * &remarks caller relinquishes memory referenced by dir parameter.
+ */
+int closedir (DIR* dir)
+{
+    if (dir && dir->dirhandle != INVALID_HANDLE_VALUE)
+        FindClose (dir->dirhandle);
+
+    etch_free (dir);
+    return 0;
+} 
+
+
+/*
+ * rewinddir()
+ * etch win32 emulation of POSIX function rewinddir().
+ * @param dir the "directory stream" allocated by opendir(). caller retains.
+ * this "directory stream" is reset to the beginning, i.e. prior to first file.
+ */
+void rewinddir (DIR *dir)
+{
+    if (NULL == dir) return;
+    if (dir->dirhandle && dir->dirhandle != INVALID_HANDLE_VALUE)
+        FindClose(dir->dirhandle);
+    dir->dirhandle = INVALID_HANDLE_VALUE;
+} 
+
+
+#endif /* IS_WINDOWS_ETCH */

Added: incubator/etch/trunk/binding-c/runtime/c/src/support/etch_mailboxint.c
URL: http://svn.apache.org/viewvc/incubator/etch/trunk/binding-c/runtime/c/src/support/etch_mailboxint.c?rev=767594&view=auto
==============================================================================
--- incubator/etch/trunk/binding-c/runtime/c/src/support/etch_mailboxint.c (added)
+++ incubator/etch/trunk/binding-c/runtime/c/src/support/etch_mailboxint.c Wed Apr 22 17:25:43 2009
@@ -0,0 +1,254 @@
+/* $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_mailboxint.c
+ * mailbox interface
+ */
+
+#include "apr_time.h" /* some apr must be included first */
+#include "etch_mailboxint.h"
+#include "etch_plainmailbox.h"
+#include "etch_global.h"
+
+int etchmbi_def_message(void* thisx, etch_who* whofrom, etch_message* msg);
+int etchmbi_def_read   (void* thisx, etch_mailbox_element** out);
+int etchmbi_def_read_withwait (void* thisx, const int maxdelay, etch_mailbox_element** out);
+int etchmbi_def_close_delivery (void* thisx);
+int etchmbi_def_close_read (void* thisx);
+int etchmbi_def_register_notify (void* thisx, etch_mailbox_notify, void* state, const int maxdelay);
+int etchmbi_def_unregister_notify (void* thisx, etch_mailbox_notify);
+int etchmbi_def_is_empty  (void* thisx);
+int etchmbi_def_is_closed (void* thisx);
+int etchmbi_def_is_full   (void* thisx);
+int64 etchmbi_def_get_message_id (void* thisx);
+int destroy_mailbox_interface (i_mailbox*);
+
+
+/**
+ * new_default_mailbox_interface
+ * return a mailbox interface populated with defaults for virtuals.
+ */
+i_mailbox* new_default_mailbox_interface(void* thisx)
+{
+    i_mailbox* newi = (i_mailbox*) etch_malloc(sizeof(i_mailbox), ETCHTYPEB_RAWOBJECT); 
+
+    newi->thisx = thisx;
+    newi->destroy = destroy_mailbox_interface;
+    newi->mailbox = etchmbox_get_implobj;
+    newi->manager = etchmbox_get_manager;
+
+    newi->message           = etchmbi_def_message;
+    newi->read              = etchmbi_def_read;
+    newi->read_withwait     = etchmbi_def_read_withwait;
+    newi->close_delivery    = etchmbi_def_close_delivery;
+    newi->close_read        = etchmbi_def_close_read;
+    newi->register_notify   = etchmbi_def_register_notify;
+    newi->unregister_notify = etchmbi_def_unregister_notify;
+    newi->is_empty          = etchmbi_def_is_empty;
+    newi->is_closed         = etchmbi_def_is_closed;
+    newi->is_full           = etchmbi_def_is_full;
+    newi->get_message_id    = etchmbi_def_get_message_id;
+
+    return newi;    
+}
+
+
+/**
+ * new_mailbox_interface
+ * return a mailbox interface populated with specified virtuals.
+ */
+i_mailbox* new_mailbox_interface(void* thisx,
+    etch_mailbox_message mbm,
+    etch_mailbox_read    mbr,
+    etch_mailbox_read_withwait     mbrd,
+    etch_mailbox_close_delivery    mbcd,
+    etch_mailbox_close_read        mbcr,
+    etch_mailbox_register_notify   mbrn,
+    etch_mailbox_unregister_notify mbun,
+    etch_mailbox_is_empty  mbise,
+    etch_mailbox_is_closed mbisc,
+    etch_mailbox_is_full   mbisf,
+    etch_mailbox_get_message_id    mbgmi) 
+{
+    i_mailbox* newi = (i_mailbox*) new_object
+       (sizeof(i_mailbox), ETCHTYPEB_MAILBOXINT, CLASSID_MAILBOXINT);
+
+    newi->thisx = thisx;
+    newi->destroy = destroy_mailbox_interface;
+    newi->mailbox = etchmbox_get_implobj;
+    newi->manager = etchmbox_get_manager;
+
+    newi->message           = mbm?   mbm:   etchmbi_def_message;
+    newi->read              = mbr?   mbr:   etchmbi_def_read;
+    newi->read_withwait     = mbrd?  mbrd:  etchmbi_def_read_withwait;
+    newi->close_delivery    = mbcd?  mbcd:  etchmbi_def_close_delivery;
+    newi->close_read        = mbcr?  mbcr:  etchmbi_def_close_read;
+    newi->register_notify   = mbrn?  mbrn:  etchmbi_def_register_notify;
+    newi->unregister_notify = mbun?  mbun:  etchmbi_def_unregister_notify;
+    newi->is_empty          = mbise? mbise: etchmbi_def_is_empty;
+    newi->is_closed         = mbisc? mbisc: etchmbi_def_is_closed;
+    newi->is_full           = mbisf? mbisf: etchmbi_def_is_full;
+    newi->get_message_id    = mbgmi? mbgmi: etchmbi_def_get_message_id;
+
+    return newi;    
+}
+
+
+/**
+ * destroy_mailbox_interface()
+ * i_mailbox destructor
+ */
+int destroy_mailbox_interface (i_mailbox* mb)
+{
+    int result = 0;
+    if (mb && !is_etchobj_static_content(mb))
+    {
+        ETCHOBJ_DESTROY(((objmask*) mb->thisx));
+    }
+    else result = -1;
+    return result;
+}  
+
+
+/**
+ * etch_mailbox_get_implobj()
+ * verify and return the concrete mailbox implementation
+ */
+etch_mailbox* etchmbox_get_implobj(i_mailbox* imb) 
+{
+    etch_mailbox* mbox = imb? imb->thisx: NULL;
+    return is_etch_mailbox(mbox)? mbox: NULL;
+}
+
+
+/**
+ * etch_mailbox_get_manager()
+ * verify and return the mailbox's mailbox manager
+ */
+i_mailbox_manager* etchmbox_get_manager(i_mailbox* imb)
+{
+    etch_mailbox* mbox = imb? imb->thisx: NULL;
+    i_mailbox_manager* mgr = mbox? mbox->manager: NULL;
+    return is_etch_mailboxmgr(mgr)? mgr: NULL;
+} 
+
+
+int etchmbi_def_message(void* thisx, etch_who* whofrom, etch_message* msg)
+{
+    return -1;
+}
+
+
+int etchmbi_def_read   (void* thisx, etch_mailbox_element** out)
+{
+    return -1;
+}
+
+
+int etchmbi_def_read_withwait (void* thisx, const int maxdelay, etch_mailbox_element** out)
+{
+    return -1;
+}
+
+
+int etchmbi_def_close_delivery (void* thisx)
+{
+    return -1;
+}
+
+
+int etchmbi_def_close_read (void* thisx)
+{
+    return -1;
+}
+
+
+int etchmbi_def_register_notify (void* thisx, etch_mailbox_notify fn, void* state, const int maxdelay)
+{
+    return -1;
+}
+
+
+int etchmbi_def_unregister_notify (void* thisx, etch_mailbox_notify fn)
+{
+    return -1;
+}
+
+
+int etchmbi_def_is_empty  (void* thisx) 
+{
+    return FALSE;
+}
+
+
+int etchmbi_def_is_closed (void* thisx)
+{
+    return FALSE;
+}
+
+
+int etchmbi_def_is_full   (void* thisx)
+{
+    return FALSE;
+}
+
+
+int64 etchmbi_def_get_message_id (void* thisx)
+{
+    return 0;
+}
+
+
+/* - - - - - - - - - - - - - - - - 
+ * etch_mailbox_element
+ * - - - - - - - - - - - - - - - -
+ */
+
+/**
+ * destroy_mailbox_element()
+ * etch_mailbox_element destructor
+ */
+int destroy_mailbox_element(etch_mailbox_element* thisx)
+{
+    if (thisx->refcount > 0 && --thisx->refcount > 0) return -1; 
+
+    if (!is_etchobj_static_content(thisx))
+    {
+        ETCHOBJ_DESTROY(thisx->msg);
+    }
+
+   return destroy_objectex((objmask*) thisx);
+}
+
+
+/**
+ * new_mailbox_element()
+ * etch_mailbox_element constructor
+ * @param msg todo document ownership
+ * @param whofrom todo document ownership
+ */
+etch_mailbox_element* new_mailbox_element(etch_message* msg, etch_who* who)
+{
+    etch_mailbox_element* elt = (etch_mailbox_element*) new_object
+        (sizeof(etch_mailbox_element), ETCHTYPEB_MBOX_ELEMENT, CLASSID_MBOX_ELEMENT); 
+    elt->msg     = msg;
+    elt->whofrom = who;
+    elt->destroy = destroy_mailbox_element;
+    return elt;
+}
\ No newline at end of file