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

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