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
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
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 ;
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));
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;
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));
00294 errno = ENOENT;
00295 return NULL;
00296 }
00297
00298
00299
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));
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));
00318 }
00319 }
00320 }
00321 errno = ENOENT;
00322 return NULL;
00323 }
00324
00325
00326
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));
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));
00345 }
00346 }
00347 }
00348 errno = ENOENT;
00349 return NULL;
00350 }
00351
00352
00353
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));
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));
00372 }
00373 }
00374 }
00375 errno = ENOENT;
00376 return NULL;
00377 }
00378
00379
00380
00381
00382 double *object_get_double_quick(OBJECT *obj, PROPERTY *prop)
00383 {
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));
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));
00403 }
00404 }
00405 }
00406 errno = ENOENT;
00407 return NULL;
00408 }
00409
00410
00411
00412
00413 complex *object_get_complex_quick(OBJECT *obj, PROPERTY *prop)
00414 {
00415 return (complex*)((char*)obj+sizeof(OBJECT)+(int64)(prop->addr));
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));
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));
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));
00444 errno = ENOENT;
00445 return NULL;
00446 }
00447
00448
00449
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));
00461 }
00462 }
00463 }
00464 errno = ENOENT;
00465 return NULL;
00466 }
00467
00468
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
00475 if (prop!=NULL && obj->oclass->pmap->otype==prop->otype && (int64)(prop->addr)==offset && prop->access != PA_PRIVATE)
00476 return prop;
00477
00478
00479 for (prop=obj->oclass->pmap; prop!=NULL; prop=(prop->next->otype==prop->otype?prop->next:NULL))
00480 {
00481 if ((int64)(prop->addr)==offset)
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
00509 if (prop->flags&PF_RECALC) obj->flags |= OF_RECALC;
00510
00511
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
00620 return SUCCESS;
00621 }
00622 else
00623 return FAILED;
00624
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;
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));
00659 return object_set_value_by_addr(obj,addr,value,prop);
00660 }
00661
00662
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;
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));
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
00753
00754
00755
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
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
00828
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);
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
00879 if ( (obj->flags&OF_RECALC) && obj->oclass->recalc!=NULL)
00880 {
00881 obj->oclass->recalc(obj);
00882 obj->flags &= ~OF_RECALC;
00883 }
00884
00885
00886 if ( !(obj->flags&OF_HASPLC) && obj->oclass->plc!=NULL && pass==PC_BOTTOMUP )
00887 plc_time = obj->oclass->plc(obj,ts);
00888
00889
00890 sync_time = (*obj->oclass->sync)(obj,ts,pass);
00891
00892
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
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
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
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
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);
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
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
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
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
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
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
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
01203
01204
01205 typedef struct s_objecttree {
01206 char name[32];
01207 OBJECT *obj;
01208 struct s_objecttree *before, *after;
01209 int balance;
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
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
01239 void rotate_tree_right(OBJECTTREE **tree){
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
01252 void rotate_tree_left(OBJECTTREE **tree){
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
01265
01266
01267 int object_tree_rebalance(OBJECTTREE *tree)
01268 {
01269
01270 return 0;
01271 }
01272
01273
01274
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){
01293 rotate_tree_right(&((*tree)->after));
01294 }
01295 rotate_tree_left(tree);
01296 } else if((*tree)->balance < -1){
01297 if((*tree)->before->balance > 0){
01298 rotate_tree_left(&((*tree)->before));
01299 }
01300 rotate_tree_right(tree);
01301 }
01302 return tree_get_height(*tree);
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){
01318 rotate_tree_right(&((*tree)->after));
01319 }
01320 rotate_tree_left(tree);
01321 } else if((*tree)->balance < -1){
01322 if((*tree)->before->balance > 0){
01323 rotate_tree_left(&((*tree)->before));
01324 }
01325 rotate_tree_right(tree);
01326 }
01327 return tree_get_height(*tree);
01328 }
01329 }
01330 else
01331 return (*tree)->obj==item->obj;
01332 return 0;
01333 }
01334
01335
01336
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
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
01396
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){
01404 free(*item);
01405 *item = NULL;
01406 } else if((*item)->after != NULL && (*item)->before != NULL){
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
01417
01418 } else if((*item)->after == NULL || (*item)->before == NULL){
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
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
01452
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