core/object.c

Go to the documentation of this file.
00001 
00027 #include <float.h>
00028 #include <math.h>
00029 
00030 #ifdef WIN32
00031 #define isnan _isnan  /* map isnan to appropriate function under Windows */
00032 #endif
00033 
00034 #include "object.h"
00035 #include "convert.h"
00036 #include "output.h"
00037 #include "globals.h"
00038 
00039 /* object list */
00040 static OBJECTNUM next_object_id = 0;
00041 static OBJECTNUM deleted_object_count = 0;
00042 static OBJECT *first_object = NULL;
00043 static OBJECT *last_object = NULL;
00044 static OBJECTNUM object_array_size = 0;
00045 static OBJECT **object_array = NULL;
00046 #define QNAN sqrt(-1) 
00048 /* {name, val, next} */
00049 KEYWORD oflags[] = {
00050     /* "name", value, next */
00051     {"NONE",OF_NONE,oflags+1},
00052     {"HASPLC",OF_HASPLC,oflags+2},
00053     {"LOCKED",OF_LOCKED,oflags+3},
00054     {"RERANKED",OF_RERANK,oflags+4},
00055     {"RECALC",OF_RECALC,NULL},
00056 };
00057 
00058 /* WARNING: untested. -d3p988 30 Jan 08 */
00059 int object_get_oflags(KEYWORD **extflags){
00060     int flag_size = sizeof(oflags);
00061     *extflags = malloc(flag_size);
00062     if(extflags == NULL){
00063         errno = ENOMEM;
00064         return -1;
00065     }
00066     memcpy(*extflags, oflags, flag_size);
00067     return flag_size/sizeof(KEYWORD); /* number of items written */
00068 }
00069 
00070 /* prototypes */
00071 void object_tree_delete(OBJECT *obj, OBJECTNAME name);
00072 
00073 PROPERTY *object_flag_property(void)
00074 {
00075     static PROPERTY flags = {0, "flags", PT_set, 1, PA_PUBLIC, NULL, (void*)-4, NULL, oflags, NULL};
00076     return &flags;
00077 }
00078 
00083 unsigned int object_get_count(void)
00084 {
00085     return next_object_id - deleted_object_count;
00086 }
00087 
00096 PROPERTY *object_get_property(OBJECT *obj, 
00097                               PROPERTYNAME name) 
00098 {
00099     PROPERTY *prop;
00100     if (obj==NULL) return NULL;
00101     for (prop=class_get_first_property(obj->oclass); prop!=NULL && obj->oclass->type==prop->otype; prop=prop->next)
00102     {
00103         if (strcmp(prop->name,name)==0)
00104             return prop;
00105     }
00106     return NULL;
00107 }
00108 
00109 
00110 int object_build_object_array(){
00111     unsigned int tcount = object_get_count();
00112     unsigned int i = 0;
00113     OBJECT *optr = object_get_first();
00114     if(object_array != NULL)
00115         free(object_array);
00116     object_array = malloc(sizeof(OBJECT *) * tcount);
00117     if(object_array == NULL)
00118         return 0;
00119     object_array_size = tcount;
00120     for(i = 0; i < tcount; ++i){
00121         object_array[i] = optr;
00122         optr = optr->next;
00123     }
00124     return object_array_size;
00125 }
00126 
00130 OBJECT *object_find_by_id(OBJECTNUM id) 
00131 {
00132     OBJECT *obj;
00133     if(object_get_count() == object_array_size){
00134         if(id < object_array_size)
00135             return object_array[id];
00136         else
00137             return NULL;
00138     } else {
00139         /* this either fails or sets object_array_size to object_get_count() */
00140         if(object_build_object_array())
00141             return object_find_by_id(id);
00142     }
00143     for (obj=first_object; obj!=NULL; obj=obj->next)
00144     {
00145         if (obj->id==id)
00146             return obj;
00147     }
00148     return NULL;
00149 }
00150 
00151 
00159 char *object_name(OBJECT *obj) 
00160 {
00161     static char32 oname="(invalid)";
00162     convert_from_object(oname,sizeof(oname),&obj,NULL);
00163     return oname;
00164 }
00165 
00171 OBJECT *object_create_single(CLASS *oclass, 
00172                              OBJECTSIZE size) 
00173 {
00174     OBJECT *obj = (OBJECT*)malloc(sizeof(OBJECT)+size);
00175     memset(obj, 0, sizeof(OBJECT)+size);
00176     if (obj==NULL)
00177     {
00178         errno = ENOMEM;
00179         return 0;
00180     }
00181     obj->id = next_object_id++;
00182     obj->size = size;
00183     obj->oclass = oclass;
00184     obj->next = NULL;
00185     obj->name = NULL;
00186     obj->parent = NULL;
00187     obj->rank = 0;
00188     obj->clock = 0;
00189     obj->latitude = QNAN;
00190     obj->longitude = QNAN;
00191     obj->in_svc = TS_ZERO;
00192     obj->out_svc = TS_NEVER;
00193     obj->flags = OF_NONE;
00194     if (first_object==NULL)
00195         first_object = obj;
00196     else
00197         last_object->next = obj;
00198     last_object = obj;
00199     oclass->profiler.numobjs++;
00200     return obj;
00201 }
00202 
00207 OBJECT *object_create_array(CLASS *oclass, 
00208                             OBJECTSIZE size, 
00209                             unsigned int n_objects) 
00210 {
00211     OBJECT *first = NULL;
00212     while (n_objects-->0)
00213     {
00214         OBJECT *obj = object_create_single(oclass,size);
00215         if (obj==NULL)
00216             return NULL;
00217         else if (first==NULL)
00218             first = obj;
00219     }
00220     return first;
00221 }
00222 
00226 OBJECT *object_remove_by_id(OBJECTNUM id){
00227     //output_error("object_remove_by_id not yet supported");
00228     OBJECT *target = object_find_by_id(id);
00229     OBJECT *prev = NULL;
00230     OBJECT *next = NULL;
00231     if(target != NULL){
00232         char name[64]="";
00233         if(first_object == target){
00234             first_object = target->next;
00235         } else {
00236             for(prev = first_object; (prev->next != NULL) && (prev->next != target); prev = prev->next){
00237                 ; /* find the object that points to the item being removed */
00238             }
00239         }
00240         object_tree_delete(target, target->name?target->name:(sprintf(name,"%s:%d",target->oclass->name,target->id),name));
00241         next = target->next;
00242         prev->next = next;
00243         target->oclass->profiler.numobjs--;
00244         free(target);
00245         deleted_object_count++;
00246     }
00247     return next;
00248 }
00249 
00253 void *object_get_addr(OBJECT *obj, 
00254                       char *name) 
00255 {
00256     PROPERTY *prop;
00257     for (prop=obj->oclass->pmap; prop!=NULL && prop->otype==obj->oclass->type; prop=prop->next)
00258     {
00259         if (obj->oclass->type==prop->otype && strcmp(name,prop->name)==0)
00260             return (void*)((char*)obj+sizeof(OBJECT)+(int64)(prop->addr)); /* warning: cast from pointer to integer of different size */
00261     }
00262     errno = ENOENT;
00263     return NULL;
00264 }
00265 
00266 OBJECT *object_get_object(OBJECT *obj, PROPERTY *prop)
00267 {
00268     int64 o=(int64)obj, s=(int64)sizeof(OBJECT), a=(int64)(prop->addr);
00269     int64 i = o+s+a;
00270     if (obj->oclass->type == prop->otype && prop->ptype == PT_object){
00271         return *(OBJECT **)i; /* warning: cast from pointer to integer of different size */
00272     }
00273     errno = ENOENT;
00274     return NULL;
00275 }
00276 
00277 OBJECT *object_get_object_by_name(OBJECT *obj, PROPERTY *prop)
00278 {
00279     if (obj->oclass->type == prop->otype && prop->ptype == PT_object)
00280         return (OBJECT *)((char*)obj+sizeof(OBJECT)+(int64)(prop->addr)); /* warning: cast from pointer to integer of different size */
00281     errno = ENOENT;
00282     return NULL;
00283 }
00284 
00285 /* Get the pointer to the value of a 16-bit integer property. 
00286  * Returns NULL if the property is not found or if the value the right type.
00287  */
00288 int16 *object_get_int16(OBJECT *obj, PROPERTY *prop)
00289 {
00290     if (obj->oclass->type == prop->otype && prop->ptype == PT_int16)
00291         return (int16 *)((char*)obj+sizeof(OBJECT)+(int64)(prop->addr)); /* warning: cast from pointer to integer of different size */
00292     errno = ENOENT;
00293     return NULL;
00294 }
00295 
00296 int16 *object_get_int16_by_name(OBJECT *obj, char *name){
00297     PROPERTY *prop;
00298     for (prop=obj->oclass->pmap; prop!=NULL && prop->otype==obj->oclass->type; prop=prop->next)
00299     {
00300         if (obj->oclass->type==prop->otype && prop->ptype==PT_int16 && strcmp(name,prop->name)==0){
00301             if(prop->access == PA_PRIVATE){
00302                 return NULL;
00303             } else {
00304                 return (int16 *)((char*)obj+sizeof(OBJECT)+(int64)(prop->addr)); /* warning: cast from pointer to integer of different size */
00305             }
00306         }
00307     }
00308     errno = ENOENT;
00309     return NULL;
00310 }
00311 
00312 /* Get the pointer to the value of a 32-bit integer property. 
00313  * Returns NULL if the property is not found or if the value the right type.
00314  */
00315 int32 *object_get_int32(OBJECT *obj, PROPERTY *prop)
00316 {
00317     if (obj->oclass->type == prop->otype && prop->ptype == PT_int32)
00318         return (int32 *)((char*)obj+sizeof(OBJECT)+(int64)(prop->addr)); /* warning: cast from pointer to integer of different size */
00319     errno = ENOENT;
00320     return NULL;
00321 }
00322 
00323 int32 *object_get_int32_by_name(OBJECT *obj, char *name){
00324     PROPERTY *prop;
00325     for (prop=obj->oclass->pmap; prop!=NULL && prop->otype==obj->oclass->type; prop=prop->next)
00326     {
00327         if (obj->oclass->type==prop->otype && prop->ptype==PT_int32 && strcmp(name,prop->name)==0){
00328             if(prop->access == PA_PRIVATE){
00329                 return NULL;
00330             } else {
00331                 return (int32 *)((char*)obj+sizeof(OBJECT)+(int64)(prop->addr)); /* warning: cast from pointer to integer of different size */
00332             }
00333         }
00334     }
00335     errno = ENOENT;
00336     return NULL;
00337 }
00338 
00339 /* Get the pointer to the value of a 64-bit integer property. 
00340  * Returns NULL if the property is not found or if the value the right type.
00341  */
00342 int64 *object_get_int64(OBJECT *obj, PROPERTY *prop)
00343 {
00344     if (obj->oclass->type == prop->otype && prop->ptype == PT_int64)
00345         return (int64 *)((char*)obj+sizeof(OBJECT)+(int64)(prop->addr)); /* warning: cast from pointer to integer of different size */
00346     errno = ENOENT;
00347     return NULL;
00348 }
00349 
00350 int64 *object_get_int64_by_name(OBJECT *obj, char *name){
00351     PROPERTY *prop;
00352     for (prop=obj->oclass->pmap; prop!=NULL && prop->otype==obj->oclass->type; prop=prop->next)
00353     {
00354         if (obj->oclass->type==prop->otype && prop->ptype==PT_int64 && strcmp(name,prop->name)==0){
00355             if(prop->access == PA_PRIVATE){
00356                 return NULL;
00357             } else {
00358                 return (int64 *)((char*)obj+sizeof(OBJECT)+(int64)(prop->addr)); /* warning: cast from pointer to integer of different size */
00359             }
00360         }
00361     }
00362     errno = ENOENT;
00363     return NULL;
00364 }
00365 
00366 /* Get the pointer to the value of a double property. 
00367  * Returns NULL if the property is not found or if the value the right type.
00368  */
00369 double *object_get_double_quick(OBJECT *obj, PROPERTY *prop)
00370 {   /* no checks */
00371     return (double*)((char*)obj+sizeof(OBJECT)+(int64)(prop->addr));
00372 }
00373 double *object_get_double(OBJECT *obj, PROPERTY *prop)
00374 {
00375     if (obj->oclass->type==prop->otype && prop->ptype==PT_double && prop->access != PA_PRIVATE)
00376         return (double*)((char*)obj+sizeof(OBJECT)+(int64)(prop->addr)); /* warning: cast from pointer to integer of different size */
00377     errno = ENOENT;
00378     return NULL;
00379 }
00380 
00381 double *object_get_double_by_name(OBJECT *obj, char *name){
00382     PROPERTY *prop;
00383     for (prop=obj->oclass->pmap; prop!=NULL && prop->otype==obj->oclass->type; prop=prop->next)
00384     {
00385         if (obj->oclass->type==prop->otype && prop->ptype==PT_double && strcmp(name,prop->name)==0){
00386             if(prop->access == PA_PRIVATE){
00387                 return NULL;
00388             } else {
00389                 return (double *)((char*)obj+sizeof(OBJECT)+(int64)(prop->addr)); /* warning: cast from pointer to integer of different size */
00390             }
00391         }
00392     }
00393     errno = ENOENT;
00394     return NULL;
00395 }
00396 
00397 /* Get the pointer to the value of a complex property. 
00398  * Returns NULL if the property is not found or if the value the right type.
00399  */
00400 complex *object_get_complex_quick(OBJECT *obj, PROPERTY *prop)
00401 {   /* no checks */
00402     return (complex*)((char*)obj+sizeof(OBJECT)+(int64)(prop->addr)); /* warning: cast from pointer to integer of different size */
00403 }
00404 complex *object_get_complex(OBJECT *obj, PROPERTY *prop)
00405 {
00406     if (obj->oclass->type==prop->otype && prop->ptype==PT_complex && prop->access != PA_PRIVATE)
00407         return (complex*)((char*)obj+sizeof(OBJECT)+(int64)(prop->addr)); /* warning: cast from pointer to integer of different size */
00408     errno = ENOENT;
00409     return NULL;
00410 }
00411 
00412 complex *object_get_complex_by_name(OBJECT *obj, char *name){
00413     PROPERTY *prop;
00414     for (prop=obj->oclass->pmap; prop!=NULL && prop->otype==obj->oclass->type; prop=prop->next)
00415     {
00416         if (obj->oclass->type==prop->otype && prop->ptype==PT_complex && strcmp(name,prop->name)==0){
00417             if(prop->access == PA_PRIVATE){
00418                 return NULL;
00419             } else {
00420                 return (complex *)((char*)obj+sizeof(OBJECT)+(int64)(prop->addr)); /* warning: cast from pointer to integer of different size */
00421             }
00422         }
00423     }
00424     errno = ENOENT;
00425     return NULL;
00426 }
00427 
00428 char *object_get_string(OBJECT *obj, PROPERTY *prop){
00429     if (obj->oclass->type==prop->otype && prop->ptype >= PT_char8 && prop->ptype <= PT_char1024 && prop->access != PA_PRIVATE)
00430         return (char *)((char*)obj+sizeof(OBJECT)+(int64)(prop->addr)); /* warning: cast from pointer to integer of different size */
00431     errno = ENOENT;
00432     return NULL;
00433 }
00434 
00435 /* Get the pointer to the value of a string property. 
00436  * Returns NULL if the property is not found or if the value the right type.
00437  */
00438 char *object_get_string_by_name(OBJECT *obj, char *name)
00439 {
00440     PROPERTY *prop;
00441     for (prop=obj->oclass->pmap; prop!=NULL && prop->otype==obj->oclass->type; prop=prop->next)
00442     {
00443         if (obj->oclass->type==prop->otype && prop->ptype>=PT_char8 && prop->ptype<=PT_char1024 && strcmp(name,prop->name)==0){
00444             if(prop->access == PA_PRIVATE){
00445                 return NULL;
00446             } else {
00447                 return ((char*)obj+sizeof(OBJECT)+(int64)(prop->addr)); /* warning: cast from pointer to integer of different size */
00448             }
00449         }
00450     }
00451     errno = ENOENT;
00452     return NULL;
00453 }
00454 
00455 /* this function finds the property associated with the addr of an object member */
00456 static PROPERTY *get_property_at_addr(OBJECT *obj, void *addr)
00457 {
00458     static PROPERTY *prop = NULL;
00459     int64 offset = (int)((char*)addr - (char*)(obj+1));
00460 
00461     /* reuse last result if possible */
00462     if (prop!=NULL && obj->oclass->pmap->otype==prop->otype && (int64)(prop->addr)==offset && prop->access != PA_PRIVATE)  /* warning: cast from pointer to integer of different size */
00463         return prop;
00464 
00465     /* scan through properties of this class and stop when no more properties or class changes */
00466     for (prop=obj->oclass->pmap; prop!=NULL; prop=(prop->next->otype==prop->otype?prop->next:NULL))
00467     {
00468         if ((int64)(prop->addr)==offset) /* warning: cast from pointer to integer of different size */
00469             if(prop->access != PA_PRIVATE)
00470                 return prop;
00471             else {
00472                 output_error("trying to get the private property %s in %s", prop->name, obj->oclass->name);
00473                 return 0;
00474             }
00475     }
00476     return NULL;
00477 }
00478 
00482 int object_set_value_by_addr(OBJECT *obj, 
00483                              void *addr, 
00484                              char *value, 
00485                              PROPERTY *prop) 
00486 {
00487     int result=0;
00488     if (prop==NULL && (prop=get_property_at_addr(obj,addr))==NULL) 
00489         return 0;
00490     if(prop->access != PA_PUBLIC){
00491         output_error("trying to set the value of non-public property %s in %s", prop->name, obj->oclass->name);
00492         return 0;
00493     }
00494 
00495     /* set the recalc bit if the property has a recalc trigger */
00496     if (prop->flags&PF_RECALC) obj->flags |= OF_RECALC;
00497 
00498     /* dispatch notifiers */
00499     if (obj->oclass->notify){
00500         if(obj->oclass->notify(obj,NM_PREUPDATE,addr) == 0){
00501             output_error("preupdate notify failure on %s in %s", prop->name, obj->name ? obj->name : "an unnamed object");
00502         }
00503     }
00504     result = class_string_to_property(prop,addr,value);
00505     if (obj->oclass->notify){
00506         if(obj->oclass->notify(obj,NM_POSTUPDATE,addr) == 0){
00507             output_error("postupdate notify failure on %s in %s", prop->name, obj->name ? obj->name : "an unnamed object");
00508         }
00509     }
00510     return result;
00511 }
00512 
00513 static int set_header_value(OBJECT *obj, char *name, char *value)
00514 {
00515     if (strcmp(name,"name")==0)
00516     {
00517         if (obj->name!=NULL)
00518         {
00519             output_error("object %s:d name already set to %s", obj->oclass->name, obj->id, obj->name);
00520             return FAILED;
00521         }
00522         else
00523         {
00524             object_set_name(obj,value);
00525             return SUCCESS;
00526         }
00527     }
00528     else if (strcmp(name,"parent")==0)
00529     {
00530         OBJECT *parent=object_find_name(value);
00531         if (parent==NULL && strcmp(value,"")!=0)
00532         {
00533             output_error("object %s:%d parent %s not found", obj->oclass->name, obj->id, value);
00534             return FAILED;
00535         }
00536         else if (object_set_parent(obj,parent)==FAILED && strcmp(value,"")!=0)
00537         {
00538             output_error("object %s:%d cannot use parent %s", obj->oclass->name, obj->id, value);
00539             return FAILED;
00540         }
00541         else
00542             return SUCCESS;
00543     }
00544     else if (strcmp(name,"rank")==0)
00545     {
00546         if (object_set_rank(obj,atoi(value))<0)
00547         {
00548             output_error("object %s:%d rank '%s' is invalid", obj->oclass->name, obj->id, value);
00549             return FAILED;
00550         }
00551         else
00552             return SUCCESS;
00553     }
00554     else if (strcmp(name,"clock")==0)
00555     {
00556         if ((obj->clock = convert_to_timestamp(value))==TS_INVALID)
00557         {
00558             output_error("object %s:%d clock timestamp '%s' is invalid", obj->oclass->name, obj->id, value);
00559             return FAILED;
00560         }
00561         else
00562             return SUCCESS;
00563     }
00564     else if (strcmp(name,"latitude")==0)
00565     {
00566         if ((obj->latitude = convert_to_latitude(value))==QNAN)
00567         {
00568             output_error("object %s:%d latitude '%s' is invalid", obj->oclass->name, obj->id, value);
00569             return FAILED;
00570         }
00571         else 
00572             return SUCCESS;
00573     }
00574     else if (strcmp(name,"longitude")==0)
00575     {
00576         if ((obj->longitude = convert_to_longitude(value))==QNAN)
00577         {
00578             output_error("object %s:d longitude '%s' is invalid", obj->oclass->name, obj->id, value);
00579             return FAILED;
00580         }
00581         else 
00582             return SUCCESS;
00583     }
00584     else if (strcmp(name,"in_svc")==0)
00585     {
00586         if ((obj->in_svc = convert_to_timestamp(value))==TS_INVALID)
00587         {
00588             output_error("object %s:%d in_svc timestamp '%s' is invalid", obj->oclass->name, obj->id, value);
00589             return FAILED;
00590         }
00591         else
00592             return SUCCESS;
00593     }
00594     else if (strcmp(name,"out_svc")==0)
00595     {
00596         if ((obj->out_svc = convert_to_timestamp(value))==TS_INVALID)
00597         {
00598             output_error("object %s:%d out_svc timestamp '%s' is invalid", obj->oclass->name, obj->id, value);
00599             return FAILED;
00600         }
00601         else
00602             return SUCCESS;
00603     }
00604     else if (strcmp(name,"flags")==0)
00605     {
00606         /* flags should be ignored */
00607         return SUCCESS;
00608     }
00609     else
00610         return FAILED;
00611     /* should never get here */
00612 }
00613 
00617 int object_set_value_by_name(OBJECT *obj, 
00618                              PROPERTYNAME name, 
00619                              char *value) 
00620 {
00621     PROPERTY *prop;
00622     void *addr;
00623     for (prop=obj->oclass->pmap; prop!=NULL && prop->otype==obj->oclass->type; prop=prop->next)
00624     {
00625         if (obj->oclass->type==prop->otype && strcmp(name,prop->name)==0)
00626             break;
00627     }
00628     if ((prop==NULL || prop->otype!=obj->oclass->type))
00629     {
00630         if (set_header_value(obj,name,value)==FAILED)
00631         {
00632             errno = ENOENT;
00633             return 0;
00634         }
00635         else
00636         {
00637             size_t len = strlen(value);
00638             return len>0?(int)len:1; /* empty string is not necessarily wrong */
00639         }
00640     }
00641     if(prop->access != PA_PUBLIC){
00642         output_error("trying to set the value of non-public property %s in %s", prop->name, obj->oclass->name);
00643         return 0;
00644     }
00645     addr = (void*)((char *)(obj+1)+(int64)(prop->addr)); /* warning: cast from pointer to integer of different size */
00646     return object_set_value_by_addr(obj,addr,value,prop);
00647 }
00648 
00649 /* Set a property value by reference to its name
00650  */
00651 int object_set_double_by_name(OBJECT *obj, PROPERTYNAME name, double value)
00652 {
00653     PROPERTY *prop;
00654     for (prop=obj->oclass->pmap; prop!=NULL && prop->otype==obj->oclass->type; prop=prop->next)
00655     {
00656         if (obj->oclass->type==prop->otype && prop->ptype==PT_double && strcmp(name,prop->name)==0)
00657             break;
00658     }
00659     if (prop==NULL || prop->otype!=obj->oclass->type )
00660     {
00661         errno = ENOENT;
00662         return 0;
00663     }
00664     if(prop->access != PA_PUBLIC){
00665         output_error("trying to set the value of non-public property %s in %s", prop->name, obj->oclass->name);
00666         return 0;
00667     }
00668     *(double*)((char *)(obj+1)+(int64)(prop->addr)) = value; /* warning: cast from pointer to integer of different size */
00669     return 1;
00670 }
00671 
00675 int object_get_value_by_addr(OBJECT *obj, 
00676                              void *addr, 
00677                              char *value, 
00678                              int size, 
00679                              PROPERTY *prop) 
00680 {
00681     prop = prop ? prop : get_property_at_addr(obj,addr);
00682     if(prop->access == PA_PRIVATE){
00683         output_error("trying to read the value of private property %s in %s", prop->name, obj->oclass->name);
00684         return 0;
00685     }
00686     return class_property_to_string(prop,addr,value,size);
00687 }
00688 
00692 int object_get_value_by_name(OBJECT *obj, PROPERTYNAME name, char *value, int size)
00693 {
00694     char *buffer = object_property_to_string(obj,name);
00695     if (buffer==NULL)
00696         return 0;
00697     strncpy(value,buffer,size);
00698     return 1;
00699 }
00700 
00704 OBJECT *object_get_first()
00705 {
00706     return first_object;
00707 }
00708 
00712 OBJECT *object_get_next(OBJECT *obj) 
00713 {
00714     return obj!=NULL ? obj->next : NULL;
00715 }
00716 
00717 
00718 /*  Set the rank of the object (internal use only) 
00719     This function keeps track of which object initiated
00720     the request to prevent looping.  This will prevent
00721     an object_set_parent call from creating a parent loop.
00722  */
00723 static int set_rank(OBJECT *obj, OBJECTRANK rank, OBJECT *first)
00724 {
00725     OBJECTRANK parent_rank = -1;
00726     if (rank >= object_get_count()){
00727         output_error("%s: set_rank wigging out, rank > object count", object_name(first));
00728         return -1;
00729     }
00730     if (obj==first)
00731     {
00732         output_error("%s: set_rank failed, parent loopback has occurred", object_name(first));
00733         return -1;
00734     }
00735     if (obj->flags & OF_RERANK){
00736         output_error("%s: object flaged as already re-ranked", object_name(obj));
00737         return -1;
00738     } else {
00739         obj->flags += OF_RERANK;
00740     }
00741     if (rank >= obj->rank)
00742         obj->rank = rank+1;
00743     if (obj->parent != NULL)
00744     {
00745         parent_rank = set_rank(obj->parent,obj->rank,first?first:obj);
00746     }
00747     obj->flags -= OF_RERANK;
00748     return obj->rank;
00749 }
00750 
00755 int object_set_rank(OBJECT *obj, 
00756                     OBJECTRANK rank) 
00757 {
00758     /* prevent rank from decreasing */
00759     if(obj == NULL)
00760         return 0;
00761     if (rank<=obj->rank)
00762         return obj->rank;
00763     return set_rank(obj,rank,NULL);
00764 }
00765 
00769 int object_set_parent(OBJECT *obj, 
00770                       OBJECT *parent) 
00771 {
00772     if(obj == parent)
00773         return -1;
00774     obj->parent = parent;
00775     if (parent!=NULL)
00776         return set_rank(parent,obj->rank,NULL);
00777     return obj->rank;
00778 }
00779 
00785 int object_set_dependent(OBJECT *obj, 
00786                          OBJECT *dependent) 
00787 {
00788     if(obj == dependent)
00789         return -1;
00790     return set_rank(dependent,obj->rank,NULL);
00791 }
00792 
00793 /* Convert the value of an object property to a string
00794  * Note that this function uses a single static buffer.
00795  */
00796 char *object_property_to_string(OBJECT *obj, char *name)
00797 {
00798     static char buffer[4096];
00799     PROPERTY *prop;
00800     void *addr;
00801     for (prop=obj->oclass->pmap; prop!=NULL && prop->otype==obj->oclass->type; prop=prop->next)
00802     {
00803         if (obj->oclass->type==prop->otype && strcmp(name,prop->name)==0)
00804             break;
00805     }
00806     if (prop==NULL || prop->otype!=obj->oclass->type)
00807     {
00808         errno = ENOENT;
00809         return NULL;
00810     }
00811     addr = GETADDR(obj,prop); /* warning: cast from pointer to integer of different size */
00812     if (prop->ptype==PT_delegated)
00813         return prop->delegation->to_string(addr,buffer,sizeof(buffer))?buffer:NULL;
00814     else if (class_property_to_string(prop,addr,buffer,sizeof(buffer)))
00815     {
00816         if (prop->unit!=NULL)
00817         {
00818             strcat(buffer," ");
00819             strcat(buffer,prop->unit->name);
00820         }
00821         return buffer;
00822     }
00823     else
00824         return "";
00825 }
00826 
00837 TIMESTAMP object_sync(OBJECT *obj, 
00838                       TIMESTAMP ts, 
00839                       PASSCONFIG pass) 
00840 {
00841     clock_t t=clock();
00842     register TIMESTAMP plc_time=TS_NEVER, sync_time;
00843     
00844     /* call recalc if recalc bit is set */
00845     if ( (obj->flags&OF_RECALC) && obj->oclass->recalc!=NULL)
00846     {
00847         obj->oclass->recalc(obj);
00848         obj->flags &= ~OF_RECALC;
00849     }
00850 
00851     /* call PLC code on bottom-up, if any */
00852     if ( !(obj->flags&OF_HASPLC) && obj->oclass->plc!=NULL && pass==PC_BOTTOMUP ) 
00853         plc_time = obj->oclass->plc(obj,ts);
00854 
00855     /* call sync */
00856     sync_time = (*obj->oclass->sync)(obj,ts,pass);
00857 
00858     /* do profiling, if needed */
00859     if (global_profiler==1)
00860     {
00861         obj->oclass->profiler.count++;
00862         obj->oclass->profiler.clocks += clock()-t;
00863     }
00864     sync_time = min(plc_time,sync_time);
00865     if (sync_time>TS_MAX)
00866         return TS_NEVER;
00867     else
00868         return sync_time;
00869 }
00870 
00876 int object_init(OBJECT *obj) 
00877 {
00878     if (obj->oclass->init!=NULL)
00879         return (int)(*(obj->oclass->init))(obj,obj->parent);
00880     return 1;
00881 }
00882 
00885 int object_isa(OBJECT *obj, 
00886                char *type) 
00887 {
00888     if (strcmp(obj->oclass->name,type)==0)
00889         return 1;
00890     else if (obj->oclass->isa)
00891         return (int)obj->oclass->isa(obj,type);
00892     else
00893         return 0;
00894 }
00895 
00899 int object_dump(char *outbuffer, 
00900                 int size, 
00901                 OBJECT *obj) 
00902 {
00903     char buffer[65536];
00904     char tmp[256];
00905     int count = 0;
00906     PROPERTY *prop;
00907     static int safesize;
00908     if (size>sizeof(buffer))
00909         size = sizeof(buffer);
00910     safesize = size;
00911 
00912     count += sprintf(buffer+count,"object %s:%d {\n", obj->oclass->name, obj->id);
00913 
00914     /* dump internal properties */
00915     if (obj->parent!=NULL)
00916         count += sprintf(buffer+count,"\tparent = %s:%d (%s)\n", obj->parent->oclass->name, obj->parent->id, obj->parent->name!=NULL?obj->parent->name:"");
00917     else
00918         count += sprintf(buffer+count,"\troot object\n");
00919     if (obj->name!=NULL)
00920         count += sprintf(buffer+count,"\tname %s\n",obj->name);
00921     count += sprintf(buffer+count,"\trank = %d;\n", obj->rank);
00922     count += sprintf(buffer+count,"\tclock = %s (%" FMT_INT64 "d);\n", convert_from_timestamp(obj->clock,tmp,sizeof(tmp))>0?tmp:"(invalid)",obj->clock);
00923     if (!isnan(obj->latitude)) count += sprintf(buffer+count,"\tlatitude = %s;\n",convert_from_latitude(obj->latitude,tmp,sizeof(tmp))?tmp:"(invalid)");
00924     if (!isnan(obj->longitude)) count += sprintf(buffer+count,"\tlongitude = %s;\n",convert_from_longitude(obj->longitude,tmp,sizeof(tmp))?tmp:"(invalid)");
00925     count += sprintf(buffer+count,"\tflags = %s;\n", convert_from_set(tmp,sizeof(tmp),&(obj->flags),object_flag_property())?tmp:"(invalid)");
00926 
00927     /* dump properties */
00928     for (prop=obj->oclass->pmap;prop!=NULL && prop->otype==obj->oclass->type;prop=prop->next)
00929     {
00930         char *value = object_property_to_string(obj,prop->name);
00931         if (value!=NULL)
00932             count += sprintf(buffer+count,"\t%s %s = %s;\n",prop->ptype==PT_delegated?prop->delegation->type:class_get_property_typename(prop->ptype),prop->name,value);
00933         if (count>safesize)
00934             throw_exception("object_dump(char *buffer=%x, int size=%d, OBJECT *obj=%s:%d) buffer overrun", outbuffer,size,obj->oclass->name,obj->id);
00935     }
00936     count += sprintf(buffer+count,"}\n");
00937     if(count < size && count < sizeof(buffer)){
00938         strncpy(outbuffer, buffer, count+1);
00939         return count;
00940     } else {
00941         output_error("buffer too small in object_dump()!");
00942         return 0;
00943     }
00944     
00945 }
00946 
00950 int object_saveall(FILE *fp) 
00951 {
00952     unsigned count=0;
00953     char buffer[1024];
00954     count += fprintf(fp,"\n########################################################\n");
00955     count += fprintf(fp,"# objects\n");
00956     {   OBJECT *obj;
00957         for (obj=first_object; obj!=NULL; obj=obj->next)
00958         {
00959             PROPERTY *prop;
00960             char32 oname="(unidentified)";
00961             count += fprintf(fp,"object %s:%d {\n", obj->oclass->name, obj->id);
00962 
00963             /* dump internal properties */
00964             if (obj->parent!=NULL)
00965             {
00966                 convert_from_object(oname,sizeof(oname),&obj->parent,NULL);
00967                 count += fprintf(fp,"\tparent %s;\n", oname);
00968             }
00969             else
00970                 count += fprintf(fp,"\troot;\n");
00971             count += fprintf(fp,"\trank %d;\n", obj->rank);
00972             if (obj->name!=NULL)
00973                 count += fprintf(fp,"\tname %s;\n", obj->name);
00974             count += fprintf(fp,"\tclock %s;\n", convert_from_timestamp(obj->clock,buffer,sizeof(buffer))>0?buffer:"(invalid)");
00975             if (!isnan(obj->latitude)) count += fprintf(fp,"\tlatitude %s;\n",convert_from_latitude(obj->latitude,buffer,sizeof(buffer))?buffer:"(invalid)");
00976             if (!isnan(obj->longitude)) count += fprintf(fp,"\tlongitude %s;\n",convert_from_longitude(obj->longitude,buffer,sizeof(buffer))?buffer:"(invalid)");
00977             count += fprintf(fp,"\tflags %s;\n", convert_from_set(buffer,sizeof(buffer),&(obj->flags),object_flag_property())?buffer:"(invalid)");
00978             /* dump properties */
00979             for (prop=obj->oclass->pmap;prop!=NULL && prop->otype==obj->oclass->type;prop=prop->next)
00980             {
00981                 char *value = object_property_to_string(obj,prop->name);
00982                 if (value!=NULL)
00983                     count += fprintf(fp,"\t%s %s;\n",prop->name,value);
00984             }
00985             count += fprintf(fp,"}\n");
00986         }
00987     }
00988     return count;   
00989 }
00990 
00994 int object_saveall_xml(FILE *fp) 
00995 {
00996     unsigned count = 0;
00997     char buffer[1024];
00998     PROPERTY *prop = NULL;
00999     OBJECT *obj;
01000     CLASS *oclass=NULL;
01001 
01002     for(obj = first_object; obj != NULL; obj = obj->next){
01003 
01004         char32 oname = "(unidentified)";
01005         convert_from_object(oname, sizeof(oname), &obj, NULL); /* what if we already have a name? -mh */
01006         if ((oclass == NULL) || (obj->oclass->type != oclass->type))
01007             oclass = obj->oclass;
01008         count += fprintf(fp,"\t\t<object type=\"%s\" id=\"%i\" name=\"%s\">\n", obj->oclass->name, obj->id, oname);
01009 
01010         /* dump internal properties */
01011         if (obj->parent!=NULL)
01012         {
01013             convert_from_object(oname,sizeof(oname),&obj->parent,NULL);
01014             count += fprintf(fp,"\t\t\t<parent>\n"); 
01015             count += fprintf(fp, "\t\t\t\t%s\n", oname);
01016             count += fprintf(fp,"\t\t\t</parent>\n");
01017         }
01018         else
01019             count += fprintf(fp,"\t\t\t<parent>root</parent>\n");
01020             count += fprintf(fp,"\t\t\t<rank>%d</rank>\n", obj->rank);
01021             count += fprintf(fp,"\t\t\t<clock>\n", obj->clock);
01022             count += fprintf(fp,"\t\t\t\t <timestamp>%s</timestamp>\n", convert_from_timestamp(obj->clock,buffer,sizeof(buffer))>0?buffer:"(invalid)");
01023             count += fprintf(fp,"\t\t\t</clock>\n");
01024             /* why do latitude/longitude have 2 values?  I currently only store as float in the schema... */
01025         if (!isnan(obj->latitude)) 
01026             count += fprintf(fp,"\t\t\t<latitude>%lf %s</latitude>\n",obj->latitude,convert_from_latitude(obj->latitude,buffer,sizeof(buffer))?buffer:"(invalid)");
01027         if (!isnan(obj->longitude)) 
01028             count += fprintf(fp,"\t\t\t<longitude>%lf %s</longitude>\n",obj->longitude,convert_from_longitude(obj->longitude,buffer,sizeof(buffer))?buffer:"(invalid)");
01029 
01030         /* dump properties */
01031         for (prop=oclass->pmap;prop!=NULL && prop->otype==oclass->type;prop=prop->next)
01032         {
01033             char *value = object_property_to_string(obj,prop->name);
01034             if (value!=NULL){
01035                 count += fprintf(fp, "\t\t\t<%s>%s</%s>\n", prop->name, value, prop->name);
01036             }
01037         }
01038         count += fprintf(fp,"\t\t</object>\n");
01039     }
01040 
01041     count += fprintf(fp,"\t</objects>\n");
01042     return count;   
01043 }
01044 
01045 int object_saveall_xml_old(FILE *fp);
01046 
01047 int object_saveall_xml_old(FILE *fp) 
01048 {
01049     unsigned count=0;
01050     char buffer[1024];
01051     count += fprintf(fp,"\t<objects>\n");
01052     {   OBJECT *obj;
01053         CLASS *oclass=NULL;
01054         for (obj=first_object; obj!=NULL; obj=obj->next)
01055         {
01056             PROPERTY *prop;
01057             char32 oname="(unidentified)";
01058             convert_from_object(oname,sizeof(oname),&obj,NULL);
01059             if (oclass==NULL || obj->oclass->type!=oclass->type)
01060                 oclass = obj->oclass;
01061             count += fprintf(fp,"\t\t<object>\n");
01062             count += fprintf(fp,"\t\t\t<name>%s</name> \n", oname);
01063             count += fprintf(fp,"\t\t\t<class>%s</class> \n", obj->oclass->name);
01064             count += fprintf(fp, "\t\t\t<id>%d</id>\n", obj->id);
01065 
01066             /* dump internal properties */
01067             if (obj->parent!=NULL)
01068             {
01069                 convert_from_object(oname,sizeof(oname),&obj->parent,NULL);
01070                 count += fprintf(fp,"\t\t\t<parent>\n"); 
01071                 count += fprintf(fp,"\t\t\t\t<name>%s</name>\n", oname);
01072                 count += fprintf(fp,"\t\t\t\t<class>%s</class>\n", obj->parent->oclass->name);
01073                 count += fprintf(fp,"\t\t\t\t<id>%d</id>\n", obj->parent->id);
01074                 count += fprintf(fp,"\t\t\t</parent>\n");
01075             }
01076             else
01077                 count += fprintf(fp,"\t\t\t<parent>root</parent>\n");
01078                 count += fprintf(fp,"\t\t\t<rank>%d</rank>\n", obj->rank);
01079                 count += fprintf(fp,"\t\t\t<clock>\n", obj->clock);
01080                 count += fprintf(fp,"\t\t\t\t <timestamp>%s</timestamp>\n", convert_from_timestamp(obj->clock,buffer,sizeof(buffer))>0?buffer:"(invalid)");
01081                 count += fprintf(fp,"\t\t\t</clock>\n");
01082                 /* why do latitude/longitude have 2 values?  I currently only store as float in the schema... */
01083             if (!isnan(obj->latitude)) 
01084                 count += fprintf(fp,"\t\t\t<latitude>%lf %s</latitude>\n",obj->latitude,convert_from_latitude(obj->latitude,buffer,sizeof(buffer))?buffer:"(invalid)");
01085             if (!isnan(obj->longitude)) 
01086                 count += fprintf(fp,"\t\t\t<longitude>%lf %s</longitude>\n",obj->longitude,convert_from_longitude(obj->longitude,buffer,sizeof(buffer))?buffer:"(invalid)");
01087 
01088             /* dump properties */
01089             count += fprintf(fp,"\t\t\t<properties>\n");
01090             for (prop=oclass->pmap;prop!=NULL && prop->otype==oclass->type;prop=prop->next)
01091             {
01092                 char *value = object_property_to_string(obj,prop->name);
01093                 if (value!=NULL)
01094                     count += fprintf(fp,"\t\t\t\t<property>\n");
01095                 count += fprintf(fp,"\t\t\t\t\t<type>%s</type> \n", prop->name);
01096                     count += fprintf(fp,"\t\t\t\t\t<value>%s</value> \n", value);
01097                     count += fprintf(fp,"\t\t\t\t</property>\n");
01098             }
01099             count += fprintf(fp,"\t\t\t</properties>\n");
01100             count += fprintf(fp,"\t\t</object>\n");
01101         }
01102     }
01103     count += fprintf(fp,"\t</objects>\n");
01104     return count;   
01105 }
01106 
01107 int convert_from_latitude(double v,void *buffer,int bufsize)
01108 {
01109     double d = floor(fabs(v));
01110     double r = fabs(v)-d;
01111     double m = floor(r*60);
01112     double s = (r - (double)m/60.0)*3600;
01113     char ns = v<0 ? 'S':'N';
01114     if(isnan(v)) return 0;
01115     return sprintf(buffer,"%.0f%c%.0f'%.2f\"",d,ns,m,s);
01116 }
01117 
01118 int convert_from_longitude(double v,void *buffer,int bufsize)
01119 {
01120     double d = floor(fabs(v));
01121     double r = fabs(v)-d;
01122     double m = floor(r*60);
01123     double s = (r - (double)m/60.0)*3600;
01124     char ns = v<0 ? 'W':'E';
01125     if(isnan(v)) return 0;
01126     return sprintf(buffer,"%.0f%c%.0f'%.2f\"",d,ns,m,s);
01127 }
01128 
01129 double convert_to_latitude(char *buffer)
01130 {
01131     int32 d, m=0;
01132     double s=0;
01133     char ns;
01134     if (sscanf(buffer,"%d%c%d'%lf\"",&d,&ns,&m,&s)>1)
01135     {   
01136         double v = (double)d+(double)m/60+s/3600;
01137         if (v>=0 || v<=90)
01138         {
01139             if (ns=='S')
01140                 return -v;
01141             else if (ns=='N')
01142                 return v;
01143         }
01144     }
01145     return QNAN;
01146 }
01147 
01148 double convert_to_longitude(char *buffer)
01149 {
01150     int32 d, m=0;
01151     double s=0;
01152     char ns;
01153     if (sscanf(buffer,"%d%c%d'%lf\"",&d,&ns,&m,&s)>1)
01154     {   
01155         double v = (double)d+(double)m/60+s/3600;
01156         if (v>=0 || v<=90)
01157         {
01158             if (ns=='W')
01159                 return -v;
01160             else if (ns=='E')
01161                 return v;
01162         }
01163     }
01164     return QNAN;
01165 }
01166 
01167 /***************************************************************************
01168  OBJECT NAME TREE
01169  ***************************************************************************/
01170 
01171 typedef struct s_objecttree {
01172     char name[32];
01173     OBJECT *obj;
01174     struct s_objecttree *before, *after;
01175     int balance; /* unused */
01176 } OBJECTTREE;
01177 
01178 static OBJECTTREE *top=NULL;
01179 
01180 void debug_traverse_tree(OBJECTTREE *tree){
01181     if(tree == NULL){
01182         tree = top;
01183         if(top == NULL)
01184             return;
01185     }
01186     if(tree->before != NULL) debug_traverse_tree(tree->before);
01187     output_test("%s", tree->name);
01188     if(tree->after != NULL) debug_traverse_tree(tree->after);
01189 }
01190 
01191 /* returns the height of the tree */
01192 int tree_get_height(OBJECTTREE *tree){
01193     if(tree == NULL){
01194         return 0;
01195     } else {
01196         int left = tree_get_height(tree->before);
01197         int right = tree_get_height(tree->after);
01198         if(left > right)
01199             return left+1;
01200         else return right+1;
01201     }
01202 }
01203 
01204 /* returns the node to point to instead of tree */
01205 void rotate_tree_right(OBJECTTREE **tree){ /* move one object from left to right */
01206     OBJECTTREE *root, *pivot, *child;
01207     root = *tree;
01208     pivot = root->before;
01209     child = root->before->after;
01210     *tree = pivot;
01211     pivot->after = root;
01212     root->before = child;
01213     root->balance += 2;
01214     pivot->balance += 1;
01215 }
01216 
01217 /* returns the node to point to instead of tree */
01218 void rotate_tree_left(OBJECTTREE **tree){ /* move one object from right to left */
01219     OBJECTTREE *root, *pivot, *child;
01220     root = *tree;
01221     pivot = root->after;
01222     child = root->after->before;
01223     *tree = pivot;
01224     pivot->before = root;
01225     root->after = child;
01226     root->balance -= 2;
01227     pivot->balance -= 1;
01228 }
01229 
01230 /*  Rebalance the tree to make searching more efficient
01231     It's a good idea to this after the tree is built
01232  */
01233 int object_tree_rebalance(OBJECTTREE *tree) /* AVL logic */
01234 {
01235     /* currently being done during insertions & deletions */
01236     return 0;
01237 }
01238 
01239 /*  Add an item to the tree
01240     returns the "correct" root node for the subtree that an object was added to.
01241  */
01242 static int addto_tree(OBJECTTREE **tree, OBJECTTREE *item)
01243 {
01244     int rel = strcmp((*tree)->name, item->name);
01245     int right = 0, left = 0, ir = 0, il = 0, rv = 0;
01246     if (rel>0)
01247     {
01248         (*tree)->balance--;
01249         if ((*tree)->before==NULL)
01250         {
01251             (*tree)->before = item;
01252             return 1;
01253         }
01254         else {
01255             rv = addto_tree(&((*tree)->before),item);
01256             if(global_no_balance) return rv + 1;
01257             if((*tree)->balance > 1){
01258                 if((*tree)->after->balance < 0){ /* inner left is heavy */
01259                     rotate_tree_right(&((*tree)->after));
01260                 }
01261                 rotate_tree_left(tree);
01262             } else if((*tree)->balance < -1){
01263                 if((*tree)->before->balance > 0){ /* inner right is heavy */
01264                     rotate_tree_left(&((*tree)->before));
01265                 }
01266                 rotate_tree_right(tree);
01267             }
01268             return tree_get_height(*tree); /* verify after rotations */
01269         }
01270     }
01271     else if (rel<0)
01272     {
01273         (*tree)->balance++;
01274         if ((*tree)->after==NULL)
01275         {
01276             (*tree)->after = item;
01277             return 1;
01278         }
01279         else {
01280             rv = addto_tree(&((*tree)->after),item);
01281             if(global_no_balance) return rv + 1;
01282             if((*tree)->balance > 1){
01283                 if((*tree)->after->balance < 0){ /* inner left is heavy */
01284                     rotate_tree_right(&((*tree)->after));
01285                 }
01286                 rotate_tree_left(tree); //  was left/right
01287             } else if((*tree)->balance < -1){
01288                 if((*tree)->before->balance > 0){ /* inner right is heavy */
01289                     rotate_tree_left(&((*tree)->before));
01290                 }
01291                 rotate_tree_right(tree);
01292             }
01293             return tree_get_height(*tree); /* verify after rotations */
01294         }
01295     }
01296     else
01297         return (*tree)->obj==item->obj;
01298     return 0;
01299 }
01300 
01301 /*  Add an object to the object tree.  Throws exceptions on memory errors.
01302     Returns a pointer to the object tree item if successful, NULL on failure (usually because name already used)
01303  */
01304 static OBJECTTREE *object_tree_add(OBJECT *obj, OBJECTNAME name)
01305 {
01306     OBJECTTREE *item = (OBJECTTREE*)malloc(sizeof(OBJECTTREE));
01307     if (item==NULL) 
01308         throw_exception("object_tree_add(obj='%s:%d', name='%s'): memory allocation failed (%s)",
01309             obj->oclass->name, obj->id, name, strerror(errno));
01310     item->obj = obj;
01311     item->balance = 0;
01312     strncpy(item->name,name,sizeof(item->name));
01313     item->before=item->after=NULL;
01314     if (top==NULL)
01315     {
01316         top = item;
01317         return top;
01318     }
01319     else{
01320         return addto_tree(&top,item) ? item : NULL;
01321     }
01322 }
01323 
01324 /*  Finds a name in the tree
01325  */
01326 static OBJECTTREE **findin_tree(OBJECTTREE *tree, OBJECTNAME name)
01327 {
01328     static OBJECTTREE **temptree = NULL;
01329     if (tree==NULL)
01330         return NULL;
01331     else 
01332     {
01333         int rel = strcmp(tree->name,name);
01334         if (rel>0)
01335         {
01336             if(tree->before != NULL){
01337                 if(strcmp(tree->before->name, name) == 0)
01338                     return &(tree->before);
01339                 else
01340                     return findin_tree(tree->before, name);
01341             } else {
01342                 return NULL;
01343             }
01344         }
01345         else if (rel<0)
01346         {
01347             if(tree->after != NULL){
01348                 if(strcmp(tree->after->name, name) == 0)
01349                     return &(tree->after);
01350                 else
01351                     return findin_tree(tree->after, name);
01352             } else {
01353                 return NULL;
01354             }
01355         }
01356         else
01357             return (temptree = &tree);
01358     }
01359 }
01360 
01361 /*  Deletes a name from the tree
01362     WARNING: removing a tree entry does NOT free() its object!
01363  */
01364 void object_tree_delete(OBJECT *obj, OBJECTNAME name)
01365 {
01366     OBJECTTREE **item = findin_tree(top,name);
01367     OBJECTTREE *temp = NULL, **dtemp = NULL;
01368     if (item!=NULL && strcmp((*item)->name,name)!=0){
01369         if((*item)->after == NULL && (*item)->before == NULL){ /* no children -- nuke */
01370             free(*item);
01371             *item = NULL;
01372         } else if((*item)->after != NULL && (*item)->before != NULL){ /* two children -- find a replacement */
01373             dtemp = &((*item)->before);
01374             while(temp->after != NULL)
01375                 dtemp = &(temp->after);
01376             temp = (*dtemp)->before;
01377             (*dtemp)->before = (*item)->before;
01378             (*dtemp)->after = (*item)->after;
01379             free(*item);
01380             *item = *dtemp;
01381             *dtemp = temp;
01382             /* replace item with the rightmost left element.*/
01383 
01384         } else if((*item)->after == NULL || (*item)->before == NULL){ /* one child -- promotion time! */
01385             if((*item)->after != NULL){
01386                 temp = (*item)->after;
01387                 free(*item);
01388                 *item = temp;
01389             } else if((*item)->before != NULL){
01390                 temp = (*item)->before;
01391                 free(*item);
01392                 *item = temp;
01393             } else {
01394                 output_fatal("unexpected branch result in object_tree_delete");
01395             }
01396         }
01397 
01398         /* throw_exception("object_tree_delete(obj=%s:%d, name='%s'): rename of objects in tree is not supported yet", obj->oclass->name, obj->id, name); */
01399     }
01400 }
01401 
01405 OBJECT *object_find_name(OBJECTNAME name)
01406 {
01407     OBJECTTREE **item = findin_tree(top,name);
01408     return item!=NULL && *item!=NULL ? (*item)->obj : NULL;
01409 }
01410 
01415 void object_set_name(OBJECT *obj, OBJECTNAME name)
01416 {
01417     /* the next line of code guards the object against floating w/o a tree. -mh */
01418     /* if (name == NULL) return; */
01419     if (obj->name!=NULL)
01420         object_tree_delete(obj,name);
01421     if (name!=NULL)
01422     {
01423         OBJECTTREE *item = object_tree_add(obj,name);
01424         obj->name = item->name;
01425     }
01426 }
01427 
01431 void remove_objects()
01432 { 
01433     OBJECT* obj1;
01434 
01435     obj1 = first_object;
01436     while(obj1 != NULL){
01437         first_object = obj1->next;
01438         obj1->oclass->profiler.numobjs--;
01439         free(obj1);
01440         obj1 = first_object;
01441     }
01442 
01443     next_object_id = 0;
01444 }
01445 

GridLAB-DTM Version 1.0
An open-source project initiated by the US Department of Energy