00001
00027 #include <float.h>
00028 #include <math.h>
00029
00030 #ifdef WIN32
00031 #define isnan _isnan
00032 #endif
00033
00034 #include "object.h"
00035 #include "convert.h"
00036 #include "output.h"
00037 #include "globals.h"
00038
00039
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
00049 KEYWORD oflags[] = {
00050
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
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);
00068 }
00069
00070
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
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
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 ;
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));
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;
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));
00281 errno = ENOENT;
00282 return NULL;
00283 }
00284
00285
00286
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));
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));
00305 }
00306 }
00307 }
00308 errno = ENOENT;
00309 return NULL;
00310 }
00311
00312
00313
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));
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));
00332 }
00333 }
00334 }
00335 errno = ENOENT;
00336 return NULL;
00337 }
00338
00339
00340
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));
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));
00359 }
00360 }
00361 }
00362 errno = ENOENT;
00363 return NULL;
00364 }
00365
00366
00367
00368
00369 double *object_get_double_quick(OBJECT *obj, PROPERTY *prop)
00370 {
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));
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));
00390 }
00391 }
00392 }
00393 errno = ENOENT;
00394 return NULL;
00395 }
00396
00397
00398
00399
00400 complex *object_get_complex_quick(OBJECT *obj, PROPERTY *prop)
00401 {
00402 return (complex*)((char*)obj+sizeof(OBJECT)+(int64)(prop->addr));
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));
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));
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));
00431 errno = ENOENT;
00432 return NULL;
00433 }
00434
00435
00436
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));
00448 }
00449 }
00450 }
00451 errno = ENOENT;
00452 return NULL;
00453 }
00454
00455
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
00462 if (prop!=NULL && obj->oclass->pmap->otype==prop->otype && (int64)(prop->addr)==offset && prop->access != PA_PRIVATE)
00463 return prop;
00464
00465
00466 for (prop=obj->oclass->pmap; prop!=NULL; prop=(prop->next->otype==prop->otype?prop->next:NULL))
00467 {
00468 if ((int64)(prop->addr)==offset)
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
00496 if (prop->flags&PF_RECALC) obj->flags |= OF_RECALC;
00497
00498
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
00607 return SUCCESS;
00608 }
00609 else
00610 return FAILED;
00611
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;
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));
00646 return object_set_value_by_addr(obj,addr,value,prop);
00647 }
00648
00649
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;
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
00719
00720
00721
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
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
00794
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);
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
00845 if ( (obj->flags&OF_RECALC) && obj->oclass->recalc!=NULL)
00846 {
00847 obj->oclass->recalc(obj);
00848 obj->flags &= ~OF_RECALC;
00849 }
00850
00851
00852 if ( !(obj->flags&OF_HASPLC) && obj->oclass->plc!=NULL && pass==PC_BOTTOMUP )
00853 plc_time = obj->oclass->plc(obj,ts);
00854
00855
00856 sync_time = (*obj->oclass->sync)(obj,ts,pass);
00857
00858
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
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
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
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
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);
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
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
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
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
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
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
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
01169
01170
01171 typedef struct s_objecttree {
01172 char name[32];
01173 OBJECT *obj;
01174 struct s_objecttree *before, *after;
01175 int balance;
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
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
01205 void rotate_tree_right(OBJECTTREE **tree){
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
01218 void rotate_tree_left(OBJECTTREE **tree){
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
01231
01232
01233 int object_tree_rebalance(OBJECTTREE *tree)
01234 {
01235
01236 return 0;
01237 }
01238
01239
01240
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){
01259 rotate_tree_right(&((*tree)->after));
01260 }
01261 rotate_tree_left(tree);
01262 } else if((*tree)->balance < -1){
01263 if((*tree)->before->balance > 0){
01264 rotate_tree_left(&((*tree)->before));
01265 }
01266 rotate_tree_right(tree);
01267 }
01268 return tree_get_height(*tree);
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){
01284 rotate_tree_right(&((*tree)->after));
01285 }
01286 rotate_tree_left(tree);
01287 } else if((*tree)->balance < -1){
01288 if((*tree)->before->balance > 0){
01289 rotate_tree_left(&((*tree)->before));
01290 }
01291 rotate_tree_right(tree);
01292 }
01293 return tree_get_height(*tree);
01294 }
01295 }
01296 else
01297 return (*tree)->obj==item->obj;
01298 return 0;
01299 }
01300
01301
01302
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
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
01362
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){
01370 free(*item);
01371 *item = NULL;
01372 } else if((*item)->after != NULL && (*item)->before != NULL){
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
01383
01384 } else if((*item)->after == NULL || (*item)->before == NULL){
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
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
01418
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