00001
00028 #include <float.h>
00029 #include <math.h>
00030
00031 #ifdef WIN32
00032 #define isnan _isnan
00033 #endif
00034
00035 #include "object.h"
00036 #include "convert.h"
00037 #include "output.h"
00038 #include "globals.h"
00039 #include "module.h"
00040
00041
00042 static OBJECTNUM next_object_id = 0;
00043 static OBJECTNUM deleted_object_count = 0;
00044 static OBJECT *first_object = NULL;
00045 static OBJECT *last_object = NULL;
00046 static OBJECTNUM object_array_size = 0;
00047 static OBJECT **object_array = NULL;
00048 #define QNAN sqrt(-1)
00050
00051 KEYWORD oflags[] = {
00052
00053 {"NONE", OF_NONE, oflags + 1},
00054 {"HASPLC", OF_HASPLC, oflags + 2},
00055 {"LOCKED", OF_LOCKED, oflags + 3},
00056 {"RERANKED", OF_RERANK, oflags + 4},
00057 {"RECALC", OF_RECALC, NULL},
00058 };
00059
00060
00061 int object_get_oflags(KEYWORD **extflags){
00062 int flag_size = sizeof(oflags);
00063
00064 *extflags = malloc(flag_size);
00065
00066 if(extflags == NULL){
00067 output_error("object_get_oflags: malloc failure");
00068 errno = ENOMEM;
00069 return -1;
00070 }
00071
00072 memcpy(*extflags, oflags, flag_size);
00073
00074 return flag_size / sizeof(KEYWORD);
00075 }
00076
00077 PROPERTY *object_flag_property(){
00078 static PROPERTY flags = {0, "flags", PT_set, 1, PA_PUBLIC, NULL, (void*)-4, NULL, oflags, NULL};
00079
00080 return &flags;
00081 }
00082
00083 KEYWORD oaccess[] = {
00084
00085 {"PUBLIC", PA_PUBLIC, oaccess + 1},
00086 {"REFERENCE", PA_REFERENCE, oaccess + 2},
00087 {"PROTECTED", PA_PROTECTED, oaccess + 3},
00088 {"PRIVATE", PA_PRIVATE, NULL},
00089 };
00090
00091 PROPERTY *object_access_property(){
00092 static PROPERTY flags = {0, "access", PT_enumeration, 1, PA_PUBLIC, NULL, (void*) -4, NULL, oaccess, NULL};
00093
00094 return &flags;
00095 }
00096
00097
00098 void object_tree_delete(OBJECT *obj, OBJECTNAME name);
00099
00104 unsigned int object_get_count(){
00105 return next_object_id - deleted_object_count;
00106 }
00107
00116 PROPERTY *object_get_property(OBJECT *obj,
00117 PROPERTYNAME name){
00118 if(obj == NULL){
00119 return NULL;
00120 } else {
00121 return class_find_property(obj->oclass, name);
00122 }
00123 }
00124
00130 int object_build_object_array(){
00131 unsigned int tcount = object_get_count();
00132 unsigned int i = 0;
00133 OBJECT *optr = object_get_first();
00134
00135 if(object_array != NULL){
00136 free(object_array);
00137 }
00138
00139 object_array = malloc(sizeof(OBJECT *) * tcount);
00140
00141 if(object_array == NULL){
00142 return 0;
00143 }
00144
00145 object_array_size = tcount;
00146
00147 for(i = 0; i < tcount; ++i){
00148 object_array[i] = optr;
00149 optr = optr->next;
00150 }
00151
00152 return object_array_size;
00153 }
00154
00155
00156 PROPERTY *object_prop_in_class(OBJECT *obj, PROPERTY *prop){
00157 if(prop == NULL){
00158 return NULL;
00159 }
00160
00161 if(obj != NULL){
00162 return class_prop_in_class(obj->oclass, prop);
00163 } else {
00164 return NULL;
00165 }
00166 }
00167
00171 OBJECT *object_find_by_id(OBJECTNUM id){
00172 OBJECT *obj;
00173
00174 if(object_get_count() == object_array_size){
00175 if(id < object_array_size){
00176 return object_array[id];
00177 } else {
00178 return NULL;
00179 }
00180 } else {
00181
00182 if(object_build_object_array())
00183 return object_find_by_id(id);
00184 }
00185
00186 for(obj = first_object; obj != NULL; obj = obj->next){
00187 if(obj->id == id){
00188 return obj;
00189 }
00190 }
00191
00192 return NULL;
00193 }
00194
00195
00203 char *object_name(OBJECT *obj){
00204 static char32 oname="(invalid)";
00205
00206 convert_from_object(oname, sizeof(oname), &obj, NULL);
00207
00208 return oname;
00209 }
00210
00213 char *object_get_unit(OBJECT *obj, char *name){
00214 static UNIT *dimless = NULL;
00215 PROPERTY *prop = object_get_property(obj, name);
00216
00217 if(prop == NULL){
00218 throw_exception("property '%s' not found in object '%s'", name, object_name(obj));
00219
00220
00221
00222
00223
00224 }
00225
00226 if(dimless == NULL){
00227 dimless=unit_find("1");
00228 }
00229
00230 if(prop->unit != NULL){
00231 return prop->unit->name;
00232 } else {
00233 return dimless->name;
00234 }
00235 }
00236
00242 OBJECT *object_create_single(CLASS *oclass){
00243
00244 OBJECT *obj = 0;
00245 static int tp_next = 0;
00246 static int tp_count = 0;
00247 PROPERTY *prop;
00248 int sz = sizeof(OBJECT);
00249
00250 if(tp_count == 0){
00251 tp_count = processor_count();
00252 }
00253
00254 if(oclass == NULL){
00255 throw_exception("object_create_single(CLASS *oclass=NULL): class is NULL");
00256
00257
00258
00259
00260 }
00261
00262 obj = (OBJECT*)malloc(sz + oclass->size);
00263
00264 if(obj == NULL){
00265 throw_exception("object_create_single(CLASS *oclass='%s'): memory allocation failed", oclass->name);
00266
00267
00268
00269 }
00270
00271 memset(obj, 0, sz + oclass->size);
00272
00273 obj->tp_affinity = 0;
00274 tp_next %= tp_count;
00275
00276 obj->id = next_object_id++;
00277 obj->oclass = oclass;
00278 obj->next = NULL;
00279 obj->name = NULL;
00280 obj->parent = NULL;
00281 obj->rank = 0;
00282 obj->clock = 0;
00283 obj->latitude = QNAN;
00284 obj->longitude = QNAN;
00285 obj->in_svc = TS_ZERO;
00286 obj->out_svc = TS_NEVER;
00287 obj->space = object_current_namespace();
00288 obj->flags = OF_NONE;
00289
00290 for (prop=obj->oclass->pmap; prop!=NULL; prop=(prop->next?prop->next:(prop->oclass->parent?prop->oclass->parent->pmap:NULL)))
00291 property_create(prop,(void*)((char *)(obj+1)+(int64)(prop->addr)));
00292
00293 if(first_object == NULL){
00294 first_object = obj;
00295 } else {
00296 last_object->next = obj;
00297 }
00298
00299 last_object = obj;
00300 oclass->profiler.numobjs++;
00301
00302 return obj;
00303 }
00304
00314 OBJECT *object_create_foreign(OBJECT *obj){
00315
00316 static int tp_next = 0;
00317 static int tp_count = 0;
00318
00319 if(tp_count == 0){
00320 tp_count = processor_count();
00321 }
00322
00323 if(obj == NULL){
00324 throw_exception("object_create_foreign(OBJECT *obj=NULL): object is NULL");
00325
00326
00327
00328
00329 }
00330
00331 if(obj->oclass == NULL){
00332 throw_exception("object_create_foreign(OBJECT *obj=<new>): object->oclass is NULL");
00333
00334
00335
00336 }
00337
00338 if(obj->oclass->magic!=CLASSVALID)
00339 throw_exception("object_create_foreign(OBJECT *obj=<new>): obj->oclass is not really a class");
00340
00341
00342
00343
00344
00345 obj->tp_affinity = 0;
00346 tp_next %= tp_count;
00347
00348 obj->id = next_object_id++;
00349 obj->next = NULL;
00350 obj->name = NULL;
00351 obj->parent = NULL;
00352 obj->rank = 0;
00353 obj->clock = 0;
00354 obj->latitude = QNAN;
00355 obj->longitude = QNAN;
00356 obj->in_svc = TS_ZERO;
00357 obj->out_svc = TS_NEVER;
00358 obj->flags = OF_FOREIGN;
00359
00360 if(first_object == NULL){
00361 first_object = obj;
00362 } else {
00363 last_object->next = obj;
00364 }
00365
00366 last_object = obj;
00367 obj->oclass->profiler.numobjs++;
00368
00369 return obj;
00370 }
00371
00376 OBJECT *object_create_array(CLASS *oclass,
00377 unsigned int n_objects){
00378 OBJECT *first = NULL;
00379
00380 while(n_objects-- > 0){
00381 OBJECT *obj = object_create_single(oclass);
00382
00383 if(obj == NULL){
00384 return NULL;
00385 } else if(first == NULL){
00386 first = obj;
00387 }
00388 }
00389 return first;
00390 }
00391
00395 OBJECT *object_remove_by_id(OBJECTNUM id){
00396
00397 OBJECT *target = object_find_by_id(id);
00398 OBJECT *prev = NULL;
00399 OBJECT *next = NULL;
00400
00401 if(target != NULL){
00402 char name[64] = "";
00403
00404 if(first_object == target){
00405 first_object = target->next;
00406 } else {
00407 for(prev = first_object; (prev->next != NULL) && (prev->next != target); prev = prev->next){
00408 ;
00409 }
00410 }
00411
00412 object_tree_delete(target, target->name ? target->name : (sprintf(name, "%s:%d", target->oclass->name, target->id), name));
00413 next = target->next;
00414 prev->next = next;
00415 target->oclass->profiler.numobjs--;
00416 free(target);
00417 deleted_object_count++;
00418 }
00419
00420 return next;
00421 }
00422
00426 void *object_get_addr(OBJECT *obj,
00427 char *name){
00428 PROPERTY *prop = class_find_property(obj->oclass,name);
00429
00430 if(prop != NULL && prop->access != PA_PRIVATE){
00431 return (void *)((char *)(obj + 1) + (int64)(prop->addr));
00432 } else {
00433 errno = ENOENT;
00434 return NULL;
00435 }
00436 }
00437
00438 OBJECT *object_get_object(OBJECT *obj, PROPERTY *prop)
00439 {
00440 int64 o = (int64)obj;
00441 int64 s = (int64)sizeof(OBJECT);
00442 int64 a = (int64)(prop->addr);
00443 int64 i = o + s + a;
00444
00445 if(object_prop_in_class(obj, prop) && prop->ptype == PT_object && prop->access != PA_PRIVATE){
00446 return *(OBJECT **)i;
00447 } else {
00448 errno = ENOENT;
00449 return NULL;
00450 }
00451 }
00452
00453 OBJECT *object_get_object_by_name(OBJECT *obj, char *name)
00454 {
00455 PROPERTY *prop = class_find_property(obj->oclass, name);
00456
00457 if(prop != NULL && prop->access != PA_PRIVATE && prop->ptype == PT_object){
00458 return (OBJECT *)((char *)obj + sizeof(OBJECT) + (int64)(prop->addr));
00459 } else {
00460 errno = ENOENT;
00461 return NULL;
00462 }
00463 }
00464
00465 enumeration *object_get_enum(OBJECT *obj, PROPERTY *prop){
00466 if(object_prop_in_class(obj, prop) && prop->ptype == PT_enumeration && prop->access != PA_PRIVATE){
00467 return (enumeration *)((char *)(obj) + sizeof(OBJECT) + (int64)(prop->addr));
00468 } else {
00469 errno = ENOENT;
00470 return NULL;
00471 }
00472 }
00473
00474 enumeration *object_get_enum_by_name(OBJECT *obj, char *name){
00475 PROPERTY *prop = class_find_property(obj->oclass, name);
00476
00477 if(prop != NULL && prop->access != PA_PRIVATE){
00478 return (enumeration *)((char *)(obj) + sizeof(OBJECT) + (int64)(prop->addr));
00479 } else {
00480 errno = ENOENT;
00481 return NULL;
00482 }
00483 }
00484
00485
00486
00487
00488 int16 *object_get_int16(OBJECT *obj, PROPERTY *prop)
00489 {
00490 if(object_prop_in_class(obj, prop) && prop->ptype == PT_int16 && prop->access != PA_PRIVATE){
00491 return (int16 *)((char *)obj+sizeof(OBJECT)+(int64)(prop->addr));
00492 } else {
00493 errno = ENOENT;
00494 return NULL;
00495 }
00496 }
00497
00498 int16 *object_get_int16_by_name(OBJECT *obj, char *name)
00499 {
00500 PROPERTY *prop = class_find_property(obj->oclass, name);
00501
00502 if(prop != NULL && prop->access != PA_PRIVATE){
00503 return (int16 *)((char *)obj + sizeof(OBJECT) + (int64)(prop->addr));
00504 } else {
00505 errno = ENOENT;
00506 return NULL;
00507 }
00508 }
00509
00510
00511
00512
00513 int32 *object_get_int32(OBJECT *obj, PROPERTY *prop)
00514 {
00515 if(object_prop_in_class(obj, prop) && prop->ptype == PT_int32 && prop->access != PA_PRIVATE){
00516 return (int32 *)((char *)obj + sizeof(OBJECT) + (int64)(prop->addr));
00517 } else {
00518 errno = ENOENT;
00519 return NULL;
00520 }
00521 }
00522
00523 int32 *object_get_int32_by_name(OBJECT *obj, char *name)
00524 {
00525 PROPERTY *prop = class_find_property(obj->oclass,name);
00526 if(prop!=NULL && prop->access != PA_PRIVATE)
00527 return (int32 *)((char*)obj+sizeof(OBJECT)+(int64)(prop->addr));
00528 errno = ENOENT;
00529 return NULL;
00530 }
00531
00532
00533
00534
00535 int64 *object_get_int64(OBJECT *obj, PROPERTY *prop)
00536 {
00537 if(object_prop_in_class(obj, prop) && prop->ptype == PT_int64 && prop->access != PA_PRIVATE){
00538 return (int64 *)((char *)obj + sizeof(OBJECT) + (int64)(prop->addr));
00539 } else {
00540 errno = ENOENT;
00541 return NULL;
00542 }
00543 }
00544
00545 int64 *object_get_int64_by_name(OBJECT *obj, char *name)
00546 {
00547 PROPERTY *prop = class_find_property(obj->oclass,name);
00548 if(prop!=NULL && prop->access != PA_PRIVATE)
00549 return (int64 *)((char*)obj+sizeof(OBJECT)+(int64)(prop->addr));
00550 errno = ENOENT;
00551 return NULL;
00552 }
00553
00554
00555
00556
00557 double *object_get_double_quick(OBJECT *obj, PROPERTY *prop)
00558 {
00559 return (double*)((char*)obj+sizeof(OBJECT)+(int64)(prop->addr));
00560 }
00561
00562 double *object_get_double(OBJECT *obj, PROPERTY *prop)
00563 {
00564 if(object_prop_in_class(obj, prop) && prop->ptype==PT_double && prop->access != PA_PRIVATE)
00565 return (double*)((char*)obj+sizeof(OBJECT)+(int64)(prop->addr));
00566 errno = ENOENT;
00567 return NULL;
00568 }
00569
00570 double *object_get_double_by_name(OBJECT *obj, char *name)
00571 {
00572 PROPERTY *prop = class_find_property(obj->oclass,name);
00573 if(prop!=NULL && prop->access != PA_PRIVATE)
00574 return (double *)((char*)obj+sizeof(OBJECT)+(int64)(prop->addr));
00575 errno = ENOENT;
00576 return NULL;
00577 }
00578
00579
00580
00581
00582 complex *object_get_complex_quick(OBJECT *obj, PROPERTY *prop)
00583 {
00584 return (complex*)((char*)obj+sizeof(OBJECT)+(int64)(prop->addr));
00585 }
00586
00587 complex *object_get_complex(OBJECT *obj, PROPERTY *prop)
00588 {
00589 if(object_prop_in_class(obj, prop) && prop->ptype==PT_complex && prop->access != PA_PRIVATE)
00590 return (complex*)((char*)obj+sizeof(OBJECT)+(int64)(prop->addr));
00591 errno = ENOENT;
00592 return NULL;
00593 }
00594
00595 complex *object_get_complex_by_name(OBJECT *obj, char *name)
00596 {
00597 PROPERTY *prop = class_find_property(obj->oclass,name);
00598 if(prop!=NULL && prop->access != PA_PRIVATE)
00599 return (complex *)((char*)obj+sizeof(OBJECT)+(int64)(prop->addr));
00600 errno = ENOENT;
00601 return NULL;
00602 }
00603
00604 char *object_get_string(OBJECT *obj, PROPERTY *prop){
00605 if(object_prop_in_class(obj, prop) && prop->ptype >= PT_char8 && prop->ptype <= PT_char1024 && prop->access != PA_PRIVATE)
00606 return (char *)((char*)obj+sizeof(OBJECT)+(int64)(prop->addr));
00607 errno = ENOENT;
00608 return NULL;
00609 }
00610
00611
00612
00613
00614 char *object_get_string_by_name(OBJECT *obj, char *name)
00615 {
00616 PROPERTY *prop = class_find_property(obj->oclass,name);
00617 if(prop!=NULL && prop->access != PA_PRIVATE)
00618 return ((char*)obj+sizeof(OBJECT)+(int64)(prop->addr));
00619 errno = ENOENT;
00620 return NULL;
00621 }
00622
00623
00624 static PROPERTY *get_property_at_addr(OBJECT *obj, void *addr)
00625 {
00626 static PROPERTY *prop = NULL;
00627 int64 offset = (int)((char*)addr - (char*)(obj+1));
00628
00629
00630 if(prop!=NULL && object_prop_in_class(obj, prop) && (int64)(prop->addr) == offset && prop->access != PA_PRIVATE)
00631 return prop;
00632
00633
00634 for (prop=obj->oclass->pmap; prop!=NULL; prop=(prop->next->oclass==prop->oclass?prop->next:NULL))
00635 {
00636 if((int64)(prop->addr)==offset)
00637 if(prop->access != PA_PRIVATE)
00638 return prop;
00639 else {
00640 output_error("trying to get the private property %s in %s", prop->name, obj->oclass->name);
00641
00642
00643
00644
00645 return 0;
00646 }
00647 }
00648 return NULL;
00649 }
00650
00654 int object_set_value_by_addr(OBJECT *obj,
00655 void *addr,
00656 char *value,
00657 PROPERTY *prop)
00658 {
00659 int result=0;
00660 if(prop==NULL && (prop=get_property_at_addr(obj,addr))==NULL)
00661 return 0;
00662 if(prop->access != PA_PUBLIC){
00663 output_error("trying to set the value of non-public property %s in %s", prop->name, obj->oclass->name);
00664
00665
00666
00667 return 0;
00668 }
00669
00670
00671 if(prop->flags&PF_RECALC) obj->flags |= OF_RECALC;
00672
00673
00674 if(obj->oclass->notify){
00675 if(obj->oclass->notify(obj,NM_PREUPDATE,prop) == 0){
00676 output_error("preupdate notify failure on %s in %s", prop->name, obj->name ? obj->name : "an unnamed object");
00677 }
00678 }
00679 result = class_string_to_property(prop,addr,value);
00680 if(obj->oclass->notify){
00681 if(obj->oclass->notify(obj,NM_POSTUPDATE,prop) == 0){
00682 output_error("postupdate notify failure on %s in %s", prop->name, obj->name ? obj->name : "an unnamed object");
00683 }
00684 }
00685 return result;
00686 }
00687
00688 static int set_header_value(OBJECT *obj, char *name, char *value)
00689 {
00690 if(strcmp(name,"name")==0)
00691 {
00692 if(obj->name!=NULL)
00693 {
00694 output_error("object %s:d name already set to %s", obj->oclass->name, obj->id, obj->name);
00695
00696
00697
00698
00699 return FAILED;
00700 }
00701 else
00702 {
00703 object_set_name(obj,value);
00704 return SUCCESS;
00705 }
00706 }
00707 else if(strcmp(name,"parent")==0)
00708 {
00709 OBJECT *parent=object_find_name(value);
00710 if(parent==NULL && strcmp(value,"")!=0)
00711 {
00712 output_error("object %s:%d parent %s not found", obj->oclass->name, obj->id, value);
00713 return FAILED;
00714 }
00715 else if(object_set_parent(obj,parent)==FAILED && strcmp(value,"")!=0)
00716 {
00717 output_error("object %s:%d cannot use parent %s", obj->oclass->name, obj->id, value);
00718 return FAILED;
00719 }
00720 else
00721 return SUCCESS;
00722 }
00723 else if(strcmp(name,"rank")==0)
00724 {
00725 if(object_set_rank(obj,atoi(value))<0)
00726 {
00727 output_error("object %s:%d rank '%s' is invalid", obj->oclass->name, obj->id, value);
00728 return FAILED;
00729 }
00730 else
00731 return SUCCESS;
00732 }
00733 else if(strcmp(name,"clock")==0)
00734 {
00735 if((obj->clock = convert_to_timestamp(value))==TS_INVALID)
00736 {
00737 output_error("object %s:%d clock timestamp '%s' is invalid", obj->oclass->name, obj->id, value);
00738 return FAILED;
00739 }
00740 else
00741 return SUCCESS;
00742 }
00743 else if(strcmp(name,"valid_to")==0)
00744 {
00745 if((obj->valid_to = convert_to_timestamp(value))==TS_INVALID)
00746 {
00747 output_error("object %s:%d valid_to timestamp '%s' is invalid", obj->oclass->name, obj->id, value);
00748 return FAILED;
00749 }
00750 else
00751 return SUCCESS;
00752 }
00753 else if(strcmp(name,"latitude")==0)
00754 {
00755 if((obj->latitude = convert_to_latitude(value))==QNAN)
00756 {
00757 output_error("object %s:%d latitude '%s' is invalid", obj->oclass->name, obj->id, value);
00758
00759
00760
00761
00762
00763
00764 return FAILED;
00765 }
00766 else
00767 return SUCCESS;
00768 }
00769 else if(strcmp(name,"longitude")==0)
00770 {
00771 if((obj->longitude = convert_to_longitude(value))==QNAN)
00772 {
00773 output_error("object %s:d longitude '%s' is invalid", obj->oclass->name, obj->id, value);
00774
00775
00776
00777
00778
00779
00780 return FAILED;
00781 }
00782 else
00783 return SUCCESS;
00784 }
00785 else if(strcmp(name,"in_svc")==0)
00786 {
00787 TIMESTAMP t = convert_to_timestamp(value);
00788 if(t == TS_INVALID)
00789 {
00790 output_error("object %s:%d in_svc timestamp '%s' is invalid", obj->oclass->name, obj->id, value);
00791 return FAILED;
00792 }
00793 else if(t >= obj->out_svc)
00794 {
00795 output_error("object %s:%d in_svc timestamp '%s' overlaps out_svc timestamp", obj->oclass->name, obj->id, value);
00796 return FAILED;
00797 }
00798 else
00799 {
00800 obj->in_svc = t;
00801 return SUCCESS;
00802 }
00803 }
00804 else if(strcmp(name,"out_svc")==0)
00805 {
00806 TIMESTAMP t = convert_to_timestamp(value);
00807 if(t == TS_INVALID)
00808 {
00809 output_error("object %s:%d out_svc timestamp '%s' is invalid", obj->oclass->name, obj->id, value);
00810 return FAILED;
00811 }
00812 else if(t <= obj->in_svc)
00813 {
00814 output_error("object %s:%d out_svc timestamp '%s' overlaps in_svc timestamp", obj->oclass->name, obj->id, value);
00815 return FAILED;
00816 }
00817 else
00818 {
00819 obj->out_svc = t;
00820 return SUCCESS;
00821 }
00822 }
00823 else if(strcmp(name,"flags")==0)
00824 {
00825
00826 return SUCCESS;
00827 }
00828 else {
00829 output_error("object %s:%d called set_header_value() for invalid field '%s'", name);
00830
00831
00832
00833
00834 return FAILED;
00835 }
00836
00837 }
00838
00842 int object_set_value_by_name(OBJECT *obj,
00843 PROPERTYNAME name,
00844 char *value)
00845 {
00846 void *addr;
00847 PROPERTY *prop = class_find_property(obj->oclass,name);
00848 if(prop==NULL)
00849 {
00850 if(set_header_value(obj,name,value)==FAILED)
00851 {
00852 errno = ENOENT;
00853 return 0;
00854 }
00855 else
00856 {
00857 size_t len = strlen(value);
00858 return len>0?(int)len:1;
00859 }
00860 }
00861 if(prop->access != PA_PUBLIC){
00862 output_error("trying to set the value of non-public property %s in %s", prop->name, obj->oclass->name);
00863
00864
00865
00866 return 0;
00867 }
00868 addr = (void*)((char *)(obj+1)+(int64)(prop->addr));
00869 return object_set_value_by_addr(obj,addr,value,prop);
00870 }
00871
00872
00873
00874
00875 int object_set_int16_by_name(OBJECT *obj, PROPERTYNAME name, int16 value)
00876 {
00877 PROPERTY *prop = class_find_property(obj->oclass,name);
00878 if(prop==NULL)
00879 {
00880 errno = ENOENT;
00881 return 0;
00882 }
00883 if(prop->access != PA_PUBLIC){
00884 output_error("trying to set the value of non-public property %s in %s", prop->name, obj->oclass->name);
00885
00886
00887
00888 return 0;
00889 }
00890 *(int16 *)((char *)(obj+1)+(int64)(prop->addr)) = value;
00891 return 1;
00892 }
00893
00894
00895
00896 int object_set_int32_by_name(OBJECT *obj, PROPERTYNAME name, int32 value)
00897 {
00898 PROPERTY *prop = class_find_property(obj->oclass,name);
00899 if(prop==NULL)
00900 {
00901 errno = ENOENT;
00902 return 0;
00903 }
00904 if(prop->access != PA_PUBLIC){
00905 output_error("trying to set the value of non-public property %s in %s", prop->name, obj->oclass->name);
00906
00907
00908
00909 return 0;
00910 }
00911 *(int32 *)((char *)(obj+1)+(int64)(prop->addr)) = value;
00912 return 1;
00913 }
00914
00915
00916
00917 int object_set_int64_by_name(OBJECT *obj, PROPERTYNAME name, int64 value)
00918 {
00919 PROPERTY *prop = class_find_property(obj->oclass,name);
00920 if(prop==NULL)
00921 {
00922 errno = ENOENT;
00923 return 0;
00924 }
00925 if(prop->access != PA_PUBLIC){
00926 output_error("trying to set the value of non-public property %s in %s", prop->name, obj->oclass->name);
00927
00928
00929
00930 return 0;
00931 }
00932 *(int64 *)((char *)(obj+1)+(int64)(prop->addr)) = value;
00933 return 1;
00934 }
00935
00936
00937
00938 int object_set_double_by_name(OBJECT *obj, PROPERTYNAME name, double value)
00939 {
00940 PROPERTY *prop = class_find_property(obj->oclass,name);
00941 if(prop==NULL)
00942 {
00943 errno = ENOENT;
00944 return 0;
00945 }
00946 if(prop->access != PA_PUBLIC){
00947 output_error("trying to set the value of non-public property %s in %s", prop->name, obj->oclass->name);
00948
00949
00950
00951 return 0;
00952 }
00953 *(double*)((char *)(obj+1)+(int64)(prop->addr)) = value;
00954 return 1;
00955 }
00956
00957
00958
00959 int object_set_complex_by_name(OBJECT *obj, PROPERTYNAME name, complex value)
00960 {
00961 PROPERTY *prop = class_find_property(obj->oclass,name);
00962 if(prop==NULL)
00963 {
00964 errno = ENOENT;
00965 return 0;
00966 }
00967 if(prop->access != PA_PUBLIC){
00968 output_error("trying to set the value of non-public property %s in %s", prop->name, obj->oclass->name);
00969
00970
00971
00972 return 0;
00973 }
00974 *(complex*)((char *)(obj+1)+(int64)(prop->addr)) = value;
00975 return 1;
00976 }
00977
00981 int object_get_value_by_addr(OBJECT *obj,
00982 void *addr,
00983 char *value,
00984 int size,
00985 PROPERTY *prop)
00986 {
00987 prop = prop ? prop : get_property_at_addr(obj,addr);
00988 if(prop->access == PA_PRIVATE){
00989 output_error("trying to read the value of private property %s in %s", prop->name, obj->oclass->name);
00990
00991
00992
00993 return 0;
00994 }
00995 return class_property_to_string(prop,addr,value,size);
00996 }
00997
01001 int object_get_value_by_name(OBJECT *obj, PROPERTYNAME name, char *value, int size)
01002 {
01003 char *buffer = object_property_to_string(obj,name);
01004 if(buffer==NULL)
01005 return 0;
01006 strncpy(value,buffer,size);
01007 return 1;
01008 }
01009
01012 OBJECT *object_get_reference(OBJECT *obj, char *name){
01013 PROPERTY *prop = class_find_property(obj->oclass,name);
01014 if(prop == NULL || prop->access == PA_PRIVATE || prop->ptype != PT_object)
01015 {
01016 if(prop == NULL){
01017 ;
01018 }
01019 errno = EINVAL;
01020 return NULL;
01021 } else {
01022 return *(OBJECT**)((char*)obj + sizeof(OBJECT) + (int64)(prop->addr));
01023 }
01024 }
01025
01029 OBJECT *object_get_first()
01030 {
01031 return first_object;
01032 }
01033
01037 OBJECT *object_get_next(OBJECT *obj){
01038 if(obj != NULL){
01039 return obj->next;
01040 } else {
01041 return NULL;
01042 }
01043 }
01044
01045
01046
01047
01048
01049
01050
01051 static int set_rank(OBJECT *obj, OBJECTRANK rank, OBJECT *first)
01052 {
01053 OBJECTRANK parent_rank = -1;
01054 if(rank >= object_get_count()){
01055 output_error("%s: set_rank wigging out, rank > object count", object_name(first));
01056
01057
01058
01059
01060
01061 return -1;
01062 }
01063 if(obj==first)
01064 {
01065 output_error("%s: set_rank failed, parent loopback has occurred", object_name(first));
01066 return -1;
01067 }
01068 if(obj->flags & OF_RERANK){
01069 output_error("%s: object flaged as already re-ranked", object_name(obj));
01070 return -1;
01071 } else {
01072 obj->flags |= OF_RERANK;
01073 }
01074 if(rank >= obj->rank)
01075 obj->rank = rank+1;
01076 if(obj->parent != NULL)
01077 {
01078 parent_rank = set_rank(obj->parent,obj->rank,first?first:obj);
01079 if(parent_rank == -1)
01080 return -1;
01081 }
01082 obj->flags &= ~OF_RERANK;
01083 return obj->rank;
01084 }
01085
01090 int object_set_rank(OBJECT *obj,
01091 OBJECTRANK rank)
01092 {
01093
01094 if(obj == NULL)
01095 return 0;
01096 if(rank<=obj->rank)
01097 return obj->rank;
01098 return set_rank(obj,rank,NULL);
01099 }
01100
01104 int object_set_parent(OBJECT *obj,
01105 OBJECT *parent)
01106 {
01107 if(obj == parent){
01108 output_error("object %s tried to set itself as its parent", object_name(obj));
01109 return -1;
01110 }
01111 obj->parent = parent;
01112 if(parent!=NULL)
01113 return set_rank(parent,obj->rank,NULL);
01114 return obj->rank;
01115 }
01116
01122 int object_set_dependent(OBJECT *obj,
01123 OBJECT *dependent)
01124 {
01125 if(obj == dependent)
01126 return -1;
01127 return set_rank(dependent,obj->rank,NULL);
01128 }
01129
01130
01131
01132
01133 char *object_property_to_string(OBJECT *obj, char *name)
01134 {
01135 static char buffer[4096];
01136 void *addr;
01137 PROPERTY *prop = class_find_property(obj->oclass,name);
01138 if(prop==NULL)
01139 {
01140 errno = ENOENT;
01141 return NULL;
01142 }
01143 addr = GETADDR(obj,prop);
01144 if(prop->ptype==PT_delegated)
01145 return prop->delegation->to_string(addr,buffer,sizeof(buffer))?buffer:NULL;
01146 else if(class_property_to_string(prop,addr,buffer,sizeof(buffer)))
01147 {
01148 if(prop->unit!=NULL)
01149 {
01150 strcat(buffer," ");
01151 strcat(buffer,prop->unit->name);
01152 }
01153 return buffer;
01154 }
01155 else
01156 return "";
01157 }
01158
01159
01160 TIMESTAMP _object_sync(OBJECT *obj,
01161 TIMESTAMP ts,
01162 PASSCONFIG pass)
01163 {
01164 clock_t t=clock();
01165 CLASS *oclass = obj->oclass;
01166 register TIMESTAMP plc_time=TS_NEVER, sync_time;
01167 TIMESTAMP effective_valid_to = min(obj->clock+global_skipsafe,obj->valid_to);
01168
01169
01170 if(global_skipsafe>0 && (obj->flags&OF_SKIPSAFE) && ts<effective_valid_to)
01171
01172
01173 return effective_valid_to;
01174
01175
01176 if(oclass->sync==NULL)
01177 {
01178 char buffer[64];
01179 char *passname = (pass==PC_PRETOPDOWN?"PC_PRETOPDOWN":(pass==PC_BOTTOMUP?"PC_BOTTOMUP":(pass==PC_POSTTOPDOWN?"PC_POSTTOPDOWN":"<unknown>")));
01180 output_fatal("object_sync(OBJECT *obj='%s', TIMESTAMP ts='%s', PASSCONFIG pass=%s): int64 sync_%s(OBJECT*,TIMESTAMP,PASSCONFIG) is not implemented in module %s", object_name(obj), convert_from_timestamp(ts,buffer,sizeof(buffer))?buffer:"<invalid>", passname, oclass->name, oclass->module->name);
01181
01182
01183
01184
01185
01186
01187
01188 return TS_INVALID;
01189 }
01190
01191 #ifndef WIN32
01192
01193 alarm(global_maximum_synctime);
01194 #endif
01195
01196
01197 if( (obj->flags&OF_RECALC) && obj->oclass->recalc!=NULL)
01198 {
01199 oclass->recalc(obj);
01200 obj->flags &= ~OF_RECALC;
01201 }
01202
01203
01204 if( !(obj->flags&OF_HASPLC) && oclass->plc!=NULL && pass==PC_BOTTOMUP )
01205 plc_time = oclass->plc(obj,ts);
01206
01207
01208 sync_time = (*obj->oclass->sync)(obj,ts,pass);
01209 if(plc_time<sync_time)
01210 sync_time = plc_time;
01211
01212
01213 if(sync_time>TS_MAX)
01214 obj->valid_to = TS_NEVER;
01215 else
01216 obj->valid_to = sync_time;
01217
01218
01219 if(global_profiler==1)
01220 {
01221 obj->oclass->profiler.count++;
01222 obj->oclass->profiler.clocks += clock()-t;
01223 }
01224
01225 #ifndef WIN32
01226
01227 alarm(0);
01228 #endif
01229
01230 return obj->valid_to;
01231 }
01242 TIMESTAMP object_sync(OBJECT *obj,
01243 TIMESTAMP ts,
01244 PASSCONFIG pass)
01245 {
01246 TIMESTAMP t2=TS_NEVER;
01247 do {
01248
01249 t2 = _object_sync(obj,(ts<(obj->valid_to>0?obj->valid_to:TS_NEVER)?ts:obj->valid_to),pass);
01250 } while (t2>0 && ts>(t2<0?-t2:t2) && t2<TS_NEVER);
01251 return t2;
01252 }
01253
01259 int object_init(OBJECT *obj){
01260 if(obj->oclass->init != NULL){
01261 return (int)(*(obj->oclass->init))(obj, obj->parent);
01262 }
01263 return 1;
01264 }
01265
01266 int object_commit(OBJECT *obj){
01267 if(obj->oclass->commit != NULL){
01268 return (int)(*(obj->oclass->commit))(obj);
01269 }
01270 return 1;
01271 }
01272
01275 int object_isa(OBJECT *obj,
01276 char *type){
01277 if(strcmp(obj->oclass->name,type) == 0){
01278 return 1;
01279 } else if(obj->oclass->isa){
01280 return (int)obj->oclass->isa(obj, type);
01281 } else {
01282 return 0;
01283 }
01284 }
01285
01289 int object_dump(char *outbuffer,
01290 int size,
01291 OBJECT *obj){
01292 char buffer[65536];
01293 char tmp[256];
01294 int count = 0;
01295 PROPERTY *prop = NULL;
01296 static int safesize;
01297 CLASS *pclass = NULL;
01298 if(size>sizeof(buffer)){
01299 size = sizeof(buffer);
01300 }
01301 safesize = size;
01302
01303 count += sprintf(buffer + count, "object %s:%d {\n", obj->oclass->name, obj->id);
01304
01305
01306 if(obj->parent != NULL){
01307 count += sprintf(buffer + count, "\tparent = %s:%d (%s)\n", obj->parent->oclass->name, obj->parent->id, obj->parent->name != NULL ? obj->parent->name : "");
01308 } else {
01309 count += sprintf(buffer + count, "\troot object\n");
01310 }
01311 if(obj->name != NULL){
01312 count += sprintf(buffer + count, "\tname %s\n", obj->name);
01313 }
01314
01315 count += sprintf(buffer + count, "\trank = %d;\n", obj->rank);
01316 count += sprintf(buffer + count, "\tclock = %s (%" FMT_INT64 "d);\n", convert_from_timestamp(obj->clock, tmp, sizeof(tmp)) > 0 ? tmp : "(invalid)", obj->clock);
01317
01318 if(!isnan(obj->latitude)){
01319 count += sprintf(buffer + count, "\tlatitude = %s;\n", convert_from_latitude(obj->latitude, tmp, sizeof(tmp)) ? tmp : "(invalid)");
01320 }
01321 if(!isnan(obj->longitude)){
01322 count += sprintf(buffer + count, "\tlongitude = %s;\n", convert_from_longitude(obj->longitude, tmp, sizeof(tmp)) ? tmp : "(invalid)");
01323 }
01324 count += sprintf(buffer + count, "\tflags = %s;\n", convert_from_set(tmp, sizeof(tmp), &(obj->flags), object_flag_property()) ? tmp : "(invalid)");
01325
01326
01327 for(prop = obj->oclass->pmap; prop != NULL && prop->oclass == obj->oclass; prop = prop->next){
01328 char *value = object_property_to_string(obj, prop->name);
01329 if(value != NULL){
01330 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);
01331 if(count > safesize){
01332 throw_exception("object_dump(char *buffer=%x, int size=%d, OBJECT *obj=%s:%d) buffer overrun", outbuffer, size, obj->oclass->name, obj->id);
01333
01334
01335
01336
01337 }
01338 }
01339 }
01340
01341
01342 pclass = obj->oclass;
01343 while((pclass = pclass->parent) != NULL){
01344 for(prop = pclass->pmap; prop != NULL && prop->oclass == pclass; prop = prop->next){
01345 char *value = object_property_to_string(obj, prop->name);
01346 if(value != NULL){
01347 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);
01348 if(count > safesize){
01349 throw_exception("object_dump(char *buffer=%x, int size=%d, OBJECT *obj=%s:%d) buffer overrun", outbuffer, size, obj->oclass->name, obj->id);
01350
01351
01352
01353
01354 }
01355 }
01356 }
01357 }
01358
01359 count += sprintf(buffer+count,"}\n");
01360 if(count < size && count < sizeof(buffer)){
01361 strncpy(outbuffer, buffer, count+1);
01362 return count;
01363 } else {
01364 output_error("buffer too small in object_dump()!");
01365 return 0;
01366 }
01367
01368 }
01369
01373 int object_saveall(FILE *fp)
01374 {
01375 unsigned count = 0;
01376 char buffer[1024];
01377
01378 count += fprintf(fp, "\n########################################################\n");
01379 count += fprintf(fp, "# objects\n");
01380 {
01381 OBJECT *obj;
01382 for (obj = first_object; obj != NULL; obj = obj->next){
01383 PROPERTY *prop = NULL;
01384 char32 oname = "(unidentified)";
01385 count += fprintf(fp, "object %s:%d {\n", obj->oclass->name, obj->id);
01386
01387
01388 if(obj->parent != NULL){
01389 convert_from_object(oname, sizeof(oname), &obj->parent, NULL);
01390 count += fprintf(fp, "\tparent %s;\n", oname);
01391 } else {
01392 count += fprintf(fp,"\troot;\n");
01393 }
01394 count += fprintf(fp, "\trank %d;\n", obj->rank);
01395 if(obj->name != NULL){
01396 count += fprintf(fp, "\tname %s;\n", obj->name);
01397 }
01398 count += fprintf(fp,"\tclock %s;\n", convert_from_timestamp(obj->clock, buffer, sizeof(buffer)) > 0 ? buffer : "(invalid)");
01399 if(!isnan(obj->latitude)){
01400 count += fprintf(fp, "\tlatitude %s;\n", convert_from_latitude(obj->latitude, buffer, sizeof(buffer)) ? buffer : "(invalid)");
01401 }
01402 if(!isnan(obj->longitude)){
01403 count += fprintf(fp, "\tlongitude %s;\n", convert_from_longitude(obj->longitude, buffer, sizeof(buffer)) ? buffer : "(invalid)");
01404 }
01405 count += fprintf(fp, "\tflags %s;\n", convert_from_set(buffer, sizeof(buffer), &(obj->flags), object_flag_property()) ? buffer : "(invalid)");
01406
01407
01408 for(prop = obj->oclass->pmap; prop != NULL && prop->oclass == obj->oclass; prop = prop->next){
01409 char *value = object_property_to_string(obj, prop->name);
01410 if(value != NULL){
01411 count += fprintf(fp, "\t%s %s;\n", prop->name, value);
01412 }
01413 }
01414 count += fprintf(fp,"}\n");
01415 }
01416 }
01417 return count;
01418 }
01419
01423 int object_saveall_xml(FILE *fp){
01424 unsigned count = 0;
01425 char buffer[1024];
01426 PROPERTY *prop = NULL;
01427 OBJECT *obj = NULL;
01428 CLASS *oclass = NULL;
01429
01430 for(obj = first_object; obj != NULL; obj = obj->next){
01431 char32 oname = "(unidentified)";
01432 convert_from_object(oname, sizeof(oname), &obj, NULL);
01433 if((oclass == NULL) || (obj->oclass != oclass)){
01434 oclass = obj->oclass;
01435 }
01436 count += fprintf(fp, "\t\t<object type=\"%s\" id=\"%i\" name=\"%s\">\n", obj->oclass->name, obj->id, oname);
01437
01438
01439 if(obj->parent != NULL){
01440 convert_from_object(oname, sizeof(oname), &obj->parent, NULL);
01441 count += fprintf(fp,"\t\t\t<parent>\n");
01442 count += fprintf(fp, "\t\t\t\t%s\n", oname);
01443 count += fprintf(fp,"\t\t\t</parent>\n");
01444 } else {
01445 count += fprintf(fp,"\t\t\t<parent>root</parent>\n");
01446 }
01447 count += fprintf(fp,"\t\t\t<rank>%d</rank>\n", obj->rank);
01448 count += fprintf(fp,"\t\t\t<clock>\n", obj->clock);
01449 count += fprintf(fp,"\t\t\t\t <timestamp>%s</timestamp>\n", convert_from_timestamp(obj->clock,buffer, sizeof(buffer)) > 0 ? buffer : "(invalid)");
01450 count += fprintf(fp,"\t\t\t</clock>\n");
01451
01452 if(!isnan(obj->latitude)){
01453 count += fprintf(fp, "\t\t\t<latitude>%lf %s</latitude>\n", obj->latitude, convert_from_latitude(obj->latitude, buffer, sizeof(buffer)) ? buffer : "(invalid)");
01454 }
01455 if(!isnan(obj->longitude)){
01456 count += fprintf(fp, "\t\t\t<longitude>%lf %s</longitude>\n", obj->longitude, convert_from_longitude(obj->longitude, buffer, sizeof(buffer)) ? buffer : "(invalid)");
01457 }
01458
01459
01460 if(oclass->parent != NULL){
01461 for (prop = oclass->parent->pmap; prop != NULL && prop->oclass == oclass->parent; prop = prop->next){
01462 char *value = object_property_to_string(obj, prop->name);
01463 if(value != NULL){
01464 count += fprintf(fp, "\t\t\t<%s>%s</%s>\n", prop->name, value, prop->name);
01465 }
01466 }
01467 }
01468
01469
01470 for(prop = oclass->pmap; prop != NULL && prop->oclass == oclass; prop = prop->next){
01471 char *value = object_property_to_string(obj, prop->name);
01472 if(value!=NULL){
01473 count += fprintf(fp, "\t\t\t<%s>%s</%s>\n", prop->name, value, prop->name);
01474 }
01475 }
01476 count += fprintf(fp, "\t\t</object>\n");
01477 }
01478
01479 count += fprintf(fp, "\t</objects>\n");
01480 return count;
01481 }
01482
01483 int object_saveall_xml_old(FILE *fp);
01484
01485 int object_saveall_xml_old(FILE *fp){
01486 unsigned count = 0;
01487 char buffer[1024];
01488
01489 count += fprintf(fp,"\t<objects>\n");
01490 {
01491 OBJECT *obj;
01492 CLASS *oclass = NULL;
01493
01494 for (obj = first_object; obj != NULL; obj = obj->next){
01495 PROPERTY *prop = NULL;
01496 char32 oname = "(unidentified)";
01497
01498 convert_from_object(oname, sizeof(oname), &obj, NULL);
01499
01500 if(oclass == NULL || obj->oclass != oclass){
01501 oclass = obj->oclass;
01502 }
01503 count += fprintf(fp, "\t\t<object>\n");
01504 count += fprintf(fp, "\t\t\t<name>%s</name> \n", oname);
01505 count += fprintf(fp, "\t\t\t<class>%s</class> \n", obj->oclass->name);
01506 count += fprintf(fp, "\t\t\t<id>%d</id>\n", obj->id);
01507
01508
01509 if(obj->parent != NULL){
01510 convert_from_object(oname, sizeof(oname), &obj->parent, NULL);
01511 count += fprintf(fp, "\t\t\t<parent>\n");
01512 count += fprintf(fp, "\t\t\t\t<name>%s</name>\n", oname);
01513 count += fprintf(fp, "\t\t\t\t<class>%s</class>\n", obj->parent->oclass->name);
01514 count += fprintf(fp, "\t\t\t\t<id>%d</id>\n", obj->parent->id);
01515 count += fprintf(fp, "\t\t\t</parent>\n");
01516 } else {
01517 count += fprintf(fp,"\t\t\t<parent>root</parent>\n");
01518 }
01519 count += fprintf(fp, "\t\t\t<rank>%d</rank>\n", obj->rank);
01520 count += fprintf(fp, "\t\t\t<clock>\n", obj->clock);
01521 count += fprintf(fp, "\t\t\t\t <timestamp>%s</timestamp>\n", (convert_from_timestamp(obj->clock, buffer, sizeof(buffer)) > 0) ? buffer : "(invalid)");
01522 count += fprintf(fp, "\t\t\t</clock>\n");
01523
01524 if(!isnan(obj->latitude)){
01525 count += fprintf(fp, "\t\t\t<latitude>%lf %s</latitude>\n" ,obj->latitude, convert_from_latitude(obj->latitude, buffer, sizeof(buffer)) ? buffer : "(invalid)");
01526 }
01527 if(!isnan(obj->longitude)) {
01528 count += fprintf(fp, "\t\t\t<longitude>%lf %s</longitude>\n", obj->longitude, convert_from_longitude(obj->longitude, buffer, sizeof(buffer)) ? buffer : "(invalid)");
01529 }
01530
01531
01532 count += fprintf(fp, "\t\t\t<properties>\n");
01533 for (prop = oclass->pmap; prop != NULL && prop->oclass == oclass; prop = prop->next){
01534 char *value = object_property_to_string(obj, prop->name);
01535
01536 if(value != NULL){
01537 count += fprintf(fp, "\t\t\t\t<property>\n");
01538 count += fprintf(fp, "\t\t\t\t\t<type>%s</type> \n", prop->name);
01539 count += fprintf(fp, "\t\t\t\t\t<value>%s</value> \n", value);
01540 count += fprintf(fp, "\t\t\t\t</property>\n");
01541 }
01542 }
01543 count += fprintf(fp, "\t\t\t</properties>\n");
01544 count += fprintf(fp, "\t\t</object>\n");
01545 }
01546 }
01547 count += fprintf(fp,"\t</objects>\n");
01548 return count;
01549 }
01550
01551 int convert_from_latitude(double v, void *buffer, int bufsize){
01552 double d = floor(fabs(v));
01553 double r = fabs(v) - d;
01554 double m = floor(r * 60.0);
01555 double s = (r - (double)m / 60.0) * 3600.0;
01556 char ns = (v < 0) ? 'S' : 'N';
01557
01558 if(isnan(v)){
01559 return 0;
01560 }
01561
01562 return sprintf(buffer, "%.0f%c%.0f'%.2f\"", d, ns, m, s);
01563 }
01564
01565 int convert_from_longitude(double v, void *buffer, int bufsize){
01566 double d = floor(fabs(v));
01567 double r = fabs(v)-d;
01568 double m = floor(r*60);
01569 double s = (r - (double)m/60.0)*3600;
01570 char ns = (v < 0) ? 'W' : 'E';
01571
01572 if(isnan(v)){
01573 return 0;
01574 }
01575
01576 return sprintf(buffer, "%.0f%c%.0f'%.2f\"", d, ns, m, s);
01577 }
01578
01579 double convert_to_latitude(char *buffer){
01580 int32 d, m = 0;
01581 double s = 0;
01582 char ns;
01583
01584 if(sscanf(buffer, "%d%c%d'%lf\"", &d, &ns, &m, &s) > 1){
01585 double v = (double)d + (double)m / 60.0 + s / 3600.0;
01586 if(v >= 0.0 || v <= 90.0){
01587 if(ns == 'S'){
01588 return -v;
01589 } else if(ns == 'N'){
01590 return v;
01591 }
01592 }
01593 }
01594
01595 return QNAN;
01596 }
01597
01598 double convert_to_longitude(char *buffer){
01599 int32 d, m = 0;
01600 double s = 0;
01601 char ns;
01602
01603 if(sscanf(buffer, "%d%c%d'%lf\"", &d, &ns, &m, &s) > 1){
01604 double v = (double)d + (double)m / 60.0 + s / 3600.0;
01605 if(v >= 0.0 || v <= 90.0){
01606 if(ns == 'W'){
01607 return -v;
01608 } else if(ns=='E'){
01609 return v;
01610 }
01611 }
01612 }
01613
01614 return QNAN;
01615 }
01616
01617
01618
01619
01620
01621 typedef struct s_objecttree {
01622 char name[64];
01623 OBJECT *obj;
01624 struct s_objecttree *before, *after;
01625 int balance;
01626 } OBJECTTREE;
01627
01628 static OBJECTTREE *top=NULL;
01629
01630 void debug_traverse_tree(OBJECTTREE *tree){
01631 if(tree == NULL){
01632 tree = top;
01633 if(top == NULL){
01634 return;
01635 }
01636 }
01637 if(tree->before != NULL){
01638 debug_traverse_tree(tree->before);
01639 }
01640 output_test("%s", tree->name);
01641 if(tree->after != NULL){
01642 debug_traverse_tree(tree->after);
01643 }
01644 }
01645
01646
01647 int tree_get_height(OBJECTTREE *tree){
01648 if(tree == NULL){
01649 return 0;
01650 } else {
01651 int left = tree_get_height(tree->before);
01652 int right = tree_get_height(tree->after);
01653 if(left > right)
01654 return left+1;
01655 else return right+1;
01656 }
01657 }
01658
01659
01660 void rotate_tree_right(OBJECTTREE **tree){
01661 OBJECTTREE *root, *pivot, *child;
01662 root = *tree;
01663 pivot = root->before;
01664 child = root->before->after;
01665 *tree = pivot;
01666 pivot->after = root;
01667 root->before = child;
01668 root->balance += 2;
01669 pivot->balance += 1;
01670 }
01671
01672
01673 void rotate_tree_left(OBJECTTREE **tree){
01674 OBJECTTREE *root, *pivot, *child;
01675 root = *tree;
01676 pivot = root->after;
01677 child = root->after->before;
01678 *tree = pivot;
01679 pivot->before = root;
01680 root->after = child;
01681 root->balance -= 2;
01682 pivot->balance -= 1;
01683 }
01684
01685
01686
01687
01688 int object_tree_rebalance(OBJECTTREE *tree)
01689 {
01690
01691 return 0;
01692 }
01693
01694
01695
01696
01697 static int addto_tree(OBJECTTREE **tree, OBJECTTREE *item){
01698 int rel = strcmp((*tree)->name, item->name);
01699 int right = 0, left = 0, ir = 0, il = 0, rv = 0;
01700
01701 if(rel > 0){
01702 (*tree)->balance--;
01703 if((*tree)->before == NULL){
01704 (*tree)->before = item;
01705 return 1;
01706 } else {
01707 rv = addto_tree(&((*tree)->before), item);
01708 if(global_no_balance){
01709 return rv + 1;
01710 }
01711 if((*tree)->balance > 1){
01712 if((*tree)->after->balance < 0){
01713 rotate_tree_right(&((*tree)->after));
01714 }
01715 rotate_tree_left(tree);
01716 } else if((*tree)->balance < -1) {
01717 if((*tree)->before->balance > 0){
01718 rotate_tree_left(&((*tree)->before));
01719 }
01720 rotate_tree_right(tree);
01721 }
01722 return tree_get_height(*tree);
01723 }
01724 } else if(rel<0) {
01725 (*tree)->balance++;
01726 if((*tree)->after == NULL) {
01727 (*tree)->after = item;
01728 return 1;
01729 } else {
01730 rv = addto_tree(&((*tree)->after),item);
01731 if(global_no_balance){
01732 return rv + 1;
01733 }
01734 if((*tree)->balance > 1){
01735 if((*tree)->after->balance < 0){
01736 rotate_tree_right(&((*tree)->after));
01737 }
01738 rotate_tree_left(tree);
01739 } else if((*tree)->balance < -1){
01740 if((*tree)->before->balance > 0){
01741 rotate_tree_left(&((*tree)->before));
01742 }
01743 rotate_tree_right(tree);
01744 }
01745 return tree_get_height(*tree);
01746 }
01747 } else {
01748 return (*tree)->obj==item->obj;
01749 }
01750 return 0;
01751 }
01752
01753
01754
01755
01756 static OBJECTTREE *object_tree_add(OBJECT *obj, OBJECTNAME name){
01757 OBJECTTREE *item = (OBJECTTREE*)malloc(sizeof(OBJECTTREE));
01758
01759 if(item == NULL) {
01760 output_fatal("object_tree_add(obj='%s:%d', name='%s'): memory allocation failed (%s)", obj->oclass->name, obj->id, name, strerror(errno));
01761 return NULL;
01762
01763
01764
01765 }
01766
01767 item->obj = obj;
01768 item->balance = 0;
01769 strncpy(item->name, name, sizeof(item->name));
01770 item->before = item->after = NULL;
01771
01772 if(top == NULL){
01773 top = item;
01774 return top;
01775 } else {
01776 if(addto_tree(&top, item) != 0){
01777 return item;
01778 } else {
01779 return NULL;
01780 }
01781 }
01782 }
01783
01784
01785
01786 static OBJECTTREE **findin_tree(OBJECTTREE *tree, OBJECTNAME name){
01787 static OBJECTTREE **temptree = NULL;
01788
01789 if(tree == NULL){
01790 return NULL;
01791 } else {
01792 int rel = strcmp(tree->name, name);
01793 if(rel > 0){
01794 if(tree->before != NULL){
01795 if(strcmp(tree->before->name, name) == 0){
01796 return &(tree->before);
01797 } else {
01798 return findin_tree(tree->before, name);
01799 }
01800 } else {
01801 return NULL;
01802 }
01803 } else if(rel<0) {
01804 if(tree->after != NULL){
01805 if(strcmp(tree->after->name, name) == 0){
01806 return &(tree->after);
01807 } else {
01808 return findin_tree(tree->after, name);
01809 }
01810 } else {
01811 return NULL;
01812 }
01813 } else {
01814 return (temptree = &tree);
01815 }
01816 }
01817 }
01818
01819
01820
01821
01822 void object_tree_delete(OBJECT *obj, OBJECTNAME name)
01823 {
01824 OBJECTTREE **item = findin_tree(top,name);
01825 OBJECTTREE *temp = NULL, **dtemp = NULL;
01826
01827 if(item != NULL && strcmp((*item)->name, name)!=0){
01828 if((*item)->after == NULL && (*item)->before == NULL){
01829 free(*item);
01830 *item = NULL;
01831 } else if((*item)->after != NULL && (*item)->before != NULL){
01832 dtemp = &((*item)->before);
01833 while(temp->after != NULL)
01834 dtemp = &(temp->after);
01835 temp = (*dtemp)->before;
01836 (*dtemp)->before = (*item)->before;
01837 (*dtemp)->after = (*item)->after;
01838 free(*item);
01839 *item = *dtemp;
01840 *dtemp = temp;
01841
01842
01843 } else if((*item)->after == NULL || (*item)->before == NULL){
01844 if((*item)->after != NULL){
01845 temp = (*item)->after;
01846 free(*item);
01847 *item = temp;
01848 } else if((*item)->before != NULL){
01849 temp = (*item)->before;
01850 free(*item);
01851 *item = temp;
01852 } else {
01853 output_fatal("unexpected branch result in object_tree_delete");
01854
01855
01856
01857 }
01858 }
01859
01860
01861 }
01862 }
01863
01867 OBJECT *object_find_name(OBJECTNAME name){
01868 OBJECTTREE **item = NULL;
01869
01870 item = findin_tree(top, name);
01871
01872 if(item != NULL && *item != NULL){
01873 return (*item)->obj;
01874 } else {
01875
01876 return NULL;
01877 }
01878 }
01879
01880 int object_build_name(OBJECT *obj, char *buffer, int len){
01881 char b[256];
01882 char *ptr = 0;
01883 int L;
01884
01885 if(obj == 0){
01886 return 0;
01887 }
01888 if(buffer == 0){
01889 return 0;
01890 }
01891
01892 if(obj->name){
01893 L = (int)strlen(obj->name);
01894 ptr = obj->name;
01895 } else {
01896 sprintf(b, "%s %i", obj->oclass->name, obj->id);
01897 L = (int)strlen(b);
01898 ptr = b;
01899 }
01900
01901 if(L > len){
01902 output_error("object_build_name(): unable to build name for '%s', input buffer too short", obj->name);
01903 return 0;
01904 } else {
01905 strcpy(buffer, obj->name);
01906 return L;
01907 }
01908
01909 output_error("object_build_name(): control unexpectedly reached end of method");
01910 return 0;
01911 }
01912
01917 OBJECTNAME object_set_name(OBJECT *obj, OBJECTNAME name){
01918 OBJECTTREE *item = NULL;
01919
01920 if((isalpha(name[0]) != 0) || (name[0] == '_')){
01921 ;
01922 } else {
01923 if(global_relax_naming_rules == 0){
01924 output_error("object name '%s' invalid, names must start with a letter or an underscore", name);
01925 return NULL;
01926 } else {
01927 output_warning("object name '%s' does not follow strict naming rules and may not link correctly during load time", name);
01928 }
01929 }
01930 if(obj->name != NULL){
01931 object_tree_delete(obj,name);
01932 }
01933
01934 if(name != NULL){
01935 if(object_find_name(name) != NULL){
01936 output_error("An object named '%s' already exists!", name);
01937
01938
01939
01940
01941 return NULL;
01942 }
01943 item = object_tree_add(obj,name);
01944 if(item != NULL){
01945 obj->name = item->name;
01946 }
01947 }
01948
01949 if(item != NULL){
01950 return item->name;
01951 } else {
01952 return NULL;
01953 }
01954 }
01955
01959 void remove_objects(){
01960 OBJECT* obj1;
01961
01962 obj1 = first_object;
01963 while(obj1 != NULL){
01964 first_object = obj1->next;
01965 obj1->oclass->profiler.numobjs--;
01966 free(obj1);
01967 obj1 = first_object;
01968 }
01969
01970 next_object_id = 0;
01971 }
01972
01973
01974
01975
01976 NAMESPACE *current_namespace = NULL;
01977 static int _object_namespace(NAMESPACE *space,char *buffer,int size)
01978 {
01979 int n=0;
01980 if(space==NULL)
01981 return 0;
01982 n += _object_namespace(space->next,buffer,size);
01983 if(buffer[0]!='\0')
01984 {
01985 strcat(buffer,"::");
01986 n++;
01987 }
01988 strcat(buffer,space->name);
01989 n+=(int)strlen(space->name);
01990 return n;
01991 }
01995 void object_namespace(char *buffer, int size)
01996 {
01997 strcpy(buffer,"");
01998 _object_namespace(current_namespace,buffer,size);
01999 }
02000
02004 int object_get_namespace(OBJECT *obj, char *buffer, int size)
02005 {
02006 strcpy(buffer,"");
02007 _object_namespace(obj->space,buffer,size);
02008 return obj->space!=NULL;
02009 }
02010
02014 NAMESPACE *object_current_namespace()
02015 {
02016 return current_namespace;
02017 }
02018
02022 int object_open_namespace(char *space)
02023 {
02024 NAMESPACE *ns = malloc(sizeof(NAMESPACE));
02025 if(ns==NULL)
02026 {
02027 throw_exception("object_open_namespace(char *space='%s'): memory allocation failure", space);
02028
02029
02030
02031 return 0;
02032 }
02033 strncpy(ns->name,space,sizeof(ns->name));
02034 ns->next = current_namespace;
02035 current_namespace = ns;
02036 return 1;
02037 }
02038
02042 int object_close_namespace()
02043 {
02044 if(current_namespace==NULL)
02045 {
02046 throw_exception("object_close_namespace(): no current namespace to close");
02047
02048
02049
02050
02051 return 0;
02052 }
02053 current_namespace = current_namespace->next;
02054 return 1;
02055 }
02056
02060 int object_select_namespace(char *space)
02061 {
02062 output_error("namespace selection not yet supported");
02063 return 0;
02064 }
02065
02070 int object_locate_property(void *addr, OBJECT **pObj, PROPERTY **pProp)
02071 {
02072 OBJECT *obj;
02073 for (obj=first_object; obj!=NULL; obj=obj->next)
02074 {
02075 if ((int64)addr>(int64)obj && (int64)addr<(int64)(obj+1)+(int64)obj->oclass->size)
02076 {
02077 int offset = (int)((int64)addr - (int64)(obj+1));
02078 PROPERTY *prop;
02079 for (prop=obj->oclass->pmap; prop!=NULL && prop->oclass==obj->oclass; prop=prop->next)
02080 {
02081 if ((int64)prop->addr == offset)
02082 {
02083 *pObj = obj;
02084 *pProp = prop;
02085 return SUCCESS;
02086 }
02087 }
02088 }
02089 }
02090 return FAILED;
02091 }